blob: ce8ce2590482e03d180cfba41ada66b47a4c45f1 [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
728 if (msmsdcc_is_dml_busy(host)) {
729 /* oops !!! this should never happen. */
730 pr_err("%s: %s: Received SPS EOT event"
731 " but DML HW is still busy !!!\n",
732 mmc_hostname(host->mmc), __func__);
733 }
734 /*
735 * Got End of transfer event!!! Check if all of the data
736 * has been transferred?
737 */
738 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
739 rc = sps_get_iovec(sps_pipe_handle, &iovec);
740 if (rc) {
741 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
742 mmc_hostname(host->mmc), __func__, rc, i);
743 break;
744 }
745 data_xfered += iovec.size;
746 }
747
748 if (data_xfered == host->curr.xfer_size) {
749 host->curr.data_xfered = host->curr.xfer_size;
750 host->curr.xfer_remain -= host->curr.xfer_size;
751 pr_debug("%s: Data xfer success. data_xfered=0x%x",
752 mmc_hostname(host->mmc),
753 host->curr.xfer_size);
754 } else {
755 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
756 " xfer_size=%d", mmc_hostname(host->mmc),
757 data_xfered, host->curr.xfer_size);
758 msmsdcc_reset_and_restore(host);
759 if (!mrq->data->error)
760 mrq->data->error = -EIO;
761 }
762
763 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530764 if (!mrq->data->host_cookie)
765 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
766 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 host->sps.sg = NULL;
768 host->sps.busy = 0;
769
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530770 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
771 (host->curr.wait_for_auto_prog_done &&
772 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 /*
774 * If we've already gotten our DATAEND / DATABLKEND
775 * for this request, then complete it through here.
776 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777
778 if (!mrq->data->error) {
779 host->curr.data_xfered = host->curr.xfer_size;
780 host->curr.xfer_remain -= host->curr.xfer_size;
781 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700782 if (host->dummy_52_needed) {
783 mrq->data->bytes_xfered = host->curr.data_xfered;
784 host->dummy_52_sent = 1;
785 msmsdcc_start_command(host, &dummy52cmd,
786 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700787 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700788 return;
789 }
790 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530791 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530792 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530794 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530796 /*
797 * Clear current request information as current
798 * request has ended
799 */
800 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 spin_unlock_irqrestore(&host->lock, flags);
802
803 mmc_request_done(host->mmc, mrq);
804 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530805 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
806 || !mrq->sbc)) {
807 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 }
809 }
810 spin_unlock_irqrestore(&host->lock, flags);
811}
812
813/**
814 * Exit from current SPS data transfer
815 *
816 * This function exits from current SPS data transfer.
817 *
818 * This function should be called when error condition
819 * is encountered during data transfer.
820 *
821 * @host - Pointer to sdcc host structure
822 *
823 */
824static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
825{
826 struct mmc_request *mrq;
827
828 mrq = host->curr.mrq;
829 BUG_ON(!mrq);
830
831 msmsdcc_reset_and_restore(host);
832 if (!mrq->data->error)
833 mrq->data->error = -EIO;
834
835 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530836 if (!mrq->data->host_cookie)
837 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
838 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839
840 host->sps.sg = NULL;
841 host->sps.busy = 0;
842 if (host->curr.data)
843 msmsdcc_stop_data(host);
844
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530845 if (!mrq->data->stop || mrq->cmd->error ||
846 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530848 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
849 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 msmsdcc_start_command(host, mrq->data->stop, 0);
851
852}
853#else
854static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
855static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
856static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
857#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
858
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530859static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530861static void
862msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
863 unsigned int result,
864 struct msm_dmov_errdata *err)
865{
866 struct msmsdcc_dma_data *dma_data =
867 container_of(cmd, struct msmsdcc_dma_data, hdr);
868 struct msmsdcc_host *host = dma_data->host;
869
870 dma_data->result = result;
871 if (err)
872 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
873
874 tasklet_schedule(&host->dma_tlet);
875}
876
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530877static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
878 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700879{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530880 bool ret = true;
881 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700882
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530883 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530884 /*
885 * BAM Mode: Fall back on PIO if size is less
886 * than or equal to SPS_MIN_XFER_SIZE bytes.
887 */
888 if (xfer_size <= SPS_MIN_XFER_SIZE)
889 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530890 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530891 /*
892 * ADM Mode: Fall back on PIO if size is less than FIFO size
893 * or not integer multiple of FIFO size
894 */
895 if (xfer_size % MCI_FIFOSIZE)
896 ret = false;
897 } else {
898 /* PIO Mode */
899 ret = false;
900 }
901
902 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700903}
904
905static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
906{
907 struct msmsdcc_nc_dmadata *nc;
908 dmov_box *box;
909 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700910 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530911 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700912 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530913 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700914
Krishna Konda25786ec2011-07-25 16:21:36 -0700915 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700917
Krishna Konda25786ec2011-07-25 16:21:36 -0700918 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700919
920 host->dma.sg = data->sg;
921 host->dma.num_ents = data->sg_len;
922
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530923 /* Prevent memory corruption */
924 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800925
San Mehat9d2bd732009-09-22 16:44:22 -0700926 nc = host->dma.nc;
927
San Mehat9d2bd732009-09-22 16:44:22 -0700928 if (data->flags & MMC_DATA_READ)
929 host->dma.dir = DMA_FROM_DEVICE;
930 else
931 host->dma.dir = DMA_TO_DEVICE;
932
Asutosh Dasaccacd42012-03-08 14:33:17 +0530933 if (!data->host_cookie) {
934 n = msmsdcc_prep_xfer(host, data);
935 if (unlikely(n < 0)) {
936 host->dma.sg = NULL;
937 host->dma.num_ents = 0;
938 return -ENOMEM;
939 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800940 }
San Mehat9d2bd732009-09-22 16:44:22 -0700941
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530942 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
943 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700944 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530945 for (i = 0; i < host->dma.num_ents; i++) {
946 len = sg_dma_len(sg);
947 offset = 0;
948
949 do {
950 /* Check if we can do DMA */
951 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
952 err = -ENOTSUPP;
953 goto unmap;
954 }
955
956 box->cmd = CMD_MODE_BOX;
957
958 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
959 len = MMC_MAX_DMA_BOX_LENGTH;
960 len -= len % data->blksz;
961 }
962 rows = (len % MCI_FIFOSIZE) ?
963 (len / MCI_FIFOSIZE) + 1 :
964 (len / MCI_FIFOSIZE);
965
966 if (data->flags & MMC_DATA_READ) {
967 box->src_row_addr = msmsdcc_fifo_addr(host);
968 box->dst_row_addr = sg_dma_address(sg) + offset;
969 box->src_dst_len = (MCI_FIFOSIZE << 16) |
970 (MCI_FIFOSIZE);
971 box->row_offset = MCI_FIFOSIZE;
972 box->num_rows = rows * ((1 << 16) + 1);
973 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
974 } else {
975 box->src_row_addr = sg_dma_address(sg) + offset;
976 box->dst_row_addr = msmsdcc_fifo_addr(host);
977 box->src_dst_len = (MCI_FIFOSIZE << 16) |
978 (MCI_FIFOSIZE);
979 box->row_offset = (MCI_FIFOSIZE << 16);
980 box->num_rows = rows * ((1 << 16) + 1);
981 box->cmd |= CMD_DST_CRCI(host->dma.crci);
982 }
983
984 offset += len;
985 len = sg_dma_len(sg) - offset;
986 box++;
987 box_cmd_cnt++;
988 } while (len);
989 sg++;
990 }
991 /* Mark last command */
992 box--;
993 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700994
995 /* location of command block must be 64 bit aligned */
996 BUG_ON(host->dma.cmd_busaddr & 0x07);
997
998 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
999 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1000 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1001 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1002
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301003 /* Flush all data to memory before starting dma */
1004 mb();
1005
1006unmap:
1007 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301008 if (!data->host_cookie)
1009 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1010 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301011 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1012 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001013 }
1014
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301015 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001016}
1017
Asutosh Dasaccacd42012-03-08 14:33:17 +05301018static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1019 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001020{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301021 int rc = 0;
1022 unsigned int dir;
1023
1024 /* Prevent memory corruption */
1025 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1026
1027 if (data->flags & MMC_DATA_READ)
1028 dir = DMA_FROM_DEVICE;
1029 else
1030 dir = DMA_TO_DEVICE;
1031
1032 /* Make sg buffers DMA ready */
1033 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1034 dir);
1035
1036 if (unlikely(rc != data->sg_len)) {
1037 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1038 mmc_hostname(host->mmc), rc);
1039 rc = -ENOMEM;
1040 goto dma_map_err;
1041 }
1042
1043 pr_debug("%s: %s: %s: sg_len=%d\n",
1044 mmc_hostname(host->mmc), __func__,
1045 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1046 data->sg_len);
1047
1048 goto out;
1049
1050dma_map_err:
1051 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1052 data->flags);
1053out:
1054 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001055}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1057/**
1058 * Submits data transfer request to SPS driver
1059 *
1060 * This function make sg (scatter gather) data buffers
1061 * DMA ready and then submits them to SPS driver for
1062 * transfer.
1063 *
1064 * @host - Pointer to sdcc host structure
1065 * @data - Pointer to mmc_data structure
1066 *
1067 * @return 0 if success else negative value
1068 */
1069static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301070 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001071{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 int rc = 0;
1073 u32 flags;
1074 int i;
1075 u32 addr, len, data_cnt;
1076 struct scatterlist *sg = data->sg;
1077 struct sps_pipe *sps_pipe_handle;
1078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 host->sps.sg = data->sg;
1080 host->sps.num_ents = data->sg_len;
1081 host->sps.xfer_req_cnt = 0;
1082 if (data->flags & MMC_DATA_READ) {
1083 host->sps.dir = DMA_FROM_DEVICE;
1084 sps_pipe_handle = host->sps.prod.pipe_handle;
1085 } else {
1086 host->sps.dir = DMA_TO_DEVICE;
1087 sps_pipe_handle = host->sps.cons.pipe_handle;
1088 }
1089
Asutosh Dasaccacd42012-03-08 14:33:17 +05301090 if (!data->host_cookie) {
1091 rc = msmsdcc_prep_xfer(host, data);
1092 if (unlikely(rc < 0)) {
1093 host->dma.sg = NULL;
1094 host->dma.num_ents = 0;
1095 goto out;
1096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 }
1098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 for (i = 0; i < data->sg_len; i++) {
1100 /*
1101 * Check if this is the last buffer to transfer?
1102 * If yes then set the INT and EOT flags.
1103 */
1104 len = sg_dma_len(sg);
1105 addr = sg_dma_address(sg);
1106 flags = 0;
1107 while (len > 0) {
1108 if (len > SPS_MAX_DESC_SIZE) {
1109 data_cnt = SPS_MAX_DESC_SIZE;
1110 } else {
1111 data_cnt = len;
1112 if (i == data->sg_len - 1)
1113 flags = SPS_IOVEC_FLAG_INT |
1114 SPS_IOVEC_FLAG_EOT;
1115 }
1116 rc = sps_transfer_one(sps_pipe_handle, addr,
1117 data_cnt, host, flags);
1118 if (rc) {
1119 pr_err("%s: sps_transfer_one() error! rc=%d,"
1120 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1121 mmc_hostname(host->mmc), rc,
1122 (u32)sps_pipe_handle, (u32)sg, i);
1123 goto dma_map_err;
1124 }
1125 addr += data_cnt;
1126 len -= data_cnt;
1127 host->sps.xfer_req_cnt++;
1128 }
1129 sg++;
1130 }
1131 goto out;
1132
1133dma_map_err:
1134 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301135 if (!data->host_cookie)
1136 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1137 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138out:
1139 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001140}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141#else
1142static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1143 struct mmc_data *data) { return 0; }
1144#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001145
1146static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001147msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1148 struct mmc_command *cmd, u32 *c)
1149{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301150 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 cmd->opcode, cmd->arg, cmd->flags);
1152
San Mehat56a8b5b2009-11-21 12:29:46 -08001153 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1154
1155 if (cmd->flags & MMC_RSP_PRESENT) {
1156 if (cmd->flags & MMC_RSP_136)
1157 *c |= MCI_CPSM_LONGRSP;
1158 *c |= MCI_CPSM_RESPONSE;
1159 }
1160
1161 if (/*interrupt*/0)
1162 *c |= MCI_CPSM_INTERRUPT;
1163
Asutosh Das05049132012-05-09 12:38:15 +05301164 /* DAT_CMD bit should be set for all ADTC */
1165 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001166 *c |= MCI_CSPM_DATCMD;
1167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301169 if (host->tuning_needed &&
1170 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1171
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301172 /*
1173 * For open ended block read operation (without CMD23),
1174 * AUTO_CMD19 bit should be set while sending the READ command.
1175 * For close ended block read operation (with CMD23),
1176 * AUTO_CMD19 bit should be set while sending CMD23.
1177 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301178 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1179 host->curr.mrq->cmd->opcode ==
1180 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301181 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301182 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1183 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301184 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1185 *c |= MCI_CSPM_AUTO_CMD19;
1186 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 }
1188
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301189 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1190 writel_relaxed((readl_relaxed(host->base +
1191 MCI_DLL_CONFIG) | MCI_CDR_EN),
1192 host->base + MCI_DLL_CONFIG);
1193 else
1194 /* Clear CDR_EN bit for non read operations */
1195 writel_relaxed((readl_relaxed(host->base +
1196 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1197 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301198
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301199 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1200 (cmd->opcode == MMC_SEND_STATUS &&
1201 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301202 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301204 }
1205
San Mehat56a8b5b2009-11-21 12:29:46 -08001206 if (cmd == cmd->mrq->stop)
1207 *c |= MCI_CSPM_MCIABORT;
1208
San Mehat56a8b5b2009-11-21 12:29:46 -08001209 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301210 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001212 }
1213 host->curr.cmd = cmd;
1214}
1215
1216static void
1217msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1218 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001219{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301220 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001221 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001223 unsigned int pio_irqmask = 0;
1224
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301225 BUG_ON(!data->sg);
1226 BUG_ON(!data->sg_len);
1227
San Mehat9d2bd732009-09-22 16:44:22 -07001228 host->curr.data = data;
1229 host->curr.xfer_size = data->blksz * data->blocks;
1230 host->curr.xfer_remain = host->curr.xfer_size;
1231 host->curr.data_xfered = 0;
1232 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301233 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001234
San Mehat9d2bd732009-09-22 16:44:22 -07001235 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1236
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301237 if (host->curr.wait_for_auto_prog_done)
1238 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001239
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301240 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301241 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301243 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 if (!msmsdcc_is_dml_busy(host)) {
1245 if (!msmsdcc_sps_start_xfer(host, data)) {
1246 /* Now kick start DML transfer */
1247 mb();
1248 msmsdcc_dml_start_xfer(host, data);
1249 datactrl |= MCI_DPSM_DMAENABLE;
1250 host->sps.busy = 1;
1251 }
1252 } else {
1253 /*
1254 * Can't proceed with new transfer as
1255 * previous trasnfer is already in progress.
1256 * There is no point of going into PIO mode
1257 * as well. Is this a time to do kernel panic?
1258 */
1259 pr_err("%s: %s: DML HW is busy!!!"
1260 " Can't perform new SPS transfers"
1261 " now\n", mmc_hostname(host->mmc),
1262 __func__);
1263 }
1264 }
1265 }
1266
1267 /* Is data transfer in PIO mode required? */
1268 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001269 if (data->flags & MMC_DATA_READ) {
1270 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1271 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1272 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1273 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1275 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001276
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001277 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001278 }
1279
1280 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301281 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301282 else if (host->curr.use_wr_data_pend)
1283 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001284
San Mehat56a8b5b2009-11-21 12:29:46 -08001285 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001287 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301288 WARN(!timeout,
1289 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1290 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001291
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301292 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 /* Use ADM (Application Data Mover) HW for Data transfer */
1294 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001295 host->cmd_timeout = timeout;
1296 host->cmd_pio_irqmask = pio_irqmask;
1297 host->cmd_datactrl = datactrl;
1298 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1301 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001302 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001303
1304 if (cmd) {
1305 msmsdcc_start_command_deferred(host, cmd, &c);
1306 host->cmd_c = c;
1307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1309 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1310 host->base + MMCIMASK0);
1311 mb();
1312 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001313 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1320 (~(MCI_IRQ_PIO))) | pio_irqmask,
1321 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001323
1324 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301325 /* Delay between data/command */
1326 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001327 /* Daisy-chain the command if requested */
1328 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301329 } else {
1330 /*
1331 * We don't need delay after writing to DATA_CTRL
1332 * register if we are not writing to CMD register
1333 * immediately after this. As we already have delay
1334 * before sending the command, we just need mb() here.
1335 */
1336 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001337 }
San Mehat9d2bd732009-09-22 16:44:22 -07001338 }
1339}
1340
1341static void
1342msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1343{
San Mehat56a8b5b2009-11-21 12:29:46 -08001344 msmsdcc_start_command_deferred(host, cmd, &c);
1345 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001346}
1347
1348static void
1349msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1350 unsigned int status)
1351{
1352 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301354 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1355 || data->mrq->cmd->opcode ==
1356 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 pr_err("%s: Data CRC error\n",
1358 mmc_hostname(host->mmc));
1359 pr_err("%s: opcode 0x%.8x\n", __func__,
1360 data->mrq->cmd->opcode);
1361 pr_err("%s: blksz %d, blocks %d\n", __func__,
1362 data->blksz, data->blocks);
1363 data->error = -EILSEQ;
1364 }
San Mehat9d2bd732009-09-22 16:44:22 -07001365 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 /* CRC is optional for the bus test commands, not all
1367 * cards respond back with CRC. However controller
1368 * waits for the CRC and times out. Hence ignore the
1369 * data timeouts during the Bustest.
1370 */
1371 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1372 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301373 pr_err("%s: CMD%d: Data timeout\n",
1374 mmc_hostname(host->mmc),
1375 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301377 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 }
San Mehat9d2bd732009-09-22 16:44:22 -07001379 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001380 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001381 data->error = -EIO;
1382 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001383 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001384 data->error = -EIO;
1385 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001386 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001388 data->error = -EIO;
1389 }
San Mehat9d2bd732009-09-22 16:44:22 -07001390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001392 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 host->dummy_52_needed = 0;
1394}
San Mehat9d2bd732009-09-22 16:44:22 -07001395
1396static int
1397msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1398{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001400 uint32_t *ptr = (uint32_t *) buffer;
1401 int count = 0;
1402
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301403 if (remain % 4)
1404 remain = ((remain >> 2) + 1) << 2;
1405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1407
1408 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001409 ptr++;
1410 count += sizeof(uint32_t);
1411
1412 remain -= sizeof(uint32_t);
1413 if (remain == 0)
1414 break;
1415 }
1416 return count;
1417}
1418
1419static int
1420msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001422{
1423 void __iomem *base = host->base;
1424 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 while (readl_relaxed(base + MMCISTATUS) &
1428 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1429 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001430
San Mehat9d2bd732009-09-22 16:44:22 -07001431 count = min(remain, maxcnt);
1432
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301433 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1434 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001435 ptr += count;
1436 remain -= count;
1437
1438 if (remain == 0)
1439 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 }
1441 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001442
1443 return ptr - buffer;
1444}
1445
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001446/*
1447 * Copy up to a word (4 bytes) between a scatterlist
1448 * and a temporary bounce buffer when the word lies across
1449 * two pages. The temporary buffer can then be read to/
1450 * written from the FIFO once.
1451 */
1452static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001453{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001454 struct msmsdcc_pio_data *pio = &host->pio;
1455 unsigned int bytes_avail;
1456
1457 if (host->curr.data->flags & MMC_DATA_READ)
1458 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1459 pio->bounce_buf_len);
1460 else
1461 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1462 pio->bounce_buf_len);
1463
1464 while (pio->bounce_buf_len != 4) {
1465 if (!sg_miter_next(&pio->sg_miter))
1466 break;
1467 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1468 4 - pio->bounce_buf_len);
1469 if (host->curr.data->flags & MMC_DATA_READ)
1470 memcpy(pio->sg_miter.addr,
1471 &pio->bounce_buf[pio->bounce_buf_len],
1472 bytes_avail);
1473 else
1474 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1475 pio->sg_miter.addr, bytes_avail);
1476
1477 pio->sg_miter.consumed = bytes_avail;
1478 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001479 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001480}
1481
1482/*
1483 * Use sg_miter_next to return as many 4-byte aligned
1484 * chunks as possible, using a temporary 4 byte buffer
1485 * for alignment if necessary
1486 */
1487static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1488{
1489 struct msmsdcc_pio_data *pio = &host->pio;
1490 unsigned int length, rlength;
1491 char *buffer;
1492
1493 if (!sg_miter_next(&pio->sg_miter))
1494 return 0;
1495
1496 buffer = pio->sg_miter.addr;
1497 length = pio->sg_miter.length;
1498
1499 if (length < host->curr.xfer_remain) {
1500 rlength = round_down(length, 4);
1501 if (rlength) {
1502 /*
1503 * We have a 4-byte aligned chunk.
1504 * The rounding will be reflected by
1505 * a call to msmsdcc_sg_consumed
1506 */
1507 length = rlength;
1508 goto sg_next_end;
1509 }
1510 /*
1511 * We have a length less than 4 bytes. Check to
1512 * see if more buffer is available, and combine
1513 * to make 4 bytes if possible.
1514 */
1515 pio->bounce_buf_len = length;
1516 memset(pio->bounce_buf, 0, 4);
1517
1518 /*
1519 * On a read, get 4 bytes from FIFO, and distribute
1520 * (4-bouce_buf_len) bytes into consecutive
1521 * sgl buffers when msmsdcc_sg_consumed is called
1522 */
1523 if (host->curr.data->flags & MMC_DATA_READ) {
1524 buffer = pio->bounce_buf;
1525 length = 4;
1526 goto sg_next_end;
1527 } else {
1528 _msmsdcc_sg_consume_word(host);
1529 buffer = pio->bounce_buf;
1530 length = pio->bounce_buf_len;
1531 }
1532 }
1533
1534sg_next_end:
1535 *buf = buffer;
1536 *len = length;
1537 return 1;
1538}
1539
1540/*
1541 * Update sg_miter.consumed based on how many bytes were
1542 * consumed. If the bounce buffer was used to read from FIFO,
1543 * redistribute into sgls.
1544 */
1545static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1546 unsigned int length)
1547{
1548 struct msmsdcc_pio_data *pio = &host->pio;
1549
1550 if (host->curr.data->flags & MMC_DATA_READ) {
1551 if (length > pio->sg_miter.consumed)
1552 /*
1553 * consumed 4 bytes, but sgl
1554 * describes < 4 bytes
1555 */
1556 _msmsdcc_sg_consume_word(host);
1557 else
1558 pio->sg_miter.consumed = length;
1559 } else
1560 if (length < pio->sg_miter.consumed)
1561 pio->sg_miter.consumed = length;
1562}
1563
1564static void msmsdcc_sg_start(struct msmsdcc_host *host)
1565{
1566 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1567
1568 host->pio.bounce_buf_len = 0;
1569
1570 if (host->curr.data->flags & MMC_DATA_READ)
1571 sg_miter_flags |= SG_MITER_TO_SG;
1572 else
1573 sg_miter_flags |= SG_MITER_FROM_SG;
1574
1575 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1576 host->curr.data->sg_len, sg_miter_flags);
1577}
1578
1579static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1580{
1581 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001582}
1583
San Mehat1cd22962010-02-03 12:59:29 -08001584static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001585msmsdcc_pio_irq(int irq, void *dev_id)
1586{
1587 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001589 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001590 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001591 unsigned int remain;
1592 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001593
Murali Palnati36448a42011-09-02 15:06:18 +05301594 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301599 (MCI_IRQ_PIO)) == 0) {
1600 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301601 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301602 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603#if IRQ_DEBUG
1604 msmsdcc_print_status(host, "irq1-r", status);
1605#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001606 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001607
1608 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001609 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1612 | MCI_RXDATAAVLBL)))
1613 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001614
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001615 if (!msmsdcc_sg_next(host, &buffer, &remain))
1616 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001617
San Mehat9d2bd732009-09-22 16:44:22 -07001618 len = 0;
1619 if (status & MCI_RXACTIVE)
1620 len = msmsdcc_pio_read(host, buffer, remain);
1621 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001623
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301624 /* len might have aligned to 32bits above */
1625 if (len > remain)
1626 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001627
San Mehat9d2bd732009-09-22 16:44:22 -07001628 host->curr.xfer_remain -= len;
1629 host->curr.data_xfered += len;
1630 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001631 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 if (remain) /* Done with this page? */
1634 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001637 } while (1);
1638
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001639 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001640 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1643 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1644 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1645 host->base + MMCIMASK0);
1646 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301647 /*
1648 * back to back write to MASK0 register don't need
1649 * synchronization delay.
1650 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1652 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1653 }
1654 mb();
1655 } else if (!host->curr.xfer_remain) {
1656 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1657 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1658 mb();
1659 }
San Mehat9d2bd732009-09-22 16:44:22 -07001660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001662
1663 return IRQ_HANDLED;
1664}
1665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666static void
1667msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1668
1669static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1670 struct mmc_data *data)
1671{
1672 u32 loop_cnt = 0;
1673
1674 /*
1675 * For read commands with data less than fifo size, it is possible to
1676 * get DATAEND first and RXDATA_AVAIL might be set later because of
1677 * synchronization delay through the asynchronous RX FIFO. Thus, for
1678 * such cases, even after DATAEND interrupt is received software
1679 * should poll for RXDATA_AVAIL until the requested data is read out
1680 * of FIFO. This change is needed to get around this abnormal but
1681 * sometimes expected behavior of SDCC3 controller.
1682 *
1683 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1684 * after the data is loaded into RX FIFO. This would amount to less
1685 * than a microsecond and thus looping for 1000 times is good enough
1686 * for that delay.
1687 */
1688 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1689 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1690 spin_unlock(&host->lock);
1691 msmsdcc_pio_irq(1, host);
1692 spin_lock(&host->lock);
1693 }
1694 }
1695 if (loop_cnt == 1000) {
1696 pr_info("%s: Timed out while polling for Rx Data\n",
1697 mmc_hostname(host->mmc));
1698 data->error = -ETIMEDOUT;
1699 msmsdcc_reset_and_restore(host);
1700 }
1701}
1702
San Mehat9d2bd732009-09-22 16:44:22 -07001703static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1704{
1705 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001706
1707 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301708 if (mmc_resp_type(cmd))
1709 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1710 /*
1711 * Read rest of the response registers only if
1712 * long response is expected for this command
1713 */
1714 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1715 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1716 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1717 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1718 }
San Mehat9d2bd732009-09-22 16:44:22 -07001719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301721 pr_debug("%s: CMD%d: Command timeout\n",
1722 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001723 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301725 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301726 pr_err("%s: CMD%d: Command CRC error\n",
1727 mmc_hostname(host->mmc), cmd->opcode);
1728 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001729 cmd->error = -EILSEQ;
1730 }
1731
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301732 if (!cmd->error) {
1733 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1734 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1735 mod_timer(&host->req_tout_timer, (jiffies +
1736 msecs_to_jiffies(host->curr.req_tout_ms)));
1737 }
1738 }
1739
San Mehat9d2bd732009-09-22 16:44:22 -07001740 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301742 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001743 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301745 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 /* Stop current SPS transfer */
1747 msmsdcc_sps_exit_curr_xfer(host);
1748 }
San Mehat9d2bd732009-09-22 16:44:22 -07001749 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301750 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001751 msmsdcc_stop_data(host);
1752 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301753 } else { /* host->data == NULL */
1754 if (!cmd->error && host->prog_enable) {
1755 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301757 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301759 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301760 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301761 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301762 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001763 if (host->dummy_52_needed)
1764 host->dummy_52_needed = 0;
1765 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301767 msmsdcc_request_end(host, cmd->mrq);
1768 }
1769 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301770 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301771 if (cmd == host->curr.mrq->sbc)
1772 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1773 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1774 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301775 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001776 }
1777}
1778
San Mehat9d2bd732009-09-22 16:44:22 -07001779static irqreturn_t
1780msmsdcc_irq(int irq, void *dev_id)
1781{
1782 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001783 u32 status;
1784 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001786
1787 spin_lock(&host->lock);
1788
1789 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 struct mmc_command *cmd;
1791 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 if (timer) {
1794 timer = 0;
1795 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001796 }
San Mehat9d2bd732009-09-22 16:44:22 -07001797
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301798 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 pr_debug("%s: %s: SDIO async irq received\n",
1800 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301801
1802 /*
1803 * Only async interrupt can come when clocks are off,
1804 * disable further interrupts and enable them when
1805 * clocks are on.
1806 */
1807 if (!host->sdcc_irq_disabled) {
1808 disable_irq_nosync(irq);
1809 host->sdcc_irq_disabled = 1;
1810 }
1811
1812 /*
1813 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1814 * will take care of signaling sdio irq during
1815 * mmc_sdio_resume().
1816 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301817 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301818 /*
1819 * This is a wakeup interrupt so hold wakelock
1820 * until SDCC resume is handled.
1821 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301823 } else {
1824 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301825 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301826 spin_lock(&host->lock);
1827 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301828 ret = 1;
1829 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 }
1831
1832 status = readl_relaxed(host->base + MMCISTATUS);
1833
1834 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1835 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001836 break;
1837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838#if IRQ_DEBUG
1839 msmsdcc_print_status(host, "irq0-r", status);
1840#endif
1841 status &= readl_relaxed(host->base + MMCIMASK0);
1842 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301843 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301844 if (host->clk_rate <=
1845 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301846 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847#if IRQ_DEBUG
1848 msmsdcc_print_status(host, "irq0-p", status);
1849#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 if (status & MCI_SDIOINTROPE) {
1852 if (host->sdcc_suspending)
1853 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301854 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301856 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001857 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001858 data = host->curr.data;
1859
1860 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1862 MCI_CMDTIMEOUT)) {
1863 if (status & MCI_CMDTIMEOUT)
1864 pr_debug("%s: dummy CMD52 timeout\n",
1865 mmc_hostname(host->mmc));
1866 if (status & MCI_CMDCRCFAIL)
1867 pr_debug("%s: dummy CMD52 CRC failed\n",
1868 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001869 host->dummy_52_sent = 0;
1870 host->dummy_52_needed = 0;
1871 if (data) {
1872 msmsdcc_stop_data(host);
1873 msmsdcc_request_end(host, data->mrq);
1874 }
1875 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 spin_unlock(&host->lock);
1877 return IRQ_HANDLED;
1878 }
1879 break;
1880 }
1881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 /*
1883 * Check for proper command response
1884 */
1885 cmd = host->curr.cmd;
1886 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1887 MCI_CMDTIMEOUT | MCI_PROGDONE |
1888 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1889 msmsdcc_do_cmdirq(host, status);
1890 }
1891
Sathish Ambley081d7842011-11-29 11:19:41 -08001892 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893 /* Check for data errors */
1894 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1895 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1896 msmsdcc_data_err(host, data, status);
1897 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301898 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001899 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301900 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 /* Stop current SPS transfer */
1902 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301903 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904 msmsdcc_reset_and_restore(host);
1905 if (host->curr.data)
1906 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301907 if (!data->stop || (host->curr.mrq->sbc
1908 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 timer |=
1910 msmsdcc_request_end(host,
1911 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301912 else if ((host->curr.mrq->sbc
1913 && data->error) ||
1914 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 msmsdcc_start_command(host,
1916 data->stop,
1917 0);
1918 timer = 1;
1919 }
1920 }
1921 }
1922
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301923 /* Check for prog done */
1924 if (host->curr.wait_for_auto_prog_done &&
1925 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301926 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928 /* Check for data done */
1929 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1930 host->curr.got_dataend = 1;
1931
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301932 if (host->curr.got_dataend &&
1933 (!host->curr.wait_for_auto_prog_done ||
1934 (host->curr.wait_for_auto_prog_done &&
1935 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001936 /*
1937 * If DMA is still in progress, we complete
1938 * via the completion handler
1939 */
1940 if (!host->dma.busy && !host->sps.busy) {
1941 /*
1942 * There appears to be an issue in the
1943 * controller where if you request a
1944 * small block transfer (< fifo size),
1945 * you may get your DATAEND/DATABLKEND
1946 * irq without the PIO data irq.
1947 *
1948 * Check to see if theres still data
1949 * to be read, and simulate a PIO irq.
1950 */
1951 if (data->flags & MMC_DATA_READ)
1952 msmsdcc_wait_for_rxdata(host,
1953 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 if (!data->error) {
1955 host->curr.data_xfered =
1956 host->curr.xfer_size;
1957 host->curr.xfer_remain -=
1958 host->curr.xfer_size;
1959 }
1960
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001961 if (!host->dummy_52_needed) {
1962 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301963 if (!data->stop ||
1964 (host->curr.mrq->sbc
1965 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001966 msmsdcc_request_end(
1967 host,
1968 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301969 else if ((host->curr.mrq->sbc
1970 && data->error) ||
1971 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001972 msmsdcc_start_command(
1973 host,
1974 data->stop, 0);
1975 timer = 1;
1976 }
1977 } else {
1978 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001980 &dummy52cmd,
1981 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 }
1983 }
1984 }
1985 }
1986
San Mehat9d2bd732009-09-22 16:44:22 -07001987 ret = 1;
1988 } while (status);
1989
1990 spin_unlock(&host->lock);
1991
San Mehat9d2bd732009-09-22 16:44:22 -07001992 return IRQ_RETVAL(ret);
1993}
1994
1995static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301996msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1997 bool is_first_request)
1998{
1999 struct msmsdcc_host *host = mmc_priv(mmc);
2000 struct mmc_data *data = mrq->data;
2001 int rc = 0;
2002
2003 if (unlikely(!data)) {
2004 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2005 __func__);
2006 return;
2007 }
2008 if (unlikely(data->host_cookie)) {
2009 /* Very wrong */
2010 data->host_cookie = 0;
2011 pr_err("%s: %s Request reposted for prepare\n",
2012 mmc_hostname(mmc), __func__);
2013 return;
2014 }
2015
2016 if (!msmsdcc_is_dma_possible(host, data))
2017 return;
2018
2019 rc = msmsdcc_prep_xfer(host, data);
2020 if (unlikely(rc < 0)) {
2021 data->host_cookie = 0;
2022 return;
2023 }
2024
2025 data->host_cookie = 1;
2026}
2027
2028static void
2029msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2030{
2031 struct msmsdcc_host *host = mmc_priv(mmc);
2032 unsigned int dir;
2033 struct mmc_data *data = mrq->data;
2034
2035 if (unlikely(!data)) {
2036 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2037 __func__);
2038 return;
2039 }
2040 if (data->flags & MMC_DATA_READ)
2041 dir = DMA_FROM_DEVICE;
2042 else
2043 dir = DMA_TO_DEVICE;
2044
2045 if (data->host_cookie)
2046 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2047 data->sg_len, dir);
2048
2049 data->host_cookie = 0;
2050}
2051
2052static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2054{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302055 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302057 if ((mrq->data->flags & MMC_DATA_READ) ||
2058 host->curr.use_wr_data_pend)
2059 msmsdcc_start_data(host, mrq->data,
2060 mrq->sbc ? mrq->sbc : mrq->cmd,
2061 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302062 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302063 msmsdcc_start_command(host,
2064 mrq->sbc ? mrq->sbc : mrq->cmd,
2065 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 } else {
2067 msmsdcc_start_command(host, mrq->cmd, 0);
2068 }
2069}
2070
2071static void
San Mehat9d2bd732009-09-22 16:44:22 -07002072msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2073{
2074 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302075 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 /*
2078 * Get the SDIO AL client out of LPM.
2079 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002080 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 if (host->plat->is_sdio_al_client)
2082 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002083
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302084 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302085 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302086 msmsdcc_sps_pipes_reset_and_restore(host);
2087 host->sps.pipe_reset_pending = false;
2088 }
San Mehat9d2bd732009-09-22 16:44:22 -07002089
2090 spin_lock_irqsave(&host->lock, flags);
2091
San Mehat9d2bd732009-09-22 16:44:22 -07002092 if (host->eject) {
2093 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2094 mrq->cmd->error = 0;
2095 mrq->data->bytes_xfered = mrq->data->blksz *
2096 mrq->data->blocks;
2097 } else
2098 mrq->cmd->error = -ENOMEDIUM;
2099
2100 spin_unlock_irqrestore(&host->lock, flags);
2101 mmc_request_done(mmc, mrq);
2102 return;
2103 }
2104
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302105 /*
subhashjf181c292012-05-02 13:07:40 +05302106 * Don't start the request if SDCC is not in proper state to handle it
2107 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302108 if (!host->pwr || !atomic_read(&host->clks_on)
2109 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302110 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2111 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2112 __func__, mrq->cmd->opcode);
2113 msmsdcc_dump_sdcc_state(host);
2114 mrq->cmd->error = -EIO;
2115 if (mrq->data) {
2116 mrq->data->error = -EIO;
2117 mrq->data->bytes_xfered = 0;
2118 }
2119 spin_unlock_irqrestore(&host->lock, flags);
2120 mmc_request_done(mmc, mrq);
2121 return;
2122 }
2123
2124 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2125 " other request (CMD%d) is in progress\n",
2126 mmc_hostname(host->mmc), __func__,
2127 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2128
2129 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302130 * Set timeout value to 10 secs (or more in case of buggy cards)
2131 */
2132 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302133 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302134 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302135 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302136 /*
2137 * Kick the software request timeout timer here with the timeout
2138 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302139 */
2140 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302141 (jiffies +
2142 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002143
San Mehat9d2bd732009-09-22 16:44:22 -07002144 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302145 if (mrq->sbc) {
2146 mrq->sbc->mrq = mrq;
2147 mrq->sbc->data = mrq->data;
2148 }
2149
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302150 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302151 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302152 /*
2153 * Auto-prog done will be enabled for following cases:
2154 * mrq->sbc | mrq->stop
2155 * _____________|________________
2156 * True | Don't care
2157 * False | False (CMD24, ACMD25 use case)
2158 */
2159 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302160 host->curr.wait_for_auto_prog_done = true;
2161 } else {
2162 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2163 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002164 host->dummy_52_needed = 1;
2165 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302166
Subhash Jadavanif5277752011-10-12 16:47:52 +05302167 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2168 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2169 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002170 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302171
Subhash Jadavanif5277752011-10-12 16:47:52 +05302172 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302173
San Mehat9d2bd732009-09-22 16:44:22 -07002174 spin_unlock_irqrestore(&host->lock, flags);
2175}
2176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2178 int min_uV, int max_uV)
2179{
2180 int rc = 0;
2181
2182 if (vreg->set_voltage_sup) {
2183 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2184 if (rc) {
2185 pr_err("%s: regulator_set_voltage(%s) failed."
2186 " min_uV=%d, max_uV=%d, rc=%d\n",
2187 __func__, vreg->name, min_uV, max_uV, rc);
2188 }
2189 }
2190
2191 return rc;
2192}
2193
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302194static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2195{
2196 int rc = 0;
2197
2198 rc = regulator_get_voltage(vreg->reg);
2199 if (rc < 0)
2200 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2201 __func__, vreg->name, rc);
2202
2203 return rc;
2204}
2205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2207 int uA_load)
2208{
2209 int rc = 0;
2210
Krishna Kondafea60182011-11-01 16:01:34 -07002211 /* regulators that do not support regulator_set_voltage also
2212 do not support regulator_set_optimum_mode */
2213 if (vreg->set_voltage_sup) {
2214 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2215 if (rc < 0)
2216 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2217 "uA_load=%d) failed. rc=%d\n", __func__,
2218 vreg->name, uA_load, rc);
2219 else
2220 /* regulator_set_optimum_mode() can return non zero
2221 * value even for success case.
2222 */
2223 rc = 0;
2224 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225
2226 return rc;
2227}
2228
2229static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2230 struct device *dev)
2231{
2232 int rc = 0;
2233
2234 /* check if regulator is already initialized? */
2235 if (vreg->reg)
2236 goto out;
2237
2238 /* Get the regulator handle */
2239 vreg->reg = regulator_get(dev, vreg->name);
2240 if (IS_ERR(vreg->reg)) {
2241 rc = PTR_ERR(vreg->reg);
2242 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2243 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002244 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002246
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302247 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002248 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302249 /* sanity check */
2250 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2251 pr_err("%s: %s invalid constraints specified\n",
2252 __func__, vreg->name);
2253 rc = -EINVAL;
2254 }
2255 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257out:
2258 return rc;
2259}
2260
2261static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2262{
2263 if (vreg->reg)
2264 regulator_put(vreg->reg);
2265}
2266
2267/* This init function should be called only once for each SDCC slot */
2268static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2269{
2270 int rc = 0;
2271 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302272 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 struct device *dev = mmc_dev(host->mmc);
2274
2275 curr_slot = host->plat->vreg_data;
2276 if (!curr_slot)
2277 goto out;
2278
2279 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302280 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002281
2282 if (is_init) {
2283 /*
2284 * Get the regulator handle from voltage regulator framework
2285 * and then try to set the voltage level for the regulator
2286 */
2287 if (curr_vdd_reg) {
2288 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2289 if (rc)
2290 goto out;
2291 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302292 if (curr_vdd_io_reg) {
2293 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 if (rc)
2295 goto vdd_reg_deinit;
2296 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002297 rc = msmsdcc_vreg_reset(host);
2298 if (rc)
2299 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2300 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301 goto out;
2302 } else {
2303 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302304 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302306vdd_io_reg_deinit:
2307 if (curr_vdd_io_reg)
2308 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309vdd_reg_deinit:
2310 if (curr_vdd_reg)
2311 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2312out:
2313 return rc;
2314}
2315
2316static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2317{
2318 int rc = 0;
2319
Subhash Jadavanicc922692011-08-01 23:05:01 +05302320 /* Put regulator in HPM (high power mode) */
2321 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2322 if (rc < 0)
2323 goto out;
2324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325 if (!vreg->is_enabled) {
2326 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302327 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2328 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 if (rc)
2330 goto out;
2331
2332 rc = regulator_enable(vreg->reg);
2333 if (rc) {
2334 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2335 __func__, vreg->name, rc);
2336 goto out;
2337 }
2338 vreg->is_enabled = true;
2339 }
2340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341out:
2342 return rc;
2343}
2344
Krishna Konda3c4142d2012-06-27 11:01:56 -07002345static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346{
2347 int rc = 0;
2348
2349 /* Never disable regulator marked as always_on */
2350 if (vreg->is_enabled && !vreg->always_on) {
2351 rc = regulator_disable(vreg->reg);
2352 if (rc) {
2353 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2354 __func__, vreg->name, rc);
2355 goto out;
2356 }
2357 vreg->is_enabled = false;
2358
2359 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2360 if (rc < 0)
2361 goto out;
2362
2363 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302364 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002365 if (rc)
2366 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002367 } else if (vreg->is_enabled && vreg->always_on) {
2368 if (!is_init && vreg->lpm_sup) {
2369 /* Put always_on regulator in LPM (low power mode) */
2370 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2371 if (rc < 0)
2372 goto out;
2373 } else if (is_init && vreg->reset_at_init) {
2374 /**
2375 * The regulator might not actually be disabled if it
2376 * is shared and in use by other drivers.
2377 */
2378 rc = regulator_disable(vreg->reg);
2379 if (rc) {
2380 pr_err("%s: regulator_disable(%s) failed at " \
2381 "bootup. rc=%d\n", __func__,
2382 vreg->name, rc);
2383 goto out;
2384 }
2385 vreg->is_enabled = false;
2386 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002387 }
2388out:
2389 return rc;
2390}
2391
Krishna Konda3c4142d2012-06-27 11:01:56 -07002392static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2393 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394{
2395 int rc = 0, i;
2396 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302397 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398
2399 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302400 if (!curr_slot) {
2401 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302403 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404
Subhash Jadavani937c7502012-06-01 15:34:46 +05302405 vreg_table[0] = curr_slot->vdd_data;
2406 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002407
2408 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2409 if (vreg_table[i]) {
2410 if (enable)
2411 rc = msmsdcc_vreg_enable(vreg_table[i]);
2412 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002413 rc = msmsdcc_vreg_disable(vreg_table[i],
2414 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415 if (rc)
2416 goto out;
2417 }
2418 }
2419out:
2420 return rc;
2421}
2422
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002423/*
2424 * Reset vreg by ensuring it is off during probe. A call
2425 * to enable vreg is needed to balance disable vreg
2426 */
2427static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2428{
2429 int rc;
2430
Krishna Konda3c4142d2012-06-27 11:01:56 -07002431 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002432 if (rc)
2433 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002434 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002435 return rc;
2436}
2437
Subhash Jadavani937c7502012-06-01 15:34:46 +05302438enum vdd_io_level {
2439 /* set vdd_io_data->low_vol_level */
2440 VDD_IO_LOW,
2441 /* set vdd_io_data->high_vol_level */
2442 VDD_IO_HIGH,
2443 /*
2444 * set whatever there in voltage_level (third argument) of
2445 * msmsdcc_set_vdd_io_vol() function.
2446 */
2447 VDD_IO_SET_LEVEL,
2448};
2449
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302450/*
2451 * This function returns the current VDD IO voltage level.
2452 * Returns negative value if it fails to read the voltage level
2453 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2454 * regulator were not defined for host.
2455 */
2456static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2457{
2458 int rc = 0;
2459
2460 if (host->plat->vreg_data) {
2461 struct msm_mmc_reg_data *io_reg =
2462 host->plat->vreg_data->vdd_io_data;
2463
2464 /*
2465 * If vdd_io is not defined, then we can consider that
2466 * IO voltage is same as VDD.
2467 */
2468 if (!io_reg)
2469 io_reg = host->plat->vreg_data->vdd_data;
2470
2471 if (io_reg && io_reg->is_enabled)
2472 rc = msmsdcc_vreg_get_voltage(io_reg);
2473 }
2474
2475 return rc;
2476}
2477
2478/*
2479 * This function updates the IO pad power switch bit in MCI_CLK register
2480 * based on currrent IO pad voltage level.
2481 * NOTE: This function assumes that host lock was not taken by caller.
2482 */
2483static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2484{
2485 int rc = 0;
2486 unsigned long flags;
2487
2488 if (!is_io_pad_pwr_switch(host))
2489 return;
2490
2491 rc = msmsdcc_get_vdd_io_vol(host);
2492
2493 spin_lock_irqsave(&host->lock, flags);
2494 /*
2495 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2496 * the SDCC instances support the dual voltage pads.
2497 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2498 * bit before using the pads in 1.8V mode.
2499 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2500 * IO_PAD_PWR_SWITCH bit is a don't care.
2501 * But we don't have an option to know (by reading some SDCC register)
2502 * that a particular SDCC instance supports dual voltage pads or not,
2503 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2504 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2505 * is anyway ignored.
2506 */
2507 if (rc > 0 && rc < 2700000)
2508 host->io_pad_pwr_switch = 1;
2509 else
2510 host->io_pad_pwr_switch = 0;
2511
2512 if (atomic_read(&host->clks_on)) {
2513 if (host->io_pad_pwr_switch)
2514 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2515 IO_PAD_PWR_SWITCH),
2516 host->base + MMCICLOCK);
2517 else
2518 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2519 ~IO_PAD_PWR_SWITCH),
2520 host->base + MMCICLOCK);
2521 msmsdcc_sync_reg_wr(host);
2522 }
2523 spin_unlock_irqrestore(&host->lock, flags);
2524}
2525
Subhash Jadavani937c7502012-06-01 15:34:46 +05302526static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2527 enum vdd_io_level level,
2528 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529{
2530 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302531 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002532
2533 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302534 struct msm_mmc_reg_data *vdd_io_reg =
2535 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002536
Subhash Jadavani937c7502012-06-01 15:34:46 +05302537 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2538 switch (level) {
2539 case VDD_IO_LOW:
2540 set_level = vdd_io_reg->low_vol_level;
2541 break;
2542 case VDD_IO_HIGH:
2543 set_level = vdd_io_reg->high_vol_level;
2544 break;
2545 case VDD_IO_SET_LEVEL:
2546 set_level = voltage_level;
2547 break;
2548 default:
2549 pr_err("%s: %s: invalid argument level = %d",
2550 mmc_hostname(host->mmc), __func__,
2551 level);
2552 rc = -EINVAL;
2553 goto out;
2554 }
2555 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2556 set_level, set_level);
2557 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558 }
2559
Subhash Jadavani937c7502012-06-01 15:34:46 +05302560out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302561 return rc;
2562}
2563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2565{
2566 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2567 return 1;
2568 return 0;
2569}
2570
Asutosh Dasf5298c32012-04-03 14:51:47 +05302571/*
2572 * Any function calling msmsdcc_setup_clocks must
2573 * acquire clk_mutex. May sleep.
2574 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302575static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002576{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302577 int rc = 0;
2578
2579 if (enable && !atomic_read(&host->clks_on)) {
2580 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2581 rc = clk_prepare_enable(host->bus_clk);
2582 if (rc) {
2583 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2584 mmc_hostname(host->mmc), __func__, rc);
2585 goto out;
2586 }
2587 }
2588 if (!IS_ERR(host->pclk)) {
2589 rc = clk_prepare_enable(host->pclk);
2590 if (rc) {
2591 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2592 mmc_hostname(host->mmc), __func__, rc);
2593 goto disable_bus;
2594 }
2595 }
2596 rc = clk_prepare_enable(host->clk);
2597 if (rc) {
2598 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2599 mmc_hostname(host->mmc), __func__, rc);
2600 goto disable_pclk;
2601 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302602 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302603 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302604 atomic_set(&host->clks_on, 1);
2605 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302606 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302607 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302608 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302610 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302611 if (!IS_ERR_OR_NULL(host->bus_clk))
2612 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302613 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302615 goto out;
2616
2617disable_pclk:
2618 if (!IS_ERR_OR_NULL(host->pclk))
2619 clk_disable_unprepare(host->pclk);
2620disable_bus:
2621 if (!IS_ERR_OR_NULL(host->bus_clk))
2622 clk_disable_unprepare(host->bus_clk);
2623out:
2624 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625}
2626
2627static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2628 unsigned int req_clk)
2629{
2630 unsigned int sel_clk = -1;
2631
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302632 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2633 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2634 goto out;
2635 }
2636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2638 unsigned char cnt;
2639
2640 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2641 if (host->plat->sup_clk_table[cnt] > req_clk)
2642 break;
2643 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2644 sel_clk = host->plat->sup_clk_table[cnt];
2645 break;
2646 } else
2647 sel_clk = host->plat->sup_clk_table[cnt];
2648 }
2649 } else {
2650 if ((req_clk < host->plat->msmsdcc_fmax) &&
2651 (req_clk > host->plat->msmsdcc_fmid))
2652 sel_clk = host->plat->msmsdcc_fmid;
2653 else
2654 sel_clk = req_clk;
2655 }
2656
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302657out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 return sel_clk;
2659}
2660
2661static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2662 struct msmsdcc_host *host)
2663{
2664 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2665 return host->plat->sup_clk_table[0];
2666 else
2667 return host->plat->msmsdcc_fmin;
2668}
2669
2670static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2671 struct msmsdcc_host *host)
2672{
2673 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2674 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2675 else
2676 return host->plat->msmsdcc_fmax;
2677}
2678
2679static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302680{
2681 struct msm_mmc_gpio_data *curr;
2682 int i, rc = 0;
2683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302685 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302686 if (!gpio_is_valid(curr->gpio[i].no)) {
2687 rc = -EINVAL;
2688 pr_err("%s: Invalid gpio = %d\n",
2689 mmc_hostname(host->mmc), curr->gpio[i].no);
2690 goto free_gpios;
2691 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302692 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693 if (curr->gpio[i].is_always_on &&
2694 curr->gpio[i].is_enabled)
2695 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302696 rc = gpio_request(curr->gpio[i].no,
2697 curr->gpio[i].name);
2698 if (rc) {
2699 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2700 mmc_hostname(host->mmc),
2701 curr->gpio[i].no,
2702 curr->gpio[i].name, rc);
2703 goto free_gpios;
2704 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302706 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 if (curr->gpio[i].is_always_on)
2708 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302709 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302711 }
2712 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302714
2715free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302716 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302717 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002718 curr->gpio[i].is_enabled = false;
2719 }
2720out:
2721 return rc;
2722}
2723
2724static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2725{
2726 struct msm_mmc_pad_data *curr;
2727 int i;
2728
2729 curr = host->plat->pin_data->pad_data;
2730 for (i = 0; i < curr->drv->size; i++) {
2731 if (enable)
2732 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2733 curr->drv->on[i].val);
2734 else
2735 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2736 curr->drv->off[i].val);
2737 }
2738
2739 for (i = 0; i < curr->pull->size; i++) {
2740 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002741 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002742 curr->pull->on[i].val);
2743 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002744 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 curr->pull->off[i].val);
2746 }
2747
2748 return 0;
2749}
2750
2751static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2752{
2753 int rc = 0;
2754
2755 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2756 return 0;
2757
2758 if (host->plat->pin_data->is_gpio)
2759 rc = msmsdcc_setup_gpio(host, enable);
2760 else
2761 rc = msmsdcc_setup_pad(host, enable);
2762
2763 if (!rc)
2764 host->plat->pin_data->cfg_sts = enable;
2765
2766 return rc;
2767}
2768
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302769static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2770 unsigned mode)
2771{
2772 int ret = 0;
2773 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2774
2775 if (!pin)
2776 return 0;
2777
2778 switch (mode) {
2779 case SDC_DAT1_DISABLE:
2780 ret = msm_mpm_enable_pin(pin, 0);
2781 break;
2782 case SDC_DAT1_ENABLE:
2783 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2784 ret = msm_mpm_enable_pin(pin, 1);
2785 break;
2786 case SDC_DAT1_ENWAKE:
2787 ret = msm_mpm_set_pin_wake(pin, 1);
2788 break;
2789 case SDC_DAT1_DISWAKE:
2790 ret = msm_mpm_set_pin_wake(pin, 0);
2791 break;
2792 default:
2793 ret = -EINVAL;
2794 break;
2795 }
2796
2797 return ret;
2798}
2799
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302800static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2801{
2802 u32 pwr = 0;
2803 int ret = 0;
2804 struct mmc_host *mmc = host->mmc;
2805
2806 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2807 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2808 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002809 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302810
2811 if (ret) {
2812 pr_err("%s: Failed to setup voltage regulators\n",
2813 mmc_hostname(host->mmc));
2814 goto out;
2815 }
2816
2817 switch (ios->power_mode) {
2818 case MMC_POWER_OFF:
2819 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302820 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302821 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302822 * If VDD IO rail is always on, set low voltage for VDD
2823 * IO rail when slot is not in use (like when card is not
2824 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302825 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302826 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302827 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302828 msmsdcc_setup_pins(host, false);
2829 break;
2830 case MMC_POWER_UP:
2831 /* writing PWR_UP bit is redundant */
2832 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302833 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302834
Subhash Jadavani937c7502012-06-01 15:34:46 +05302835 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302836 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302837 msmsdcc_setup_pins(host, true);
2838 break;
2839 case MMC_POWER_ON:
2840 pwr = MCI_PWR_ON;
2841 break;
2842 }
2843
2844out:
2845 return pwr;
2846}
2847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2849{
2850 unsigned int wakeup_irq;
2851
2852 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2853 host->plat->sdiowakeup_irq :
2854 host->core_irqres->start;
2855
2856 if (!host->irq_wake_enabled) {
2857 enable_irq_wake(wakeup_irq);
2858 host->irq_wake_enabled = true;
2859 }
2860}
2861
2862static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2863{
2864 unsigned int wakeup_irq;
2865
2866 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2867 host->plat->sdiowakeup_irq :
2868 host->core_irqres->start;
2869
2870 if (host->irq_wake_enabled) {
2871 disable_irq_wake(wakeup_irq);
2872 host->irq_wake_enabled = false;
2873 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302874}
2875
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302876/* Returns required bandwidth in Bytes per Sec */
2877static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2878 struct mmc_ios *ios)
2879{
2880 unsigned int bw;
2881
2882 bw = host->clk_rate;
2883 /*
2884 * For DDR mode, SDCC controller clock will be at
2885 * the double rate than the actual clock that goes to card.
2886 */
2887 if (ios->bus_width == MMC_BUS_WIDTH_4)
2888 bw /= 2;
2889 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2890 bw /= 8;
2891
2892 return bw;
2893}
2894
2895static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2896 unsigned int bw)
2897{
2898 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2899 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2900 int i;
2901
2902 if (host->msm_bus_vote.is_max_bw_needed && bw)
2903 return host->msm_bus_vote.max_bw_vote;
2904
2905 for (i = 0; i < size; i++) {
2906 if (bw <= table[i])
2907 break;
2908 }
2909
2910 if (i && (i == size))
2911 i--;
2912
2913 return i;
2914}
2915
2916static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2917{
2918 int rc = 0;
2919 struct msm_bus_scale_pdata *use_cases;
2920
2921 if (host->plat->msm_bus_voting_data &&
2922 host->plat->msm_bus_voting_data->use_cases &&
2923 host->plat->msm_bus_voting_data->bw_vecs &&
2924 host->plat->msm_bus_voting_data->bw_vecs_size) {
2925 use_cases = host->plat->msm_bus_voting_data->use_cases;
2926 host->msm_bus_vote.client_handle =
2927 msm_bus_scale_register_client(use_cases);
2928 } else {
2929 return 0;
2930 }
2931
2932 if (!host->msm_bus_vote.client_handle) {
2933 pr_err("%s: msm_bus_scale_register_client() failed\n",
2934 mmc_hostname(host->mmc));
2935 rc = -EFAULT;
2936 } else {
2937 /* cache the vote index for minimum and maximum bandwidth */
2938 host->msm_bus_vote.min_bw_vote =
2939 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2940 host->msm_bus_vote.max_bw_vote =
2941 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2942 }
2943
2944 return rc;
2945}
2946
2947static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2948{
2949 if (host->msm_bus_vote.client_handle)
2950 msm_bus_scale_unregister_client(
2951 host->msm_bus_vote.client_handle);
2952}
2953
2954/*
2955 * This function must be called with host lock acquired.
2956 * Caller of this function should also ensure that msm bus client
2957 * handle is not null.
2958 */
2959static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2960 int vote,
2961 unsigned long flags)
2962{
2963 int rc = 0;
2964
2965 if (vote != host->msm_bus_vote.curr_vote) {
2966 spin_unlock_irqrestore(&host->lock, flags);
2967 rc = msm_bus_scale_client_update_request(
2968 host->msm_bus_vote.client_handle, vote);
2969 if (rc)
2970 pr_err("%s: msm_bus_scale_client_update_request() failed."
2971 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2972 mmc_hostname(host->mmc),
2973 host->msm_bus_vote.client_handle, vote, rc);
2974 spin_lock_irqsave(&host->lock, flags);
2975 if (!rc)
2976 host->msm_bus_vote.curr_vote = vote;
2977 }
2978
2979 return rc;
2980}
2981
2982/*
2983 * Internal work. Work to set 0 bandwidth for msm bus.
2984 */
2985static void msmsdcc_msm_bus_work(struct work_struct *work)
2986{
2987 struct msmsdcc_host *host = container_of(work,
2988 struct msmsdcc_host,
2989 msm_bus_vote.vote_work.work);
2990 unsigned long flags;
2991
2992 if (!host->msm_bus_vote.client_handle)
2993 return;
2994
2995 spin_lock_irqsave(&host->lock, flags);
2996 /* don't vote for 0 bandwidth if any request is in progress */
2997 if (!host->curr.mrq)
2998 msmsdcc_msm_bus_set_vote(host,
2999 host->msm_bus_vote.min_bw_vote, flags);
3000 else
3001 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3002 " bus voting to 0 bandwidth\n",
3003 mmc_hostname(host->mmc), __func__);
3004 spin_unlock_irqrestore(&host->lock, flags);
3005}
3006
3007/*
3008 * This function cancels any scheduled delayed work
3009 * and sets the bus vote based on ios argument.
3010 * If "ios" argument is NULL, bandwidth required is 0 else
3011 * calculate the bandwidth based on ios parameters.
3012 */
3013static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3014 struct msmsdcc_host *host,
3015 struct mmc_ios *ios)
3016{
3017 unsigned long flags;
3018 unsigned int bw;
3019 int vote;
3020
3021 if (!host->msm_bus_vote.client_handle)
3022 return;
3023
3024 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3025
3026 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3027 spin_lock_irqsave(&host->lock, flags);
3028 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3029 msmsdcc_msm_bus_set_vote(host, vote, flags);
3030 spin_unlock_irqrestore(&host->lock, flags);
3031}
3032
3033/* This function queues a work which will set the bandwidth requiement to 0 */
3034static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3035{
3036 unsigned long flags;
3037
3038 if (!host->msm_bus_vote.client_handle)
3039 return;
3040
3041 spin_lock_irqsave(&host->lock, flags);
3042 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3043 queue_delayed_work(system_nrt_wq,
3044 &host->msm_bus_vote.vote_work,
3045 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3046 spin_unlock_irqrestore(&host->lock, flags);
3047}
3048
San Mehat9d2bd732009-09-22 16:44:22 -07003049static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303050msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3051{
3052 struct mmc_host *mmc = host->mmc;
3053
3054 /*
3055 * SDIO_AL clients has different mechanism of handling LPM through
3056 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3057 * part of that. Here, we are interested only in clients like WLAN.
3058 */
3059 if (!(mmc->card && mmc_card_sdio(mmc->card))
3060 || host->plat->is_sdio_al_client)
3061 goto out;
3062
3063 if (!host->sdcc_suspended) {
3064 /*
3065 * When MSM is not in power collapse and we
3066 * are disabling clocks, enable bit 22 in MASK0
3067 * to handle asynchronous SDIO interrupts.
3068 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303069 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303070 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303071 mb();
3072 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303073 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303074 msmsdcc_sync_reg_wr(host);
3075 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303076 goto out;
3077 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3078 /*
3079 * Wakeup MSM only if SDIO function drivers set
3080 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3081 */
3082 goto out;
3083 }
3084
3085 if (enable_wakeup_irq) {
3086 if (!host->plat->sdiowakeup_irq) {
3087 /*
3088 * When there is no gpio line that can be configured
3089 * as wakeup interrupt handle it by configuring
3090 * asynchronous sdio interrupts and DAT1 line.
3091 */
3092 writel_relaxed(MCI_SDIOINTMASK,
3093 host->base + MMCIMASK0);
3094 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303095 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303096 /* configure sdcc core interrupt as wakeup interrupt */
3097 msmsdcc_enable_irq_wake(host);
3098 } else {
3099 /* Let gpio line handle wakeup interrupt */
3100 writel_relaxed(0, host->base + MMCIMASK0);
3101 mb();
3102 if (host->sdio_wakeupirq_disabled) {
3103 host->sdio_wakeupirq_disabled = 0;
3104 /* configure gpio line as wakeup interrupt */
3105 msmsdcc_enable_irq_wake(host);
3106 enable_irq(host->plat->sdiowakeup_irq);
3107 }
3108 }
3109 } else {
3110 if (!host->plat->sdiowakeup_irq) {
3111 /*
3112 * We may not have cleared bit 22 in the interrupt
3113 * handler as the clocks might be off at that time.
3114 */
3115 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303116 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303117 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303118 msmsdcc_disable_irq_wake(host);
3119 } else if (!host->sdio_wakeupirq_disabled) {
3120 disable_irq_nosync(host->plat->sdiowakeup_irq);
3121 msmsdcc_disable_irq_wake(host);
3122 host->sdio_wakeupirq_disabled = 1;
3123 }
3124 }
3125out:
3126 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003127}
3128
3129static void
3130msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3131{
3132 struct msmsdcc_host *host = mmc_priv(mmc);
3133 u32 clk = 0, pwr = 0;
3134 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003135 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003137
Sahitya Tummala7a892482011-01-18 11:22:49 +05303138
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303139 /*
3140 * Disable SDCC core interrupt until set_ios is completed.
3141 * This avoids any race conditions with interrupt raised
3142 * when turning on/off the clocks. One possible
3143 * scenario is SDIO operational interrupt while the clock
3144 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303145 * host->lock is being released intermittently below.
3146 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303147 */
3148
Asutosh Dasf5298c32012-04-03 14:51:47 +05303149 mutex_lock(&host->clk_mutex);
3150 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003151 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303152 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303153 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303154 host->sdcc_irq_disabled = 1;
3155 }
San Mehatd0719e52009-12-03 10:58:54 -08003156 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003157
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303158 /* Make sure sdcc core irq is synchronized */
3159 synchronize_irq(host->core_irqres->start);
3160
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303161 pwr = msmsdcc_setup_pwr(host, ios);
3162
3163 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003164 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303165 spin_unlock_irqrestore(&host->lock, flags);
3166 rc = msmsdcc_setup_clocks(host, true);
3167 if (rc)
3168 goto out;
3169 spin_lock_irqsave(&host->lock, flags);
3170 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3171 mb();
3172 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 /*
3176 * For DDR50 mode, controller needs clock rate to be
3177 * double than what is required on the SD card CLK pin.
3178 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303179 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180 /*
3181 * Make sure that we don't double the clock if
3182 * doubled clock rate is already set
3183 */
3184 if (!host->ddr_doubled_clk_rate ||
3185 (host->ddr_doubled_clk_rate &&
3186 (host->ddr_doubled_clk_rate != ios->clock))) {
3187 host->ddr_doubled_clk_rate =
3188 msmsdcc_get_sup_clk_rate(
3189 host, (ios->clock * 2));
3190 clock = host->ddr_doubled_clk_rate;
3191 }
3192 } else {
3193 host->ddr_doubled_clk_rate = 0;
3194 }
3195
3196 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303197 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003198 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303199 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303201 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 mmc_hostname(mmc), clock);
3203 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303204 host->reg_write_delay =
3205 (1 + ((3 * USEC_PER_SEC) /
3206 (host->clk_rate ? host->clk_rate :
3207 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208 }
3209 /*
3210 * give atleast 2 MCLK cycles delay for clocks
3211 * and SDCC core to stabilize
3212 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303213 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003215 clk |= MCI_CLK_ENABLE;
3216 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217 if (ios->bus_width == MMC_BUS_WIDTH_8)
3218 clk |= MCI_CLK_WIDEBUS_8;
3219 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3220 clk |= MCI_CLK_WIDEBUS_4;
3221 else
3222 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003224 if (msmsdcc_is_pwrsave(host))
3225 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 host->tuning_needed = 0;
3230 /*
3231 * Select the controller timing mode according
3232 * to current bus speed mode
3233 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303234 if (host->clk_rate > (100 * 1000 * 1000) &&
3235 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3236 ios->timing == MMC_TIMING_MMC_HS200)) {
3237 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 clk |= (4 << 14);
3239 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303240 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003241 clk |= (3 << 14);
3242 } else {
3243 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003244 }
3245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003246 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3247 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249 if (host->io_pad_pwr_switch)
3250 clk |= IO_PAD_PWR_SWITCH;
3251
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303252 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303253 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303254 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3255 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303256 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003257 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303258 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3259 host->pwr = pwr;
3260 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303261 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 }
San Mehat9d2bd732009-09-22 16:44:22 -07003263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003264
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303265 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303266 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303267 spin_unlock_irqrestore(&host->lock, flags);
3268 /*
3269 * May get a wake-up interrupt the instant we disable the
3270 * clocks. This would disable the wake-up interrupt.
3271 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303273 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003274 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303275
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303276 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303277 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303278 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303279
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303280 /* Let interrupts be disabled if the host is powered off */
3281 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3282 enable_irq(host->core_irqres->start);
3283 host->sdcc_irq_disabled = 0;
3284 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003285 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303286out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303287 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003288}
3289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003290int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3291{
3292 struct msmsdcc_host *host = mmc_priv(mmc);
3293 u32 clk;
3294
3295 clk = readl_relaxed(host->base + MMCICLOCK);
3296 pr_debug("Changing to pwr_save=%d", pwrsave);
3297 if (pwrsave && msmsdcc_is_pwrsave(host))
3298 clk |= MCI_CLK_PWRSAVE;
3299 else
3300 clk &= ~MCI_CLK_PWRSAVE;
3301 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303302 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003303
3304 return 0;
3305}
3306
3307static int msmsdcc_get_ro(struct mmc_host *mmc)
3308{
3309 int status = -ENOSYS;
3310 struct msmsdcc_host *host = mmc_priv(mmc);
3311
3312 if (host->plat->wpswitch) {
3313 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303314 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003315 status = gpio_request(host->plat->wpswitch_gpio,
3316 "SD_WP_Switch");
3317 if (status) {
3318 pr_err("%s: %s: Failed to request GPIO %d\n",
3319 mmc_hostname(mmc), __func__,
3320 host->plat->wpswitch_gpio);
3321 } else {
3322 status = gpio_direction_input(
3323 host->plat->wpswitch_gpio);
3324 if (!status) {
3325 /*
3326 * Wait for atleast 300ms as debounce
3327 * time for GPIO input to stabilize.
3328 */
3329 msleep(300);
3330 status = gpio_get_value_cansleep(
3331 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303332 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003333 }
3334 gpio_free(host->plat->wpswitch_gpio);
3335 }
3336 }
3337
3338 if (status < 0)
3339 status = -ENOSYS;
3340 pr_debug("%s: Card read-only status %d\n", __func__, status);
3341
3342 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003343}
3344
3345static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3346{
3347 struct msmsdcc_host *host = mmc_priv(mmc);
3348 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303350 /*
3351 * We may come here with clocks turned off in that case don't
3352 * attempt to write into MASK0 register. While turning on the
3353 * clocks mci_irqenable will be written to MASK0 register.
3354 */
San Mehat9d2bd732009-09-22 16:44:22 -07003355
3356 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003357 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303359 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303360 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303362 mb();
3363 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364 } else {
3365 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303366 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303367 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003368 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303369 mb();
3370 }
San Mehat9d2bd732009-09-22 16:44:22 -07003371 }
3372 spin_unlock_irqrestore(&host->lock, flags);
3373}
3374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303376static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003377{
subhashj245831e2012-04-30 18:46:17 +05303378 struct device *dev = mmc_dev(host->mmc);
3379
Subhash Jadavani1371d192012-08-16 18:46:57 +05303380 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3381 mmc_hostname(host->mmc), host->sdcc_suspended,
3382 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303383 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3384 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3385 " request_pending=%d, request=%d\n",
3386 mmc_hostname(host->mmc), dev->power.runtime_status,
3387 atomic_read(&dev->power.usage_count),
3388 dev->power.is_suspended, dev->power.disable_depth,
3389 dev->power.runtime_error, dev->power.request_pending,
3390 dev->power.request);
3391}
3392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393static int msmsdcc_enable(struct mmc_host *mmc)
3394{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003395 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003397 struct msmsdcc_host *host = mmc_priv(mmc);
3398
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303399 msmsdcc_pm_qos_update_latency(host, 1);
3400
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003401 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303402 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403
Subhash Jadavani1371d192012-08-16 18:46:57 +05303404 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003405 host->pending_resume = false;
3406 pm_runtime_get_noresume(dev);
3407 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303408 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003409 }
3410
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303411 if (dev->power.runtime_status == RPM_SUSPENDING) {
3412 if (mmc->suspend_task == current) {
3413 pm_runtime_get_noresume(dev);
3414 goto out;
3415 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303416 } else if (dev->power.runtime_status == RPM_RESUMING) {
3417 pm_runtime_get_noresume(dev);
3418 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303419 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003420
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303421 rc = pm_runtime_get_sync(dev);
3422
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303423skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303424 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303425 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3426 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303427 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303428 return rc;
3429 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303430out:
3431 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303432 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433}
3434
Steve Mucklef132c6c2012-06-06 18:30:57 -07003435static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436{
3437 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303438 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303440 msmsdcc_pm_qos_update_latency(host, 0);
3441
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303442 if (mmc->card && mmc_card_sdio(mmc->card)) {
3443 rc = 0;
3444 goto out;
3445 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303446
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303447 if (host->plat->disable_runtime_pm)
3448 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449
3450 rc = pm_runtime_put_sync(mmc->parent);
3451
Subhash Jadavani1371d192012-08-16 18:46:57 +05303452 if (rc < 0) {
3453 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3454 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303455 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003456 return rc;
3457 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303458
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303459out:
3460 msmsdcc_msm_bus_queue_work(host);
3461 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462}
3463#else
subhashj245831e2012-04-30 18:46:17 +05303464static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3465
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303466static int msmsdcc_enable(struct mmc_host *mmc)
3467{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003468 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303469 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303470 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303471
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303472 msmsdcc_pm_qos_update_latency(host, 1);
3473
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303474 if (mmc->card && mmc_card_sdio(mmc->card)) {
3475 rc = 0;
3476 goto out;
3477 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003478
3479 if (host->sdcc_suspended && host->pending_resume) {
3480 host->pending_resume = false;
3481 rc = msmsdcc_runtime_resume(dev);
3482 goto out;
3483 }
3484
Asutosh Dasf5298c32012-04-03 14:51:47 +05303485 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303486 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303487 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303488
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003489out:
3490 if (rc < 0) {
3491 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3492 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303493 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003494 return rc;
3495 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303496 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303497 return 0;
3498}
3499
Steve Mucklef132c6c2012-06-06 18:30:57 -07003500static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303501{
3502 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303503 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303504
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303505 msmsdcc_pm_qos_update_latency(host, 0);
3506
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303507 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303508 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303509
Asutosh Dasf5298c32012-04-03 14:51:47 +05303510 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303511 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303512 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303513
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303514 if (rc) {
3515 msmsdcc_pm_qos_update_latency(host, 1);
3516 return rc;
3517 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303518out:
3519 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303520 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303521}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522#endif
3523
Subhash Jadavani937c7502012-06-01 15:34:46 +05303524static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3525 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526{
3527 struct msmsdcc_host *host = mmc_priv(mmc);
3528 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303529 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530
Subhash Jadavani937c7502012-06-01 15:34:46 +05303531 switch (ios->signal_voltage) {
3532 case MMC_SIGNAL_VOLTAGE_330:
3533 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3534 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303535 if (!rc)
3536 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303537 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303538 case MMC_SIGNAL_VOLTAGE_180:
3539 break;
3540 case MMC_SIGNAL_VOLTAGE_120:
3541 /*
3542 * For eMMC cards, VDD_IO voltage range must be changed
3543 * only if it operates in HS200 SDR 1.2V mode or in
3544 * DDR 1.2V mode.
3545 */
3546 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303547 if (!rc)
3548 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303550 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303552 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003553 goto out;
3554 }
San Mehat9d2bd732009-09-22 16:44:22 -07003555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003556 /*
3557 * If we are here means voltage switch from high voltage to
3558 * low voltage is required
3559 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303560 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561
3562 /*
3563 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3564 * register until they become all zeros.
3565 */
3566 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303567 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3569 mmc_hostname(mmc), __func__);
3570 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003571 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572
3573 /* Stop SD CLK output. */
3574 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3575 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303576 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003577 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578
3579 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303580 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3581 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303583 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303584 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003585 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303587 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003588
3589 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3590 usleep_range(5000, 5500);
3591
3592 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303593 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003594 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3595 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303596 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 spin_unlock_irqrestore(&host->lock, flags);
3598
3599 /*
3600 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3601 * don't become all ones within 1 ms then a Voltage Switch
3602 * sequence has failed and a power cycle to the card is required.
3603 * Otherwise Voltage Switch sequence is completed successfully.
3604 */
3605 usleep_range(1000, 1500);
3606
3607 spin_lock_irqsave(&host->lock, flags);
3608 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3609 != (0xF << 1)) {
3610 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3611 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303612 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613 goto out_unlock;
3614 }
3615
3616out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303617 /* Enable PWRSAVE */
3618 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3619 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303620 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003621 spin_unlock_irqrestore(&host->lock, flags);
3622out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303623 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624}
3625
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303626static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629
3630 /* Program the MCLK value to MCLK_FREQ bit field */
3631 if (host->clk_rate <= 112000000)
3632 mclk_freq = 0;
3633 else if (host->clk_rate <= 125000000)
3634 mclk_freq = 1;
3635 else if (host->clk_rate <= 137000000)
3636 mclk_freq = 2;
3637 else if (host->clk_rate <= 150000000)
3638 mclk_freq = 3;
3639 else if (host->clk_rate <= 162000000)
3640 mclk_freq = 4;
3641 else if (host->clk_rate <= 175000000)
3642 mclk_freq = 5;
3643 else if (host->clk_rate <= 187000000)
3644 mclk_freq = 6;
3645 else if (host->clk_rate <= 200000000)
3646 mclk_freq = 7;
3647
3648 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3649 & ~(7 << 24)) | (mclk_freq << 24)),
3650 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651}
3652
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303653/* Initialize the DLL (Programmable Delay Line ) */
3654static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303657 unsigned long flags;
3658 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303660 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003661 /*
3662 * Make sure that clock is always enabled when DLL
3663 * tuning is in progress. Keeping PWRSAVE ON may
3664 * turn off the clock. So let's disable the PWRSAVE
3665 * here and re-enable it once tuning is completed.
3666 */
3667 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3668 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303669 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303670
3671 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3672 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3673 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3674
3675 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3676 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3677 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3678
3679 msmsdcc_cm_sdc4_dll_set_freq(host);
3680
3681 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3682 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3683 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3684
3685 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3686 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3687 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3688
3689 /* Set DLL_EN bit to 1. */
3690 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3691 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3692
3693 /* Set CK_OUT_EN bit to 1. */
3694 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3695 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3696
3697 wait_cnt = 50;
3698 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3699 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3700 /* max. wait for 50us sec for LOCK bit to be set */
3701 if (--wait_cnt == 0) {
3702 pr_err("%s: %s: DLL failed to LOCK\n",
3703 mmc_hostname(host->mmc), __func__);
3704 rc = -ETIMEDOUT;
3705 goto out;
3706 }
3707 /* wait for 1us before polling again */
3708 udelay(1);
3709 }
3710
3711out:
3712 /* re-enable PWRSAVE */
3713 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3714 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303715 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303716 spin_unlock_irqrestore(&host->lock, flags);
3717
3718 return rc;
3719}
3720
3721static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3722 u8 poll)
3723{
3724 int rc = 0;
3725 u32 wait_cnt = 50;
3726 u8 ck_out_en = 0;
3727
3728 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3729 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3730 MCI_CK_OUT_EN);
3731
3732 while (ck_out_en != poll) {
3733 if (--wait_cnt == 0) {
3734 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3735 mmc_hostname(host->mmc), __func__, poll);
3736 rc = -ETIMEDOUT;
3737 goto out;
3738 }
3739 udelay(1);
3740
3741 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3742 MCI_CK_OUT_EN);
3743 }
3744out:
3745 return rc;
3746}
3747
3748/*
3749 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3750 * calibration sequence. This function should be called before
3751 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3752 * commands (CMD17/CMD18).
3753 *
3754 * This function gets called when host spinlock acquired.
3755 */
3756static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3757{
3758 int rc = 0;
3759 u32 config;
3760
3761 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3762 config |= MCI_CDR_EN;
3763 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3764 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3765
3766 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3767 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3768 if (rc)
3769 goto err_out;
3770
3771 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3772 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3773 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3774
3775 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3776 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3777 if (rc)
3778 goto err_out;
3779
3780 goto out;
3781
3782err_out:
3783 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3784out:
3785 return rc;
3786}
3787
3788static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3789 u8 phase)
3790{
3791 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303792 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3793 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3794 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303795 unsigned long flags;
3796 u32 config;
3797
3798 spin_lock_irqsave(&host->lock, flags);
3799
3800 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3801 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3802 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3803 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3804
3805 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3806 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3807 if (rc)
3808 goto err_out;
3809
3810 /*
3811 * Write the selected DLL clock output phase (0 ... 15)
3812 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3813 */
3814 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3815 & ~(0xF << 20))
3816 | (grey_coded_phase_table[phase] << 20)),
3817 host->base + MCI_DLL_CONFIG);
3818
3819 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3820 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3821 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3822
3823 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3824 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3825 if (rc)
3826 goto err_out;
3827
3828 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3829 config |= MCI_CDR_EN;
3830 config &= ~MCI_CDR_EXT_EN;
3831 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3832 goto out;
3833
3834err_out:
3835 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3836 mmc_hostname(host->mmc), __func__, phase);
3837out:
3838 spin_unlock_irqrestore(&host->lock, flags);
3839 return rc;
3840}
3841
3842/*
3843 * Find out the greatest range of consecuitive selected
3844 * DLL clock output phases that can be used as sampling
3845 * setting for SD3.0 UHS-I card read operation (in SDR104
3846 * timing mode) or for eMMC4.5 card read operation (in HS200
3847 * timing mode).
3848 * Select the 3/4 of the range and configure the DLL with the
3849 * selected DLL clock output phase.
3850*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303851static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303852 u8 *phase_table, u8 total_phases)
3853{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303854 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303855 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303856 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3857 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303858 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303859 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3860 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303861
Subhash Jadavani6159c622012-03-15 19:05:55 +05303862 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303863 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3864 mmc_hostname(host->mmc), __func__, total_phases);
3865 return -EINVAL;
3866 }
3867
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303868 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303869 ranges[row_index][col_index] = phase_table[cnt];
3870 phases_per_row[row_index] += 1;
3871 col_index++;
3872
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303873 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303874 continue;
3875 /* check if next phase in phase_table is consecutive or not */
3876 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3877 row_index++;
3878 col_index = 0;
3879 }
3880 }
3881
Subhash Jadavani6159c622012-03-15 19:05:55 +05303882 if (row_index >= MAX_PHASES)
3883 return -EINVAL;
3884
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303885 /* Check if phase-0 is present in first valid window? */
3886 if (!ranges[0][0]) {
3887 phase_0_found = true;
3888 phase_0_raw_index = 0;
3889 /* Check if cycle exist between 2 valid windows */
3890 for (cnt = 1; cnt <= row_index; cnt++) {
3891 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303892 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303893 if (ranges[cnt][i] == 15) {
3894 phase_15_found = true;
3895 phase_15_raw_index = cnt;
3896 break;
3897 }
3898 }
3899 }
3900 }
3901 }
3902
3903 /* If 2 valid windows form cycle then merge them as single window */
3904 if (phase_0_found && phase_15_found) {
3905 /* number of phases in raw where phase 0 is present */
3906 u8 phases_0 = phases_per_row[phase_0_raw_index];
3907 /* number of phases in raw where phase 15 is present */
3908 u8 phases_15 = phases_per_row[phase_15_raw_index];
3909
Subhash Jadavani6159c622012-03-15 19:05:55 +05303910 if (phases_0 + phases_15 >= MAX_PHASES)
3911 /*
3912 * If there are more than 1 phase windows then total
3913 * number of phases in both the windows should not be
3914 * more than or equal to MAX_PHASES.
3915 */
3916 return -EINVAL;
3917
3918 /* Merge 2 cyclic windows */
3919 i = phases_15;
3920 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303921 ranges[phase_15_raw_index][i] =
3922 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303923 if (++i >= MAX_PHASES)
3924 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303925 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303926
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303927 phases_per_row[phase_0_raw_index] = 0;
3928 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3929 }
3930
3931 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303932 if (phases_per_row[cnt] > curr_max) {
3933 curr_max = phases_per_row[cnt];
3934 selected_row_index = cnt;
3935 }
3936 }
3937
Subhash Jadavani6159c622012-03-15 19:05:55 +05303938 i = ((curr_max * 3) / 4);
3939 if (i)
3940 i--;
3941
Subhash Jadavani34187042012-03-02 10:59:49 +05303942 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303943
Subhash Jadavani6159c622012-03-15 19:05:55 +05303944 if (ret >= MAX_PHASES) {
3945 ret = -EINVAL;
3946 pr_err("%s: %s: invalid phase selected=%d\n",
3947 mmc_hostname(host->mmc), __func__, ret);
3948 }
3949
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303950 return ret;
3951}
3952
Girish K Sa3f41692012-02-29 12:00:09 +05303953static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303954{
3955 int rc = 0;
3956 struct msmsdcc_host *host = mmc_priv(mmc);
3957 unsigned long flags;
3958 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303959 const u32 *tuning_block_pattern = tuning_block_64;
3960 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303961
3962 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3963
3964 /* Tuning is only required for SDR104 modes */
3965 if (!host->tuning_needed) {
3966 rc = 0;
3967 goto exit;
3968 }
3969
3970 spin_lock_irqsave(&host->lock, flags);
3971 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303972 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303973 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3974
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303975 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303976 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3977 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3978 tuning_block_pattern = tuning_block_128;
3979 size = sizeof(tuning_block_128);
3980 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303981 spin_unlock_irqrestore(&host->lock, flags);
3982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003983 /* first of all reset the tuning block */
3984 rc = msmsdcc_init_cm_sdc4_dll(host);
3985 if (rc)
3986 goto out;
3987
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303988 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003989 if (!data_buf) {
3990 rc = -ENOMEM;
3991 goto out;
3992 }
3993
3994 phase = 0;
3995 do {
3996 struct mmc_command cmd = {0};
3997 struct mmc_data data = {0};
3998 struct mmc_request mrq = {
3999 .cmd = &cmd,
4000 .data = &data
4001 };
4002 struct scatterlist sg;
4003
4004 /* set the phase in delay line hw block */
4005 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4006 if (rc)
4007 goto kfree;
4008
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304009 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4011
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304012 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004013 data.blocks = 1;
4014 data.flags = MMC_DATA_READ;
4015 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4016
4017 data.sg = &sg;
4018 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304019 sg_init_one(&sg, data_buf, size);
4020 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 mmc_wait_for_req(mmc, &mrq);
4022
4023 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304024 !memcmp(data_buf, tuning_block_pattern, size)) {
4025 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304027 pr_debug("%s: %s: found good phase = %d\n",
4028 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029 }
4030 } while (++phase < 16);
4031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304033 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304034 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304035 if (rc < 0)
4036 goto kfree;
4037 else
4038 phase = (u8)rc;
4039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 /*
4041 * Finally set the selected phase in delay
4042 * line hw block.
4043 */
4044 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4045 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304046 goto kfree;
4047 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4048 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004049 } else {
4050 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304051 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304053 msmsdcc_dump_sdcc_state(host);
4054 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056
4057kfree:
4058 kfree(data_buf);
4059out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304060 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304061 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304062 spin_unlock_irqrestore(&host->lock, flags);
4063exit:
4064 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004066}
4067
Asutosh Dasebd7d092012-07-09 19:08:26 +05304068/*
4069 * Work around of the unavailability of a power_reset functionality in SD cards
4070 * by turning the OFF & back ON the regulators supplying the SD card.
4071 */
4072void msmsdcc_hw_reset(struct mmc_host *mmc)
4073{
4074 struct mmc_card *card = mmc->card;
4075 struct msmsdcc_host *host = mmc_priv(mmc);
4076 int rc;
4077
4078 /* Write-protection bits would be lost on a hardware reset in emmc */
4079 if (!card || !mmc_card_sd(card))
4080 return;
4081
4082 /*
4083 * Continuing on failing to disable regulator would lead to a panic
4084 * anyway, since the commands would fail and console would be flooded
4085 * with prints, eventually leading to a watchdog bark
4086 */
4087 rc = msmsdcc_setup_vreg(host, false, false);
4088 if (rc) {
4089 pr_err("%s: %s disable regulator: failed: %d\n",
4090 mmc_hostname(mmc), __func__, rc);
4091 BUG_ON(rc);
4092 }
4093
4094 /* 10ms delay for the supply to reach the desired voltage level */
4095 usleep_range(10000, 12000);
4096
4097 /*
4098 * Continuing on failing to enable 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, true, false);
4103 if (rc) {
4104 pr_err("%s: %s enable 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
San Mehat9d2bd732009-09-22 16:44:22 -07004113static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004114 .enable = msmsdcc_enable,
4115 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304116 .pre_req = msmsdcc_pre_req,
4117 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004118 .request = msmsdcc_request,
4119 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004121 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304122 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304123 .execute_tuning = msmsdcc_execute_tuning,
4124 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004125};
4126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127static unsigned int
4128msmsdcc_slot_status(struct msmsdcc_host *host)
4129{
4130 int status;
4131 unsigned int gpio_no = host->plat->status_gpio;
4132
4133 status = gpio_request(gpio_no, "SD_HW_Detect");
4134 if (status) {
4135 pr_err("%s: %s: Failed to request GPIO %d\n",
4136 mmc_hostname(host->mmc), __func__, gpio_no);
4137 } else {
4138 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004139 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004140 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004141 if (host->plat->is_status_gpio_active_low)
4142 status = !status;
4143 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004144 gpio_free(gpio_no);
4145 }
4146 return status;
4147}
4148
San Mehat9d2bd732009-09-22 16:44:22 -07004149static void
4150msmsdcc_check_status(unsigned long data)
4151{
4152 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4153 unsigned int status;
4154
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304155 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004156 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004158 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 status = msmsdcc_slot_status(host);
4160
Krishna Konda941604a2012-01-10 17:46:34 -08004161 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004164 if (host->plat->status)
4165 pr_info("%s: Slot status change detected "
4166 "(%d -> %d)\n",
4167 mmc_hostname(host->mmc),
4168 host->oldstat, status);
4169 else if (host->plat->is_status_gpio_active_low)
4170 pr_info("%s: Slot status change detected "
4171 "(%d -> %d) and the card detect GPIO"
4172 " is ACTIVE_LOW\n",
4173 mmc_hostname(host->mmc),
4174 host->oldstat, status);
4175 else
4176 pr_info("%s: Slot status change detected "
4177 "(%d -> %d) and the card detect GPIO"
4178 " is ACTIVE_HIGH\n",
4179 mmc_hostname(host->mmc),
4180 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004181 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004182 }
4183 host->oldstat = status;
4184 } else {
4185 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004186 }
San Mehat9d2bd732009-09-22 16:44:22 -07004187}
4188
4189static irqreturn_t
4190msmsdcc_platform_status_irq(int irq, void *dev_id)
4191{
4192 struct msmsdcc_host *host = dev_id;
4193
Girish K Sa3c76eb2011-10-11 11:44:09 +05304194 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004195 msmsdcc_check_status((unsigned long) host);
4196 return IRQ_HANDLED;
4197}
4198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199static irqreturn_t
4200msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4201{
4202 struct msmsdcc_host *host = dev_id;
4203
4204 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4205 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304206 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004207 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304208 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209 wake_lock(&host->sdio_wlock);
4210 msmsdcc_disable_irq_wake(host);
4211 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304212 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004213 }
4214 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004215 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304216 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304217 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304218 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004219 }
4220 spin_unlock(&host->lock);
4221
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304222out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 return IRQ_HANDLED;
4224}
4225
San Mehat9d2bd732009-09-22 16:44:22 -07004226static void
4227msmsdcc_status_notify_cb(int card_present, void *dev_id)
4228{
4229 struct msmsdcc_host *host = dev_id;
4230
Girish K Sa3c76eb2011-10-11 11:44:09 +05304231 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004232 card_present);
4233 msmsdcc_check_status((unsigned long) host);
4234}
4235
San Mehat9d2bd732009-09-22 16:44:22 -07004236static int
4237msmsdcc_init_dma(struct msmsdcc_host *host)
4238{
4239 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4240 host->dma.host = host;
4241 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004242 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004243
4244 if (!host->dmares)
4245 return -ENODEV;
4246
4247 host->dma.nc = dma_alloc_coherent(NULL,
4248 sizeof(struct msmsdcc_nc_dmadata),
4249 &host->dma.nc_busaddr,
4250 GFP_KERNEL);
4251 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004252 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004253 return -ENOMEM;
4254 }
4255 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4256 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4257 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4258 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4259 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004260 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004261
4262 return 0;
4263}
4264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004265#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4266/**
4267 * Allocate and Connect a SDCC peripheral's SPS endpoint
4268 *
4269 * This function allocates endpoint context and
4270 * connect it with memory endpoint by calling
4271 * appropriate SPS driver APIs.
4272 *
4273 * Also registers a SPS callback function with
4274 * SPS driver
4275 *
4276 * This function should only be called once typically
4277 * during driver probe.
4278 *
4279 * @host - Pointer to sdcc host structure
4280 * @ep - Pointer to sps endpoint data structure
4281 * @is_produce - 1 means Producer endpoint
4282 * 0 means Consumer endpoint
4283 *
4284 * @return - 0 if successful else negative value.
4285 *
4286 */
4287static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4288 struct msmsdcc_sps_ep_conn_data *ep,
4289 bool is_producer)
4290{
4291 int rc = 0;
4292 struct sps_pipe *sps_pipe_handle;
4293 struct sps_connect *sps_config = &ep->config;
4294 struct sps_register_event *sps_event = &ep->event;
4295
4296 /* Allocate endpoint context */
4297 sps_pipe_handle = sps_alloc_endpoint();
4298 if (!sps_pipe_handle) {
4299 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4300 mmc_hostname(host->mmc), is_producer);
4301 rc = -ENOMEM;
4302 goto out;
4303 }
4304
4305 /* Get default connection configuration for an endpoint */
4306 rc = sps_get_config(sps_pipe_handle, sps_config);
4307 if (rc) {
4308 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4309 " rc=%d", mmc_hostname(host->mmc),
4310 (u32)sps_pipe_handle, rc);
4311 goto get_config_err;
4312 }
4313
4314 /* Modify the default connection configuration */
4315 if (is_producer) {
4316 /*
4317 * For SDCC producer transfer, source should be
4318 * SDCC peripheral where as destination should
4319 * be system memory.
4320 */
4321 sps_config->source = host->sps.bam_handle;
4322 sps_config->destination = SPS_DEV_HANDLE_MEM;
4323 /* Producer pipe will handle this connection */
4324 sps_config->mode = SPS_MODE_SRC;
4325 sps_config->options =
4326 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4327 } else {
4328 /*
4329 * For SDCC consumer transfer, source should be
4330 * system memory where as destination should
4331 * SDCC peripheral
4332 */
4333 sps_config->source = SPS_DEV_HANDLE_MEM;
4334 sps_config->destination = host->sps.bam_handle;
4335 sps_config->mode = SPS_MODE_DEST;
4336 sps_config->options =
4337 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4338 }
4339
4340 /* Producer pipe index */
4341 sps_config->src_pipe_index = host->sps.src_pipe_index;
4342 /* Consumer pipe index */
4343 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4344 /*
4345 * This event thresold value is only significant for BAM-to-BAM
4346 * transfer. It's ignored for BAM-to-System mode transfer.
4347 */
4348 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304349
4350 /* Allocate maximum descriptor fifo size */
4351 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4352 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004353 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4354 sps_config->desc.size,
4355 &sps_config->desc.phys_base,
4356 GFP_KERNEL);
4357
Pratibhasagar V00b94332011-10-18 14:57:27 +05304358 if (!sps_config->desc.base) {
4359 rc = -ENOMEM;
4360 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4361 , mmc_hostname(host->mmc));
4362 goto get_config_err;
4363 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004364 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4365
4366 /* Establish connection between peripheral and memory endpoint */
4367 rc = sps_connect(sps_pipe_handle, sps_config);
4368 if (rc) {
4369 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4370 " rc=%d", mmc_hostname(host->mmc),
4371 (u32)sps_pipe_handle, rc);
4372 goto sps_connect_err;
4373 }
4374
4375 sps_event->mode = SPS_TRIGGER_CALLBACK;
4376 sps_event->options = SPS_O_EOT;
4377 sps_event->callback = msmsdcc_sps_complete_cb;
4378 sps_event->xfer_done = NULL;
4379 sps_event->user = (void *)host;
4380
4381 /* Register callback event for EOT (End of transfer) event. */
4382 rc = sps_register_event(sps_pipe_handle, sps_event);
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 reg_event_err;
4388 }
4389 /* Now save the sps pipe handle */
4390 ep->pipe_handle = sps_pipe_handle;
4391 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4392 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4393 __func__, is_producer ? "READ" : "WRITE",
4394 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4395 goto out;
4396
4397reg_event_err:
4398 sps_disconnect(sps_pipe_handle);
4399sps_connect_err:
4400 dma_free_coherent(mmc_dev(host->mmc),
4401 sps_config->desc.size,
4402 sps_config->desc.base,
4403 sps_config->desc.phys_base);
4404get_config_err:
4405 sps_free_endpoint(sps_pipe_handle);
4406out:
4407 return rc;
4408}
4409
4410/**
4411 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4412 *
4413 * This function disconnect endpoint and deallocates
4414 * endpoint context.
4415 *
4416 * This function should only be called once typically
4417 * during driver remove.
4418 *
4419 * @host - Pointer to sdcc host structure
4420 * @ep - Pointer to sps endpoint data structure
4421 *
4422 */
4423static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4424 struct msmsdcc_sps_ep_conn_data *ep)
4425{
4426 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4427 struct sps_connect *sps_config = &ep->config;
4428 struct sps_register_event *sps_event = &ep->event;
4429
4430 sps_event->xfer_done = NULL;
4431 sps_event->callback = NULL;
4432 sps_register_event(sps_pipe_handle, sps_event);
4433 sps_disconnect(sps_pipe_handle);
4434 dma_free_coherent(mmc_dev(host->mmc),
4435 sps_config->desc.size,
4436 sps_config->desc.base,
4437 sps_config->desc.phys_base);
4438 sps_free_endpoint(sps_pipe_handle);
4439}
4440
4441/**
4442 * Reset SDCC peripheral's SPS endpoint
4443 *
4444 * This function disconnects an endpoint.
4445 *
4446 * This function should be called for reseting
4447 * SPS endpoint when data transfer error is
4448 * encountered during data transfer. This
4449 * can be considered as soft reset to endpoint.
4450 *
4451 * This function should only be called if
4452 * msmsdcc_sps_init() is already called.
4453 *
4454 * @host - Pointer to sdcc host structure
4455 * @ep - Pointer to sps endpoint data structure
4456 *
4457 * @return - 0 if successful else negative value.
4458 */
4459static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4460 struct msmsdcc_sps_ep_conn_data *ep)
4461{
4462 int rc = 0;
4463 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4464
4465 rc = sps_disconnect(sps_pipe_handle);
4466 if (rc) {
4467 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4468 " rc=%d", mmc_hostname(host->mmc), __func__,
4469 (u32)sps_pipe_handle, rc);
4470 goto out;
4471 }
4472 out:
4473 return rc;
4474}
4475
4476/**
4477 * Restore SDCC peripheral's SPS endpoint
4478 *
4479 * This function connects an endpoint.
4480 *
4481 * This function should be called for restoring
4482 * SPS endpoint after data transfer error is
4483 * encountered during data transfer. This
4484 * can be considered as soft reset to endpoint.
4485 *
4486 * This function should only be called if
4487 * msmsdcc_sps_reset_ep() is called before.
4488 *
4489 * @host - Pointer to sdcc host structure
4490 * @ep - Pointer to sps endpoint data structure
4491 *
4492 * @return - 0 if successful else negative value.
4493 */
4494static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4495 struct msmsdcc_sps_ep_conn_data *ep)
4496{
4497 int rc = 0;
4498 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4499 struct sps_connect *sps_config = &ep->config;
4500 struct sps_register_event *sps_event = &ep->event;
4501
4502 /* Establish connection between peripheral and memory endpoint */
4503 rc = sps_connect(sps_pipe_handle, sps_config);
4504 if (rc) {
4505 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4506 " rc=%d", mmc_hostname(host->mmc), __func__,
4507 (u32)sps_pipe_handle, rc);
4508 goto out;
4509 }
4510
4511 /* Register callback event for EOT (End of transfer) event. */
4512 rc = sps_register_event(sps_pipe_handle, sps_event);
4513 if (rc) {
4514 pr_err("%s: %s: sps_register_event() failed!!!"
4515 " pipe_handle=0x%x, rc=%d",
4516 mmc_hostname(host->mmc), __func__,
4517 (u32)sps_pipe_handle, rc);
4518 goto reg_event_err;
4519 }
4520 goto out;
4521
4522reg_event_err:
4523 sps_disconnect(sps_pipe_handle);
4524out:
4525 return rc;
4526}
4527
4528/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004529 * Handle BAM device's global error condition
4530 *
4531 * This is an error handler for the SDCC bam device
4532 *
4533 * This function is registered as a callback with SPS-BAM
4534 * driver and will called in case there are an errors for
4535 * the SDCC BAM deivce. Any error conditions in the BAM
4536 * device are global and will be result in this function
4537 * being called once per device.
4538 *
4539 * This function will be called from the sps driver's
4540 * interrupt context.
4541 *
4542 * @sps_cb_case - indicates what error it is
4543 * @user - Pointer to sdcc host structure
4544 */
4545static void
4546msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4547{
4548 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4549 struct mmc_request *mrq;
4550 unsigned long flags;
4551 int32_t error = 0;
4552
4553 BUG_ON(!host);
4554 BUG_ON(!is_sps_mode(host));
4555
4556 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4557 /**
4558 * Reset the all endpoints along with reseting the sps device.
4559 */
4560 host->sps.pipe_reset_pending = true;
4561 host->sps.reset_device = true;
4562
4563 pr_err("%s: BAM Global ERROR IRQ happened\n",
4564 mmc_hostname(host->mmc));
4565 error = EAGAIN;
4566 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4567 /**
4568 * This means that there was an AHB access error and
4569 * the address we are trying to read/write is something
4570 * we dont have priviliges to do so.
4571 */
4572 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4573 mmc_hostname(host->mmc));
4574 error = EACCES;
4575 } else {
4576 /**
4577 * This should not have happened ideally. If this happens
4578 * there is some seriously wrong.
4579 */
4580 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4581 mmc_hostname(host->mmc), (u32) sps_cb_case);
4582 error = EIO;
4583 }
4584
4585 spin_lock_irqsave(&host->lock, flags);
4586
4587 mrq = host->curr.mrq;
4588
4589 if (mrq && mrq->cmd) {
4590 msmsdcc_dump_sdcc_state(host);
4591
4592 if (!mrq->cmd->error)
4593 mrq->cmd->error = -error;
4594 if (host->curr.data) {
4595 if (mrq->data && !mrq->data->error)
4596 mrq->data->error = -error;
4597 host->curr.data_xfered = 0;
4598 if (host->sps.sg && is_sps_mode(host)) {
4599 /* Stop current SPS transfer */
4600 msmsdcc_sps_exit_curr_xfer(host);
4601 } else {
4602 /* this condition should not have happened */
4603 pr_err("%s: something is seriously wrong. "\
4604 "Funtion: %s, line: %d\n",
4605 mmc_hostname(host->mmc),
4606 __func__, __LINE__);
4607 }
4608 } else {
4609 /* this condition should not have happened */
4610 pr_err("%s: something is seriously wrong. Funtion: "\
4611 "%s, line: %d\n", mmc_hostname(host->mmc),
4612 __func__, __LINE__);
4613 }
4614 }
4615 spin_unlock_irqrestore(&host->lock, flags);
4616}
4617
4618/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004619 * Initialize SPS HW connected with SDCC core
4620 *
4621 * This function register BAM HW resources with
4622 * SPS driver and then initialize 2 SPS endpoints
4623 *
4624 * This function should only be called once typically
4625 * during driver probe.
4626 *
4627 * @host - Pointer to sdcc host structure
4628 *
4629 * @return - 0 if successful else negative value.
4630 *
4631 */
4632static int msmsdcc_sps_init(struct msmsdcc_host *host)
4633{
4634 int rc = 0;
4635 struct sps_bam_props bam = {0};
4636
4637 host->bam_base = ioremap(host->bam_memres->start,
4638 resource_size(host->bam_memres));
4639 if (!host->bam_base) {
4640 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4641 " size=0x%x", mmc_hostname(host->mmc),
4642 host->bam_memres->start,
4643 (host->bam_memres->end -
4644 host->bam_memres->start));
4645 rc = -ENOMEM;
4646 goto out;
4647 }
4648
4649 bam.phys_addr = host->bam_memres->start;
4650 bam.virt_addr = host->bam_base;
4651 /*
4652 * This event thresold value is only significant for BAM-to-BAM
4653 * transfer. It's ignored for BAM-to-System mode transfer.
4654 */
4655 bam.event_threshold = 0x10; /* Pipe event threshold */
4656 /*
4657 * This threshold controls when the BAM publish
4658 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304659 * SPS HW will be used for data transfer size even
4660 * less than SDCC FIFO size. So let's set BAM summing
4661 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004662 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304663 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004664 /* SPS driver wll handle the SDCC BAM IRQ */
4665 bam.irq = (u32)host->bam_irqres->start;
4666 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004667 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4668 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004669
4670 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4671 (u32)bam.phys_addr);
4672 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4673 (u32)bam.virt_addr);
4674
4675 /* Register SDCC Peripheral BAM device to SPS driver */
4676 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4677 if (rc) {
4678 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4679 mmc_hostname(host->mmc), rc);
4680 goto reg_bam_err;
4681 }
4682 pr_info("%s: BAM device registered. bam_handle=0x%x",
4683 mmc_hostname(host->mmc), host->sps.bam_handle);
4684
4685 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4686 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4687
4688 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4689 SPS_PROD_PERIPHERAL);
4690 if (rc)
4691 goto sps_reset_err;
4692 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4693 SPS_CONS_PERIPHERAL);
4694 if (rc)
4695 goto cons_conn_err;
4696
4697 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4698 mmc_hostname(host->mmc),
4699 (unsigned long long)host->bam_memres->start,
4700 (unsigned int)host->bam_irqres->start);
4701 goto out;
4702
4703cons_conn_err:
4704 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4705sps_reset_err:
4706 sps_deregister_bam_device(host->sps.bam_handle);
4707reg_bam_err:
4708 iounmap(host->bam_base);
4709out:
4710 return rc;
4711}
4712
4713/**
4714 * De-initialize SPS HW connected with SDCC core
4715 *
4716 * This function deinitialize SPS endpoints and then
4717 * deregisters BAM resources from SPS driver.
4718 *
4719 * This function should only be called once typically
4720 * during driver remove.
4721 *
4722 * @host - Pointer to sdcc host structure
4723 *
4724 */
4725static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4726{
4727 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4728 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4729 sps_deregister_bam_device(host->sps.bam_handle);
4730 iounmap(host->bam_base);
4731}
4732#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4733
4734static ssize_t
4735show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4736{
4737 struct mmc_host *mmc = dev_get_drvdata(dev);
4738 struct msmsdcc_host *host = mmc_priv(mmc);
4739 int poll;
4740 unsigned long flags;
4741
4742 spin_lock_irqsave(&host->lock, flags);
4743 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4744 spin_unlock_irqrestore(&host->lock, flags);
4745
4746 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4747}
4748
4749static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304750store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 const char *buf, size_t count)
4752{
4753 struct mmc_host *mmc = dev_get_drvdata(dev);
4754 struct msmsdcc_host *host = mmc_priv(mmc);
4755 int value;
4756 unsigned long flags;
4757
4758 sscanf(buf, "%d", &value);
4759
4760 spin_lock_irqsave(&host->lock, flags);
4761 if (value) {
4762 mmc->caps |= MMC_CAP_NEEDS_POLL;
4763 mmc_detect_change(host->mmc, 0);
4764 } else {
4765 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4766 }
4767#ifdef CONFIG_HAS_EARLYSUSPEND
4768 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4769#endif
4770 spin_unlock_irqrestore(&host->lock, flags);
4771 return count;
4772}
4773
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304774static ssize_t
4775show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4776 char *buf)
4777{
4778 struct mmc_host *mmc = dev_get_drvdata(dev);
4779 struct msmsdcc_host *host = mmc_priv(mmc);
4780
4781 return snprintf(buf, PAGE_SIZE, "%u\n",
4782 host->msm_bus_vote.is_max_bw_needed);
4783}
4784
4785static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304786store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304787 const char *buf, size_t count)
4788{
4789 struct mmc_host *mmc = dev_get_drvdata(dev);
4790 struct msmsdcc_host *host = mmc_priv(mmc);
4791 uint32_t value;
4792 unsigned long flags;
4793
4794 if (!kstrtou32(buf, 0, &value)) {
4795 spin_lock_irqsave(&host->lock, flags);
4796 host->msm_bus_vote.is_max_bw_needed = !!value;
4797 spin_unlock_irqrestore(&host->lock, flags);
4798 }
4799
4800 return count;
4801}
4802
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304803static ssize_t
4804show_idle_timeout(struct device *dev, struct device_attribute *attr,
4805 char *buf)
4806{
4807 struct mmc_host *mmc = dev_get_drvdata(dev);
4808 struct msmsdcc_host *host = mmc_priv(mmc);
4809
4810 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4811 host->idle_tout_ms / 1000);
4812}
4813
4814static ssize_t
4815store_idle_timeout(struct device *dev, struct device_attribute *attr,
4816 const char *buf, size_t count)
4817{
4818 struct mmc_host *mmc = dev_get_drvdata(dev);
4819 struct msmsdcc_host *host = mmc_priv(mmc);
4820 unsigned int long flags;
4821 int timeout; /* in secs */
4822
4823 if (!kstrtou32(buf, 0, &timeout)
4824 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4825 spin_lock_irqsave(&host->lock, flags);
4826 host->idle_tout_ms = timeout * 1000;
4827 spin_unlock_irqrestore(&host->lock, flags);
4828 }
4829 return count;
4830}
4831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832#ifdef CONFIG_HAS_EARLYSUSPEND
4833static void msmsdcc_early_suspend(struct early_suspend *h)
4834{
4835 struct msmsdcc_host *host =
4836 container_of(h, struct msmsdcc_host, early_suspend);
4837 unsigned long flags;
4838
4839 spin_lock_irqsave(&host->lock, flags);
4840 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4841 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4842 spin_unlock_irqrestore(&host->lock, flags);
4843};
4844static void msmsdcc_late_resume(struct early_suspend *h)
4845{
4846 struct msmsdcc_host *host =
4847 container_of(h, struct msmsdcc_host, early_suspend);
4848 unsigned long flags;
4849
4850 if (host->polling_enabled) {
4851 spin_lock_irqsave(&host->lock, flags);
4852 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4853 mmc_detect_change(host->mmc, 0);
4854 spin_unlock_irqrestore(&host->lock, flags);
4855 }
4856};
4857#endif
4858
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304859static void msmsdcc_print_regs(const char *name, void __iomem *base,
4860 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304861{
4862 unsigned int i;
4863
4864 if (!base)
4865 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304866
4867 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4868 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304869 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304870 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4871 (u32)readl_relaxed(base + i*4),
4872 (u32)readl_relaxed(base + ((i+1)*4)),
4873 (u32)readl_relaxed(base + ((i+2)*4)),
4874 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304875 }
4876}
4877
4878static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4879{
4880 /* Dump current state of SDCC clocks, power and irq */
4881 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304882 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304883 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304884 mmc_hostname(host->mmc),
4885 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304886 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304887 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4888 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4889
4890 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304891 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304892 msmsdcc_print_regs("SDCC-CORE", host->base,
4893 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304894
4895 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304896 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304897 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304898 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304899 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4900 mmc_hostname(host->mmc), host->dma.busy,
4901 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304902 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304903 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304904 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4905 host->dml_memres->start,
4906 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304907 pr_info("%s: SPS mode: busy=%d\n",
4908 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304909 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304910
4911 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4912 mmc_hostname(host->mmc), host->curr.xfer_size,
4913 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304914 }
4915
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304916 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304917 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4918 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4919 host->curr.got_dataend, host->prog_enable,
4920 host->curr.wait_for_auto_prog_done,
4921 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304922 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304923}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004925static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4926{
4927 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4928 struct mmc_request *mrq;
4929 unsigned long flags;
4930
4931 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004932 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004933 pr_info("%s: %s: dummy CMD52 timeout\n",
4934 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004935 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936 }
4937
4938 mrq = host->curr.mrq;
4939
4940 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304941 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4942 mrq->cmd->opcode);
4943 msmsdcc_dump_sdcc_state(host);
4944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945 if (!mrq->cmd->error)
4946 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304947 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004948 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 if (mrq->data && !mrq->data->error)
4950 mrq->data->error = -ETIMEDOUT;
4951 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304952 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004953 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304954 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955 /* Stop current SPS transfer */
4956 msmsdcc_sps_exit_curr_xfer(host);
4957 } else {
4958 msmsdcc_reset_and_restore(host);
4959 msmsdcc_stop_data(host);
4960 if (mrq->data && mrq->data->stop)
4961 msmsdcc_start_command(host,
4962 mrq->data->stop, 0);
4963 else
4964 msmsdcc_request_end(host, mrq);
4965 }
4966 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304967 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304968 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004969 msmsdcc_reset_and_restore(host);
4970 msmsdcc_request_end(host, mrq);
4971 }
4972 }
4973 spin_unlock_irqrestore(&host->lock, flags);
4974}
4975
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304976/*
4977 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4978 *
4979 * @dev: device node from which the property value is to be read.
4980 * @prop_name: name of the property to be searched.
4981 * @out_array: filled array returned to caller
4982 * @len: filled array size returned to caller
4983 * @size: expected size of the array
4984 *
4985 * If expected "size" doesn't match with "len" an error is returned. If
4986 * expected size is zero, the length of actual array is returned provided
4987 * return value is zero.
4988 *
4989 * RETURNS:
4990 * zero on success, negative error if failed.
4991 */
4992static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4993 u32 **out_array, int *len, int size)
4994{
4995 int ret = 0;
4996 u32 *array = NULL;
4997 struct device_node *np = dev->of_node;
4998
4999 if (of_get_property(np, prop_name, len)) {
5000 size_t sz;
5001 sz = *len = *len / sizeof(*array);
5002
5003 if (sz > 0 && !(size > 0 && (sz != size))) {
5004 array = devm_kzalloc(dev, sz * sizeof(*array),
5005 GFP_KERNEL);
5006 if (!array) {
5007 dev_err(dev, "%s: no memory\n", prop_name);
5008 ret = -ENOMEM;
5009 goto out;
5010 }
5011
5012 ret = of_property_read_u32_array(np, prop_name,
5013 array, sz);
5014 if (ret < 0) {
5015 dev_err(dev, "%s: error reading array %d\n",
5016 prop_name, ret);
5017 goto out;
5018 }
5019 } else {
5020 dev_err(dev, "%s invalid size\n", prop_name);
5021 ret = -EINVAL;
5022 goto out;
5023 }
5024 } else {
5025 dev_err(dev, "%s not specified\n", prop_name);
5026 ret = -EINVAL;
5027 goto out;
5028 }
5029 *out_array = array;
5030out:
5031 if (ret)
5032 *len = 0;
5033 return ret;
5034}
5035
5036static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5037 struct msm_mmc_pad_pull_data **pad_pull_data)
5038{
5039 int ret = 0, base = 0, len, i;
5040 u32 *tmp;
5041 struct msm_mmc_pad_pull_data *pull_data;
5042 struct msm_mmc_pad_pull *pull;
5043
5044 switch (id) {
5045 case 1:
5046 base = TLMM_PULL_SDC1_CLK;
5047 break;
5048 case 2:
5049 base = TLMM_PULL_SDC2_CLK;
5050 break;
5051 case 3:
5052 base = TLMM_PULL_SDC3_CLK;
5053 break;
5054 case 4:
5055 base = TLMM_PULL_SDC4_CLK;
5056 break;
5057 default:
5058 dev_err(dev, "%s: Invalid slot id\n", __func__);
5059 ret = -EINVAL;
5060 goto err;
5061 }
5062
5063 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5064 GFP_KERNEL);
5065 if (!pull_data) {
5066 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5067 ret = -ENOMEM;
5068 goto err;
5069 }
5070 pull_data->size = 3; /* array size for clk, cmd, data */
5071
5072 /* Allocate on, off configs for clk, cmd, data */
5073 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5074 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5075 if (!pull) {
5076 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5077 ret = -ENOMEM;
5078 goto err;
5079 }
5080 pull_data->on = pull;
5081 pull_data->off = pull + pull_data->size;
5082
5083 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5084 &tmp, &len, pull_data->size);
5085 if (!ret) {
5086 for (i = 0; i < len; i++) {
5087 pull_data->on[i].no = base + i;
5088 pull_data->on[i].val = tmp[i];
5089 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5090 i, pull_data->on[i].val);
5091 }
5092 } else {
5093 goto err;
5094 }
5095
5096 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5097 &tmp, &len, pull_data->size);
5098 if (!ret) {
5099 for (i = 0; i < len; i++) {
5100 pull_data->off[i].no = base + i;
5101 pull_data->off[i].val = tmp[i];
5102 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5103 i, pull_data->off[i].val);
5104 }
5105 } else {
5106 goto err;
5107 }
5108
5109 *pad_pull_data = pull_data;
5110err:
5111 return ret;
5112}
5113
5114static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5115 struct msm_mmc_pad_drv_data **pad_drv_data)
5116{
5117 int ret = 0, base = 0, len, i;
5118 u32 *tmp;
5119 struct msm_mmc_pad_drv_data *drv_data;
5120 struct msm_mmc_pad_drv *drv;
5121
5122 switch (id) {
5123 case 1:
5124 base = TLMM_HDRV_SDC1_CLK;
5125 break;
5126 case 2:
5127 base = TLMM_HDRV_SDC2_CLK;
5128 break;
5129 case 3:
5130 base = TLMM_HDRV_SDC3_CLK;
5131 break;
5132 case 4:
5133 base = TLMM_HDRV_SDC4_CLK;
5134 break;
5135 default:
5136 dev_err(dev, "%s: Invalid slot id\n", __func__);
5137 ret = -EINVAL;
5138 goto err;
5139 }
5140
5141 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5142 GFP_KERNEL);
5143 if (!drv_data) {
5144 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5145 ret = -ENOMEM;
5146 goto err;
5147 }
5148 drv_data->size = 3; /* array size for clk, cmd, data */
5149
5150 /* Allocate on, off configs for clk, cmd, data */
5151 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5152 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5153 if (!drv) {
5154 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5155 ret = -ENOMEM;
5156 goto err;
5157 }
5158 drv_data->on = drv;
5159 drv_data->off = drv + drv_data->size;
5160
5161 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5162 &tmp, &len, drv_data->size);
5163 if (!ret) {
5164 for (i = 0; i < len; i++) {
5165 drv_data->on[i].no = base + i;
5166 drv_data->on[i].val = tmp[i];
5167 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5168 i, drv_data->on[i].val);
5169 }
5170 } else {
5171 goto err;
5172 }
5173
5174 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5175 &tmp, &len, drv_data->size);
5176 if (!ret) {
5177 for (i = 0; i < len; i++) {
5178 drv_data->off[i].no = base + i;
5179 drv_data->off[i].val = tmp[i];
5180 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5181 i, drv_data->off[i].val);
5182 }
5183 } else {
5184 goto err;
5185 }
5186
5187 *pad_drv_data = drv_data;
5188err:
5189 return ret;
5190}
5191
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305192static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5193 struct mmc_platform_data *pdata)
5194{
5195 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5196 struct device_node *np = dev->of_node;
5197
5198 pdata->status_gpio = of_get_named_gpio_flags(np,
5199 "cd-gpios", 0, &flags);
5200 if (gpio_is_valid(pdata->status_gpio)) {
5201 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5202 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5203 }
5204
5205 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5206 "wp-gpios", 0, &flags);
5207 if (gpio_is_valid(pdata->wpswitch_gpio))
5208 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5209}
5210
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305211static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5212 struct mmc_platform_data *pdata)
5213{
5214 int ret = 0, id = 0, cnt, i;
5215 struct msm_mmc_pin_data *pin_data;
5216 struct device_node *np = dev->of_node;
5217
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305218 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5219
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305220 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5221 if (!pin_data) {
5222 dev_err(dev, "No memory for pin_data\n");
5223 ret = -ENOMEM;
5224 goto err;
5225 }
5226
5227 cnt = of_gpio_count(np);
5228 if (cnt > 0) {
5229 pin_data->is_gpio = true;
5230
5231 pin_data->gpio_data = devm_kzalloc(dev,
5232 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5233 if (!pin_data->gpio_data) {
5234 dev_err(dev, "No memory for gpio_data\n");
5235 ret = -ENOMEM;
5236 goto err;
5237 }
5238 pin_data->gpio_data->size = cnt;
5239 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5240 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5241 if (!pin_data->gpio_data->gpio) {
5242 dev_err(dev, "No memory for gpio\n");
5243 ret = -ENOMEM;
5244 goto err;
5245 }
5246
5247 for (i = 0; i < cnt; i++) {
5248 const char *name = NULL;
5249 char result[32];
5250 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5251 of_property_read_string_index(np,
5252 "qcom,sdcc-gpio-names", i, &name);
5253
5254 snprintf(result, 32, "%s-%s",
5255 dev_name(dev), name ? name : "?");
5256 pin_data->gpio_data->gpio[i].name = result;
5257 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5258 pin_data->gpio_data->gpio[i].name,
5259 pin_data->gpio_data->gpio[i].no);
5260 }
5261 } else {
5262 pin_data->pad_data = devm_kzalloc(dev,
5263 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5264 if (!pin_data->pad_data) {
5265 dev_err(dev, "No memory for pin_data->pad_data\n");
5266 ret = -ENOMEM;
5267 goto err;
5268 }
5269
5270 of_property_read_u32(np, "cell-index", &id);
5271
5272 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5273 &pin_data->pad_data->pull);
5274 if (ret)
5275 goto err;
5276 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5277 &pin_data->pad_data->drv);
5278 if (ret)
5279 goto err;
5280 }
5281
5282 pdata->pin_data = pin_data;
5283err:
5284 if (ret)
5285 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5286 return ret;
5287}
5288
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305289#define MAX_PROP_SIZE 32
5290static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5291 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5292{
5293 int len, ret = 0;
5294 const __be32 *prop;
5295 char prop_name[MAX_PROP_SIZE];
5296 struct msm_mmc_reg_data *vreg;
5297 struct device_node *np = dev->of_node;
5298
5299 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5300 if (of_parse_phandle(np, prop_name, 0)) {
5301 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5302 if (!vreg) {
5303 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5304 ret = -ENOMEM;
5305 goto err;
5306 }
5307
5308 vreg->name = vreg_name;
5309
5310 snprintf(prop_name, MAX_PROP_SIZE,
5311 "qcom,sdcc-%s-always_on", vreg_name);
5312 if (of_get_property(np, prop_name, NULL))
5313 vreg->always_on = true;
5314
5315 snprintf(prop_name, MAX_PROP_SIZE,
5316 "qcom,sdcc-%s-lpm_sup", vreg_name);
5317 if (of_get_property(np, prop_name, NULL))
5318 vreg->lpm_sup = true;
5319
5320 snprintf(prop_name, MAX_PROP_SIZE,
5321 "qcom,sdcc-%s-voltage_level", vreg_name);
5322 prop = of_get_property(np, prop_name, &len);
5323 if (!prop || (len != (2 * sizeof(__be32)))) {
5324 dev_warn(dev, "%s %s property\n",
5325 prop ? "invalid format" : "no", prop_name);
5326 } else {
5327 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5328 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5329 }
5330
5331 snprintf(prop_name, MAX_PROP_SIZE,
5332 "qcom,sdcc-%s-current_level", vreg_name);
5333 prop = of_get_property(np, prop_name, &len);
5334 if (!prop || (len != (2 * sizeof(__be32)))) {
5335 dev_warn(dev, "%s %s property\n",
5336 prop ? "invalid format" : "no", prop_name);
5337 } else {
5338 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5339 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5340 }
5341
5342 *vreg_data = vreg;
5343 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5344 vreg->name, vreg->always_on ? "always_on," : "",
5345 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5346 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5347 }
5348
5349err:
5350 return ret;
5351}
5352
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305353static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5354{
5355 int i, ret;
5356 struct mmc_platform_data *pdata;
5357 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005358 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305359 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005360 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305361
5362 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5363 if (!pdata) {
5364 dev_err(dev, "could not allocate memory for platform data\n");
5365 goto err;
5366 }
5367
5368 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5369 if (bus_width == 8) {
5370 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5371 } else if (bus_width == 4) {
5372 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5373 } else {
5374 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5375 pdata->mmc_bus_width = 0;
5376 }
5377
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305378 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5379 &sup_voltages, &sup_volt_len, 0);
5380 if (!ret) {
5381 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305382 u32 mask;
5383
5384 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5385 sup_voltages[i + 1]);
5386 if (!mask)
5387 dev_err(dev, "Invalide voltage range %d\n", i);
5388 pdata->ocr_mask |= mask;
5389 }
5390 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305391 }
5392
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305393 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5394 &clk_table, &clk_table_len, 0);
5395 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305396 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305397 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305398 }
5399
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305400 pdata->vreg_data = devm_kzalloc(dev,
5401 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5402 if (!pdata->vreg_data) {
5403 dev_err(dev, "could not allocate memory for vreg_data\n");
5404 goto err;
5405 }
5406
5407 if (msmsdcc_dt_parse_vreg_info(dev,
5408 &pdata->vreg_data->vdd_data, "vdd"))
5409 goto err;
5410
5411 if (msmsdcc_dt_parse_vreg_info(dev,
5412 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5413 goto err;
5414
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305415 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5416 goto err;
5417
Devin Kim9ccbff52012-07-16 20:55:14 -07005418 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5419
5420 for (i = 0; i < len; i++) {
5421 const char *name = NULL;
5422
5423 of_property_read_string_index(np,
5424 "qcom,sdcc-bus-speed-mode", i, &name);
5425 if (!name)
5426 continue;
5427
5428 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5429 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5430 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5431 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5432 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5433 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5434 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5435 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5436 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5437 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5438 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5439 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5440 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5441 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5442 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5443 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5444 | MMC_CAP_UHS_DDR50;
5445 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5446 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5447 | MMC_CAP_UHS_DDR50;
5448 }
5449
5450 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5451 if (current_limit == 800)
5452 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5453 else if (current_limit == 600)
5454 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5455 else if (current_limit == 400)
5456 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5457 else if (current_limit == 200)
5458 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5459
5460 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5461 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305462 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5463 pdata->nonremovable = true;
5464 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5465 pdata->disable_cmd23 = true;
5466
5467 return pdata;
5468err:
5469 return NULL;
5470}
5471
San Mehat9d2bd732009-09-22 16:44:22 -07005472static int
5473msmsdcc_probe(struct platform_device *pdev)
5474{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305475 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005476 struct msmsdcc_host *host;
5477 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005478 unsigned long flags;
5479 struct resource *core_irqres = NULL;
5480 struct resource *bam_irqres = NULL;
5481 struct resource *core_memres = NULL;
5482 struct resource *dml_memres = NULL;
5483 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005484 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005485 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305486 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005487
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305488 if (pdev->dev.of_node) {
5489 plat = msmsdcc_populate_pdata(&pdev->dev);
5490 of_property_read_u32((&pdev->dev)->of_node,
5491 "cell-index", &pdev->id);
5492 } else {
5493 plat = pdev->dev.platform_data;
5494 }
San Mehat9d2bd732009-09-22 16:44:22 -07005495
5496 /* must have platform data */
5497 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005498 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005499 ret = -EINVAL;
5500 goto out;
5501 }
5502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005503 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005504 return -EINVAL;
5505
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305506 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5507 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5508 return -EINVAL;
5509 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005510
San Mehat9d2bd732009-09-22 16:44:22 -07005511 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005512 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005513 return -ENXIO;
5514 }
5515
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305516 core_memres = platform_get_resource_byname(pdev,
5517 IORESOURCE_MEM, "core_mem");
5518 bam_memres = platform_get_resource_byname(pdev,
5519 IORESOURCE_MEM, "bam_mem");
5520 dml_memres = platform_get_resource_byname(pdev,
5521 IORESOURCE_MEM, "dml_mem");
5522 core_irqres = platform_get_resource_byname(pdev,
5523 IORESOURCE_IRQ, "core_irq");
5524 bam_irqres = platform_get_resource_byname(pdev,
5525 IORESOURCE_IRQ, "bam_irq");
5526 dmares = platform_get_resource_byname(pdev,
5527 IORESOURCE_DMA, "dma_chnl");
5528 dma_crci_res = platform_get_resource_byname(pdev,
5529 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005531 if (!core_irqres || !core_memres) {
5532 pr_err("%s: Invalid sdcc core resource\n", __func__);
5533 return -ENXIO;
5534 }
5535
5536 /*
5537 * Both BAM and DML memory resource should be preset.
5538 * BAM IRQ resource should also be present.
5539 */
5540 if ((bam_memres && !dml_memres) ||
5541 (!bam_memres && dml_memres) ||
5542 ((bam_memres && dml_memres) && !bam_irqres)) {
5543 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005544 return -ENXIO;
5545 }
5546
5547 /*
5548 * Setup our host structure
5549 */
San Mehat9d2bd732009-09-22 16:44:22 -07005550 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5551 if (!mmc) {
5552 ret = -ENOMEM;
5553 goto out;
5554 }
5555
5556 host = mmc_priv(mmc);
5557 host->pdev_id = pdev->id;
5558 host->plat = plat;
5559 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005560 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305561
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305562 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305563 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005564 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305565 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005567 host->base = ioremap(core_memres->start,
5568 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005569 if (!host->base) {
5570 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305571 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005572 }
5573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005574 host->core_irqres = core_irqres;
5575 host->bam_irqres = bam_irqres;
5576 host->core_memres = core_memres;
5577 host->dml_memres = dml_memres;
5578 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005579 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005580 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005581 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305582 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005584#ifdef CONFIG_MMC_EMBEDDED_SDIO
5585 if (plat->embedded_sdio)
5586 mmc_set_embedded_sdio_data(mmc,
5587 &plat->embedded_sdio->cis,
5588 &plat->embedded_sdio->cccr,
5589 plat->embedded_sdio->funcs,
5590 plat->embedded_sdio->num_funcs);
5591#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005592
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305593 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5594 (unsigned long)host);
5595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005596 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5597 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305598 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005599 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305600 ret = msmsdcc_init_dma(host);
5601 if (ret)
5602 goto ioremap_free;
5603 } else {
5604 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005605 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305606 }
San Mehat9d2bd732009-09-22 16:44:22 -07005607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005608 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305609 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005610 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305611 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5612 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5613 /* Vote for max. clk rate for max. performance */
5614 ret = clk_set_rate(host->bus_clk, INT_MAX);
5615 if (ret)
5616 goto bus_clk_put;
5617 ret = clk_prepare_enable(host->bus_clk);
5618 if (ret)
5619 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005620 }
5621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005622 /*
5623 * Setup main peripheral bus clock
5624 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005625 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005626 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305627 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005628 if (ret)
5629 goto pclk_put;
5630
5631 host->pclk_rate = clk_get_rate(host->pclk);
5632 }
5633
5634 /*
5635 * Setup SDC MMC clock
5636 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005637 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005638 if (IS_ERR(host->clk)) {
5639 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005640 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005641 }
5642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005643 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305644 if (ret) {
5645 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5646 goto clk_put;
5647 }
5648
Asutosh Dasf5298c32012-04-03 14:51:47 +05305649 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005650 if (ret)
5651 goto clk_put;
5652
San Mehat9d2bd732009-09-22 16:44:22 -07005653 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305654 if (!host->clk_rate)
5655 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305656
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305657 set_default_hw_caps(host);
5658
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305659 /*
5660 * Set the register write delay according to min. clock frequency
5661 * supported and update later when the host->clk_rate changes.
5662 */
5663 host->reg_write_delay =
5664 (1 + ((3 * USEC_PER_SEC) /
5665 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005666
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305667 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305668 /* Apply Hard reset to SDCC to put it in power on default state */
5669 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005670
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005671#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305672 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005673 if (host->plat->cpu_dma_latency)
5674 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5675 else
5676 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5677 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305678 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5679
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305680 ret = msmsdcc_msm_bus_register(host);
5681 if (ret)
5682 goto pm_qos_remove;
5683
5684 if (host->msm_bus_vote.client_handle)
5685 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5686 msmsdcc_msm_bus_work);
5687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005688 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005689 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005690 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005691 goto clk_disable;
5692 }
5693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005694
5695 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305696 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005697 /* Initialize SPS */
5698 ret = msmsdcc_sps_init(host);
5699 if (ret)
5700 goto vreg_deinit;
5701 /* Initialize DML */
5702 ret = msmsdcc_dml_init(host);
5703 if (ret)
5704 goto sps_exit;
5705 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305706 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005707
San Mehat9d2bd732009-09-22 16:44:22 -07005708 /*
5709 * Setup MMC host structure
5710 */
5711 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005712 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5713 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005714 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305715 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005717 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5718 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005719 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305720 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305721 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305722 /*
5723 * If we send the CMD23 before multi block write/read command
5724 * then we need not to send CMD12 at the end of the transfer.
5725 * If we don't send the CMD12 then only way to detect the PROG_DONE
5726 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5727 * controller. So let's enable the CMD23 for SDCC4 only.
5728 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305729 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305730 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005732 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005733 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005734 /*
5735 * XPC controls the maximum current in the default speed mode of SDXC
5736 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5737 * XPC=1 means 150mA (max.) and speed class is supported.
5738 */
5739 if (plat->xpc_cap)
5740 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5741 MMC_CAP_SET_XPC_180);
5742
Devin Kim9b67ee02012-07-16 21:13:05 -07005743 /* packed write */
5744 mmc->caps2 |= plat->packed_write;
5745
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305746 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005747 mmc->caps2 |= MMC_CAP2_SANITIZE;
5748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005749 if (plat->nonremovable)
5750 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005751 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005752
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005753 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005755 if (plat->is_sdio_al_client)
5756 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005757
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305758 mmc->max_segs = msmsdcc_get_nr_sg(host);
5759 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5760 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005761
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305762 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005763 mmc->max_seg_size = mmc->max_req_size;
5764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005765 writel_relaxed(0, host->base + MMCIMASK0);
5766 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305767 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005769 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5770 mb();
5771 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005773 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5774 DRIVER_NAME " (cmd)", host);
5775 if (ret)
5776 goto dml_exit;
5777
5778 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5779 DRIVER_NAME " (pio)", host);
5780 if (ret)
5781 goto irq_free;
5782
5783 /*
5784 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5785 * IRQ is un-necessarily being monitored by MPM (Modem power
5786 * management block) during idle-power collapse. The MPM will be
5787 * configured to monitor the DATA1 GPIO line with level-low trigger
5788 * and thus depending on the GPIO status, it prevents TCXO shutdown
5789 * during idle-power collapse.
5790 */
5791 disable_irq(core_irqres->start);
5792 host->sdcc_irq_disabled = 1;
5793
5794 if (plat->sdiowakeup_irq) {
5795 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5796 mmc_hostname(mmc));
5797 ret = request_irq(plat->sdiowakeup_irq,
5798 msmsdcc_platform_sdiowakeup_irq,
5799 IRQF_SHARED | IRQF_TRIGGER_LOW,
5800 DRIVER_NAME "sdiowakeup", host);
5801 if (ret) {
5802 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5803 plat->sdiowakeup_irq, ret);
5804 goto pio_irq_free;
5805 } else {
5806 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305807 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005808 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305809 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005810 }
5811 spin_unlock_irqrestore(&host->lock, flags);
5812 }
5813 }
5814
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305815 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005816 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5817 mmc_hostname(mmc));
5818 }
5819
5820 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5821 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005822 /*
5823 * Setup card detect change
5824 */
5825
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305826 if (!plat->status_gpio)
5827 plat->status_gpio = -ENOENT;
5828 if (!plat->wpswitch_gpio)
5829 plat->wpswitch_gpio = -ENOENT;
5830
5831 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005832 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005833 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005834 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005835 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005836
Krishna Konda941604a2012-01-10 17:46:34 -08005837 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005838 }
San Mehat9d2bd732009-09-22 16:44:22 -07005839
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005840 if (plat->status_irq) {
5841 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005842 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005843 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005844 DRIVER_NAME " (slot)",
5845 host);
5846 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005847 pr_err("Unable to get slot IRQ %d (%d)\n",
5848 plat->status_irq, ret);
5849 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005850 }
5851 } else if (plat->register_status_notify) {
5852 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5853 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005854 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005855 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005856
5857 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005858
5859 ret = pm_runtime_set_active(&(pdev)->dev);
5860 if (ret < 0)
5861 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5862 __func__, ret);
5863 /*
5864 * There is no notion of suspend/resume for SD/MMC/SDIO
5865 * cards. So host can be suspended/resumed with out
5866 * worrying about its children.
5867 */
5868 pm_suspend_ignore_children(&(pdev)->dev, true);
5869
5870 /*
5871 * MMC/SD/SDIO bus suspend/resume operations are defined
5872 * only for the slots that will be used for non-removable
5873 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5874 * defined. Otherwise, they simply become card removal and
5875 * insertion events during suspend and resume respectively.
5876 * Hence, enable run-time PM only for slots for which bus
5877 * suspend/resume operations are defined.
5878 */
5879#ifdef CONFIG_MMC_UNSAFE_RESUME
5880 /*
5881 * If this capability is set, MMC core will enable/disable host
5882 * for every claim/release operation on a host. We use this
5883 * notification to increment/decrement runtime pm usage count.
5884 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005885 pm_runtime_enable(&(pdev)->dev);
5886#else
5887 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005888 pm_runtime_enable(&(pdev)->dev);
5889 }
5890#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305891 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005892 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5893 (unsigned long)host);
5894
San Mehat9d2bd732009-09-22 16:44:22 -07005895 mmc_add_host(mmc);
5896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005897#ifdef CONFIG_HAS_EARLYSUSPEND
5898 host->early_suspend.suspend = msmsdcc_early_suspend;
5899 host->early_suspend.resume = msmsdcc_late_resume;
5900 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5901 register_early_suspend(&host->early_suspend);
5902#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005903
Krishna Konda25786ec2011-07-25 16:21:36 -07005904 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5905 " dmacrcri %d\n", mmc_hostname(mmc),
5906 (unsigned long long)core_memres->start,
5907 (unsigned int) core_irqres->start,
5908 (unsigned int) plat->status_irq, host->dma.channel,
5909 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005910
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305911 pr_info("%s: Controller capabilities: 0x%.8x\n",
5912 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005913 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5914 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5915 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5916 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5917 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5918 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5919 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5920 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5921 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5922 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5923 host->eject);
5924 pr_info("%s: Power save feature enable = %d\n",
5925 mmc_hostname(mmc), msmsdcc_pwrsave);
5926
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305927 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005928 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005929 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005930 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005931 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005932 mmc_hostname(mmc), host->dma.cmd_busaddr,
5933 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305934 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005935 pr_info("%s: SPS-BAM data transfer mode available\n",
5936 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005937 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005938 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005940#if defined(CONFIG_DEBUG_FS)
5941 msmsdcc_dbg_createhost(host);
5942#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305943
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305944 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5945 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5946 sysfs_attr_init(&host->max_bus_bw.attr);
5947 host->max_bus_bw.attr.name = "max_bus_bw";
5948 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5949 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305950 if (ret)
5951 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305952
5953 if (!plat->status_irq) {
5954 host->polling.show = show_polling;
5955 host->polling.store = store_polling;
5956 sysfs_attr_init(&host->polling.attr);
5957 host->polling.attr.name = "polling";
5958 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5959 ret = device_create_file(&pdev->dev, &host->polling);
5960 if (ret)
5961 goto remove_max_bus_bw_file;
5962 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305963 host->idle_timeout.show = show_idle_timeout;
5964 host->idle_timeout.store = store_idle_timeout;
5965 sysfs_attr_init(&host->idle_timeout.attr);
5966 host->idle_timeout.attr.name = "idle_timeout";
5967 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5968 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5969 if (ret)
5970 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005971 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005972
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305973 remove_polling_file:
5974 if (!plat->status_irq)
5975 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305976 remove_max_bus_bw_file:
5977 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 platform_irq_free:
5979 del_timer_sync(&host->req_tout_timer);
5980 pm_runtime_disable(&(pdev)->dev);
5981 pm_runtime_set_suspended(&(pdev)->dev);
5982
5983 if (plat->status_irq)
5984 free_irq(plat->status_irq, host);
5985 sdiowakeup_irq_free:
5986 wake_lock_destroy(&host->sdio_suspend_wlock);
5987 if (plat->sdiowakeup_irq)
5988 free_irq(plat->sdiowakeup_irq, host);
5989 pio_irq_free:
5990 if (plat->sdiowakeup_irq)
5991 wake_lock_destroy(&host->sdio_wlock);
5992 free_irq(core_irqres->start, host);
5993 irq_free:
5994 free_irq(core_irqres->start, host);
5995 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305996 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005997 msmsdcc_dml_exit(host);
5998 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305999 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006000 msmsdcc_sps_exit(host);
6001 vreg_deinit:
6002 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006003 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006004 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306005 msmsdcc_msm_bus_unregister(host);
6006 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006007 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306008 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006009 clk_put:
6010 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006011 pclk_disable:
6012 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306013 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006014 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006015 if (!IS_ERR(host->pclk))
6016 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306017 if (!IS_ERR_OR_NULL(host->bus_clk))
6018 clk_disable_unprepare(host->bus_clk);
6019 bus_clk_put:
6020 if (!IS_ERR_OR_NULL(host->bus_clk))
6021 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306022 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006023 if (host->dmares)
6024 dma_free_coherent(NULL,
6025 sizeof(struct msmsdcc_nc_dmadata),
6026 host->dma.nc, host->dma.nc_busaddr);
6027 }
6028 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306029 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006030 host_free:
6031 mmc_free_host(mmc);
6032 out:
6033 return ret;
6034}
6035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006036static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006037{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006038 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6039 struct mmc_platform_data *plat;
6040 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006042 if (!mmc)
6043 return -ENXIO;
6044
6045 if (pm_runtime_suspended(&(pdev)->dev))
6046 pm_runtime_resume(&(pdev)->dev);
6047
6048 host = mmc_priv(mmc);
6049
6050 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6051 plat = host->plat;
6052
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306053 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006054 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306055 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306056 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006057
6058 del_timer_sync(&host->req_tout_timer);
6059 tasklet_kill(&host->dma_tlet);
6060 tasklet_kill(&host->sps.tlet);
6061 mmc_remove_host(mmc);
6062
6063 if (plat->status_irq)
6064 free_irq(plat->status_irq, host);
6065
6066 wake_lock_destroy(&host->sdio_suspend_wlock);
6067 if (plat->sdiowakeup_irq) {
6068 wake_lock_destroy(&host->sdio_wlock);
6069 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6070 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006071 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006072
6073 free_irq(host->core_irqres->start, host);
6074 free_irq(host->core_irqres->start, host);
6075
6076 clk_put(host->clk);
6077 if (!IS_ERR(host->pclk))
6078 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306079 if (!IS_ERR_OR_NULL(host->bus_clk))
6080 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006081
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006082 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306083 pm_qos_remove_request(&host->pm_qos_req_dma);
6084
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306085 if (host->msm_bus_vote.client_handle) {
6086 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6087 msmsdcc_msm_bus_unregister(host);
6088 }
6089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006090 msmsdcc_vreg_init(host, false);
6091
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306092 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006093 if (host->dmares)
6094 dma_free_coherent(NULL,
6095 sizeof(struct msmsdcc_nc_dmadata),
6096 host->dma.nc, host->dma.nc_busaddr);
6097 }
6098
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306099 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006100 msmsdcc_dml_exit(host);
6101 msmsdcc_sps_exit(host);
6102 }
6103
6104 iounmap(host->base);
6105 mmc_free_host(mmc);
6106
6107#ifdef CONFIG_HAS_EARLYSUSPEND
6108 unregister_early_suspend(&host->early_suspend);
6109#endif
6110 pm_runtime_disable(&(pdev)->dev);
6111 pm_runtime_set_suspended(&(pdev)->dev);
6112
6113 return 0;
6114}
6115
6116#ifdef CONFIG_MSM_SDIO_AL
6117int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6118{
6119 struct msmsdcc_host *host = mmc_priv(mmc);
6120 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306121 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006122
Asutosh Dasf5298c32012-04-03 14:51:47 +05306123 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006124 spin_lock_irqsave(&host->lock, flags);
6125 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6126 enable ? "En" : "Dis");
6127
6128 if (enable) {
6129 if (!host->sdcc_irq_disabled) {
6130 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306131 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006132 host->sdcc_irq_disabled = 1;
6133 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306134 rc = msmsdcc_setup_clocks(host, false);
6135 if (rc)
6136 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006137
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306138 if (host->plat->sdio_lpm_gpio_setup &&
6139 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 spin_unlock_irqrestore(&host->lock, flags);
6141 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6142 spin_lock_irqsave(&host->lock, flags);
6143 host->sdio_gpio_lpm = 1;
6144 }
6145
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306146 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006147 msmsdcc_enable_irq_wake(host);
6148 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306149 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006150 }
6151 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306152 rc = msmsdcc_setup_clocks(host, true);
6153 if (rc)
6154 goto out;
6155
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306156 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006157 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306158 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006159 msmsdcc_disable_irq_wake(host);
6160 }
6161
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306162 if (host->plat->sdio_lpm_gpio_setup &&
6163 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006164 spin_unlock_irqrestore(&host->lock, flags);
6165 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6166 spin_lock_irqsave(&host->lock, flags);
6167 host->sdio_gpio_lpm = 0;
6168 }
6169
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306170 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171 writel_relaxed(host->mci_irqenable,
6172 host->base + MMCIMASK0);
6173 mb();
6174 enable_irq(host->core_irqres->start);
6175 host->sdcc_irq_disabled = 0;
6176 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006177 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306178out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006179 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306180 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306181 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006182}
6183#else
6184int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6185{
6186 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006187}
6188#endif
6189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006190#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306191#ifdef CONFIG_MMC_CLKGATE
6192static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6193{
6194 struct mmc_host *mmc = host->mmc;
6195 unsigned long flags;
6196
6197 mmc_host_clk_hold(mmc);
6198 spin_lock_irqsave(&mmc->clk_lock, flags);
6199 mmc->clk_old = mmc->ios.clock;
6200 mmc->ios.clock = 0;
6201 mmc->clk_gated = true;
6202 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6203 mmc_set_ios(mmc);
6204 mmc_host_clk_release(mmc);
6205}
6206
6207static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6208{
6209 struct mmc_host *mmc = host->mmc;
6210
6211 mmc_host_clk_hold(mmc);
6212 mmc->ios.clock = host->clk_rate;
6213 mmc_set_ios(mmc);
6214 mmc_host_clk_release(mmc);
6215}
6216#else
6217static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6218{
6219 struct mmc_host *mmc = host->mmc;
6220
6221 mmc->ios.clock = 0;
6222 mmc_set_ios(mmc);
6223}
6224
6225static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6226{
6227 struct mmc_host *mmc = host->mmc;
6228
6229 mmc->ios.clock = host->clk_rate;
6230 mmc_set_ios(mmc);
6231}
6232#endif
6233
San Mehat9d2bd732009-09-22 16:44:22 -07006234static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006235msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006236{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006237 struct mmc_host *mmc = dev_get_drvdata(dev);
6238 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006239 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306240 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006241
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306242 if (host->plat->is_sdio_al_client) {
6243 rc = 0;
6244 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006245 }
San Mehat9d2bd732009-09-22 16:44:22 -07006246
Sahitya Tummala7661a452011-07-18 13:28:35 +05306247 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006248 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006249 host->sdcc_suspending = 1;
6250 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006252 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006253 * MMC core thinks that host is disabled by now since
6254 * runtime suspend is scheduled after msmsdcc_disable()
6255 * is called. Thus, MMC core will try to enable the host
6256 * while suspending it. This results in a synchronous
6257 * runtime resume request while in runtime suspending
6258 * context and hence inorder to complete this resume
6259 * requet, it will wait for suspend to be complete,
6260 * but runtime suspend also can not proceed further
6261 * until the host is resumed. Thus, it leads to a hang.
6262 * Hence, increase the pm usage count before suspending
6263 * the host so that any resume requests after this will
6264 * simple become pm usage counter increment operations.
6265 */
6266 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306267 /* If there is pending detect work abort runtime suspend */
6268 if (unlikely(work_busy(&mmc->detect.work)))
6269 rc = -EAGAIN;
6270 else
6271 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006272 pm_runtime_put_noidle(dev);
6273
6274 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306275 spin_lock_irqsave(&host->lock, flags);
6276 host->sdcc_suspended = true;
6277 spin_unlock_irqrestore(&host->lock, flags);
6278 if (mmc->card && mmc_card_sdio(mmc->card) &&
6279 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006280 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306281 * If SDIO function driver doesn't want
6282 * to power off the card, atleast turn off
6283 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006284 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306285 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006286 }
6287 }
6288 host->sdcc_suspending = 0;
6289 mmc->suspend_task = NULL;
6290 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6291 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006292 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306293 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306294out:
6295 /* set bus bandwidth to 0 immediately */
6296 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006297 return rc;
6298}
6299
6300static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006301msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006302{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006303 struct mmc_host *mmc = dev_get_drvdata(dev);
6304 struct msmsdcc_host *host = mmc_priv(mmc);
6305 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006307 if (host->plat->is_sdio_al_client)
6308 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006309
Sahitya Tummala7661a452011-07-18 13:28:35 +05306310 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006311 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306312 if (mmc->card && mmc_card_sdio(mmc->card) &&
6313 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306314 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306315 }
San Mehat9d2bd732009-09-22 16:44:22 -07006316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006317 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006319 /*
6320 * FIXME: Clearing of flags must be handled in clients
6321 * resume handler.
6322 */
6323 spin_lock_irqsave(&host->lock, flags);
6324 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306325 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006326 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006328 /*
6329 * After resuming the host wait for sometime so that
6330 * the SDIO work will be processed.
6331 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306332 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306333 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006334 host->plat->sdiowakeup_irq) &&
6335 wake_lock_active(&host->sdio_wlock))
6336 wake_lock_timeout(&host->sdio_wlock, 1);
6337 }
6338
6339 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006340 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306341 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306342 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006343 return 0;
6344}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006345
6346static int msmsdcc_runtime_idle(struct device *dev)
6347{
6348 struct mmc_host *mmc = dev_get_drvdata(dev);
6349 struct msmsdcc_host *host = mmc_priv(mmc);
6350
6351 if (host->plat->is_sdio_al_client)
6352 return 0;
6353
6354 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306355 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006356
6357 return -EAGAIN;
6358}
6359
6360static int msmsdcc_pm_suspend(struct device *dev)
6361{
6362 struct mmc_host *mmc = dev_get_drvdata(dev);
6363 struct msmsdcc_host *host = mmc_priv(mmc);
6364 int rc = 0;
6365
6366 if (host->plat->is_sdio_al_client)
6367 return 0;
6368
6369
6370 if (host->plat->status_irq)
6371 disable_irq(host->plat->status_irq);
6372
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006373 if (!pm_runtime_suspended(dev))
6374 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006375
6376 return rc;
6377}
6378
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306379static int msmsdcc_suspend_noirq(struct device *dev)
6380{
6381 struct mmc_host *mmc = dev_get_drvdata(dev);
6382 struct msmsdcc_host *host = mmc_priv(mmc);
6383 int rc = 0;
6384
6385 /*
6386 * After platform suspend there may be active request
6387 * which might have enabled clocks. For example, in SDIO
6388 * case, ksdioirq thread might have scheduled after sdcc
6389 * suspend but before system freeze. In that case abort
6390 * suspend and retry instead of keeping the clocks on
6391 * during suspend and not allowing TCXO.
6392 */
6393
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306394 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306395 pr_warn("%s: clocks are on after suspend, aborting system "
6396 "suspend\n", mmc_hostname(mmc));
6397 rc = -EAGAIN;
6398 }
6399
6400 return rc;
6401}
6402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006403static int msmsdcc_pm_resume(struct device *dev)
6404{
6405 struct mmc_host *mmc = dev_get_drvdata(dev);
6406 struct msmsdcc_host *host = mmc_priv(mmc);
6407 int rc = 0;
6408
6409 if (host->plat->is_sdio_al_client)
6410 return 0;
6411
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006412 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306413 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306414 /*
6415 * As runtime PM is enabled before calling the device's platform resume
6416 * callback, we use the pm_runtime_suspended API to know if SDCC is
6417 * really runtime suspended or not and set the pending_resume flag only
6418 * if its not runtime suspended.
6419 */
6420 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006421 host->pending_resume = true;
6422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006423 if (host->plat->status_irq) {
6424 msmsdcc_check_status((unsigned long)host);
6425 enable_irq(host->plat->status_irq);
6426 }
6427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006428 return rc;
6429}
6430
Daniel Walker08ecfde2010-06-23 12:32:20 -07006431#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006432static int msmsdcc_runtime_suspend(struct device *dev)
6433{
6434 return 0;
6435}
6436static int msmsdcc_runtime_idle(struct device *dev)
6437{
6438 return 0;
6439}
6440static int msmsdcc_pm_suspend(struct device *dev)
6441{
6442 return 0;
6443}
6444static int msmsdcc_pm_resume(struct device *dev)
6445{
6446 return 0;
6447}
6448static int msmsdcc_suspend_noirq(struct device *dev)
6449{
6450 return 0;
6451}
6452static int msmsdcc_runtime_resume(struct device *dev)
6453{
6454 return 0;
6455}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006456#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006458static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6459 .runtime_suspend = msmsdcc_runtime_suspend,
6460 .runtime_resume = msmsdcc_runtime_resume,
6461 .runtime_idle = msmsdcc_runtime_idle,
6462 .suspend = msmsdcc_pm_suspend,
6463 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306464 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006465};
6466
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306467static const struct of_device_id msmsdcc_dt_match[] = {
6468 {.compatible = "qcom,msm-sdcc"},
6469
6470};
6471MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6472
San Mehat9d2bd732009-09-22 16:44:22 -07006473static struct platform_driver msmsdcc_driver = {
6474 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006475 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006476 .driver = {
6477 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006478 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306479 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006480 },
6481};
6482
6483static int __init msmsdcc_init(void)
6484{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006485#if defined(CONFIG_DEBUG_FS)
6486 int ret = 0;
6487 ret = msmsdcc_dbg_init();
6488 if (ret) {
6489 pr_err("Failed to create debug fs dir \n");
6490 return ret;
6491 }
6492#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006493 return platform_driver_register(&msmsdcc_driver);
6494}
San Mehat9d2bd732009-09-22 16:44:22 -07006495
San Mehat9d2bd732009-09-22 16:44:22 -07006496static void __exit msmsdcc_exit(void)
6497{
6498 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006499
6500#if defined(CONFIG_DEBUG_FS)
6501 debugfs_remove(debugfs_file);
6502 debugfs_remove(debugfs_dir);
6503#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006504}
6505
6506module_init(msmsdcc_init);
6507module_exit(msmsdcc_exit);
6508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006509MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006510MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006511
6512#if defined(CONFIG_DEBUG_FS)
6513
6514static int
6515msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6516{
6517 file->private_data = inode->i_private;
6518 return 0;
6519}
6520
6521static ssize_t
6522msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6523 size_t count, loff_t *ppos)
6524{
6525 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006526 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006527 int max, i;
6528
6529 i = 0;
6530 max = sizeof(buf) - 1;
6531
6532 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6533 host->curr.cmd, host->curr.data);
6534 if (host->curr.cmd) {
6535 struct mmc_command *cmd = host->curr.cmd;
6536
6537 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6538 cmd->opcode, cmd->arg, cmd->flags);
6539 }
6540 if (host->curr.data) {
6541 struct mmc_data *data = host->curr.data;
6542 i += scnprintf(buf + i, max - i,
6543 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6544 data->timeout_ns, data->timeout_clks,
6545 data->blksz, data->blocks, data->error,
6546 data->flags);
6547 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6548 host->curr.xfer_size, host->curr.xfer_remain,
6549 host->curr.data_xfered, host->dma.sg);
6550 }
6551
6552 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6553}
6554
6555static const struct file_operations msmsdcc_dbg_state_ops = {
6556 .read = msmsdcc_dbg_state_read,
6557 .open = msmsdcc_dbg_state_open,
6558};
6559
6560static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6561{
6562 if (debugfs_dir) {
6563 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6564 0644, debugfs_dir, host,
6565 &msmsdcc_dbg_state_ops);
6566 }
6567}
6568
6569static int __init msmsdcc_dbg_init(void)
6570{
6571 int err;
6572
6573 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6574 if (IS_ERR(debugfs_dir)) {
6575 err = PTR_ERR(debugfs_dir);
6576 debugfs_dir = NULL;
6577 return err;
6578 }
6579
6580 return 0;
6581}
6582#endif