blob: 8bac4ef0db17cc99894496c1a308bbd396e4e6d7 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
Sujit Reddy Thumma38459152012-06-26 00:07:59 +053023#include <linux/of_gpio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070024#include <linux/device.h>
25#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070027#include <linux/delay.h>
28#include <linux/err.h>
29#include <linux/highmem.h>
30#include <linux/log2.h>
31#include <linux/mmc/host.h>
32#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080034#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070035#include <linux/clk.h>
36#include <linux/scatterlist.h>
37#include <linux/platform_device.h>
38#include <linux/dma-mapping.h>
39#include <linux/debugfs.h>
40#include <linux/io.h>
41#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <linux/pm_runtime.h>
43#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053044#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045#include <linux/regulator/consumer.h>
46#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070047#include <linux/pm_qos.h>
San Mehat9d2bd732009-09-22 16:44:22 -070048
49#include <asm/cacheflush.h>
50#include <asm/div64.h>
51#include <asm/sizes.h>
52
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070054#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053055#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053058#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053059#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070060
San Mehat9d2bd732009-09-22 16:44:22 -070061#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070063
64#define DRIVER_NAME "msm-sdcc"
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066#define DBG(host, fmt, args...) \
67 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
68
69#define IRQ_DEBUG 0
70#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
71#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
72#define SPS_CONS_PERIPHERAL 0
73#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053074/* Use SPS only if transfer size is more than this macro */
75#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053077#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
78
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079#if defined(CONFIG_DEBUG_FS)
80static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
81static struct dentry *debugfs_dir;
82static struct dentry *debugfs_file;
83static int msmsdcc_dbg_init(void);
84#endif
85
Asutosh Dasaccacd42012-03-08 14:33:17 +053086static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
87 *data);
88
Subhash Jadavani8766e352011-11-30 11:30:32 +053089static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070090static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092static struct mmc_command dummy52cmd;
93static struct mmc_request dummy52mrq = {
94 .cmd = &dummy52cmd,
95 .data = NULL,
96 .stop = NULL,
97};
98static struct mmc_command dummy52cmd = {
99 .opcode = SD_IO_RW_DIRECT,
100 .flags = MMC_RSP_PRESENT,
101 .data = NULL,
102 .mrq = &dummy52mrq,
103};
104/*
105 * An array holding the Tuning pattern to compare with when
106 * executing a tuning cycle.
107 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530108static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
110 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
111 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
112 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
113};
San Mehat9d2bd732009-09-22 16:44:22 -0700114
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530115static const u32 tuning_block_128[] = {
116 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
117 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
118 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
119 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
120 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
121 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
122 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
123 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
124};
San Mehat865c8062009-11-13 13:42:06 -0800125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126#if IRQ_DEBUG == 1
127static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
128 "dattimeout", "txunderrun", "rxoverrun",
129 "cmdrespend", "cmdsent", "dataend", NULL,
130 "datablkend", "cmdactive", "txactive",
131 "rxactive", "txhalfempty", "rxhalffull",
132 "txfifofull", "rxfifofull", "txfifoempty",
133 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
134 "sdiointr", "progdone", "atacmdcompl",
135 "sdiointrope", "ccstimeout", NULL, NULL,
136 NULL, NULL, NULL };
137
138static void
139msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800140{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
144 for (i = 0; i < 32; i++) {
145 if (status & (1 << i))
146 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800149}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150#endif
San Mehat865c8062009-11-13 13:42:06 -0800151
San Mehat9d2bd732009-09-22 16:44:22 -0700152static void
153msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
154 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530155static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530156static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530157static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800158static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800159static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700160static int msmsdcc_runtime_resume(struct device *dev);
San Mehat9d2bd732009-09-22 16:44:22 -0700161
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530162static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530163{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530164 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530165
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530166 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530167 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530168 } else { /* DMA or PIO mode */
169 if (NR_SG > MAX_NR_SG_DMA_PIO)
170 ret = MAX_NR_SG_DMA_PIO;
171 }
172
173 return ret;
174}
175
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530176/* Prevent idle power collapse(pc) while operating in peripheral mode */
177static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
178{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700179 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530180 return;
181
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530182 if (vote)
183 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700184 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530185 else
186 pm_qos_update_request(&host->pm_qos_req_dma,
187 PM_QOS_DEFAULT_VALUE);
188}
189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
191static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
192 struct msmsdcc_sps_ep_conn_data *ep);
193static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
194 struct msmsdcc_sps_ep_conn_data *ep);
195#else
196static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
197 struct msmsdcc_sps_ep_conn_data *ep,
198 bool is_producer) { return 0; }
199static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep) { }
201static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
202 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530203{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 return 0;
205}
206static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
207 struct msmsdcc_sps_ep_conn_data *ep)
208{
209 return 0;
210}
211static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
212static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
213#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530216 * Apply soft reset to all SDCC BAM pipes
217 *
218 * This function applies soft reset to SDCC BAM pipe.
219 *
220 * This function should be called to recover from error
221 * conditions encountered during CMD/DATA tranfsers with card.
222 *
223 * @host - Pointer to driver's host structure
224 *
225 */
226static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
227{
228 int rc;
229
230 /* Reset all SDCC BAM pipes */
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
236 if (rc)
237 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
238 mmc_hostname(host->mmc), rc);
239
Krishna Konda5af8f972012-05-14 16:15:24 -0700240 if (host->sps.reset_device) {
241 rc = sps_device_reset(host->sps.bam_handle);
242 if (rc)
243 pr_err("%s: sps_device_reset error=%d\n",
244 mmc_hostname(host->mmc), rc);
245 host->sps.reset_device = false;
246 }
247
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530248 /* Restore all BAM pipes connections */
249 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
250 if (rc)
251 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
252 mmc_hostname(host->mmc), rc);
253 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
254 if (rc)
255 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
256 mmc_hostname(host->mmc), rc);
257}
258
259/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 * Apply soft reset
261 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530262 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 *
264 * This function should be called to recover from error
265 * conditions encountered with CMD/DATA tranfsers with card.
266 *
267 * Soft reset should only be used with SDCC controller v4.
268 *
269 * @host - Pointer to driver's host structure
270 *
271 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530275 * Reset controller state machines without resetting
276 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530278 if (is_sw_reset_save_config(host)) {
279 ktime_t start;
280
281 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
282 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
283 msmsdcc_sync_reg_wr(host);
284
285 start = ktime_get();
286 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
287 /*
288 * SW reset can take upto 10HCLK + 15MCLK cycles.
289 * Calculating based on min clk rates (hclk = 27MHz,
290 * mclk = 400KHz) it comes to ~40us. Let's poll for
291 * max. 1ms for reset completion.
292 */
293 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
294 pr_err("%s: %s failed\n",
295 mmc_hostname(host->mmc), __func__);
296 BUG();
297 }
298 }
299 } else {
300 writel_relaxed(0, host->base + MMCICOMMAND);
301 msmsdcc_sync_reg_wr(host);
302 writel_relaxed(0, host->base + MMCIDATACTRL);
303 msmsdcc_sync_reg_wr(host);
304 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530305}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530306
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530307static void msmsdcc_hard_reset(struct msmsdcc_host *host)
308{
309 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530310
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530311 /*
312 * Reset SDCC controller to power on default state.
313 * Don't issue a reset request to clock control block if
314 * SDCC controller itself can support hard reset.
315 */
316 if (is_sw_hard_reset(host)) {
317 ktime_t start;
318
319 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
320 | MCI_SW_RST, host->base + MMCIPOWER);
321 msmsdcc_sync_reg_wr(host);
322
323 start = ktime_get();
324 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
325 /*
326 * See comment in msmsdcc_soft_reset() on choosing 1ms
327 * poll timeout.
328 */
329 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
330 pr_err("%s: %s failed\n",
331 mmc_hostname(host->mmc), __func__);
332 BUG();
333 }
334 }
335 } else {
336 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
337 if (ret)
338 pr_err("%s: Clock assert failed at %u Hz" \
339 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530340 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530341
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530342 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
343 if (ret)
344 pr_err("%s: Clock deassert failed at %u Hz" \
345 " with err %d\n", mmc_hostname(host->mmc),
346 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530347
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530348 mb();
349 /* Give some delay for clock reset to propogate to controller */
350 msmsdcc_delay(host);
351 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530352}
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
355{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530356 if (is_soft_reset(host)) {
357 if (is_sps_mode(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530358 /* Reset DML first */
359 msmsdcc_dml_reset(host);
360 /*
361 * delay the SPS pipe reset in thread context as
362 * sps_connect/sps_disconnect APIs can be called
363 * only from non-atomic context.
364 */
365 host->sps.pipe_reset_pending = true;
366 }
367 mb();
368 msmsdcc_soft_reset(host);
369
370 pr_debug("%s: Applied soft reset to Controller\n",
371 mmc_hostname(host->mmc));
372
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530373 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530374 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 } else {
376 /* Give Clock reset (hard reset) to controller */
377 u32 mci_clk = 0;
378 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379
380 /* Save the controller state */
381 mci_clk = readl_relaxed(host->base + MMCICLOCK);
382 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530383 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530386 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 pr_debug("%s: Controller has been reinitialized\n",
388 mmc_hostname(host->mmc));
389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 /* Restore the contoller state */
391 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530392 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530396 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530398
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700399 if (host->dummy_52_needed)
400 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401}
402
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530403static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
404{
405 struct mmc_request *mrq = host->curr.mrq;
406
407 if (!mrq || !mrq->cmd || (!mrq->data && !host->pending_dpsm_reset))
408 goto out;
409
410 /*
411 * For CMD24, if auto prog done is not supported defer
412 * dpsm reset until prog done is received. Otherwise,
413 * we poll here unnecessarily as TXACTIVE will not be
414 * deasserted until DAT0 goes high.
415 */
416 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) && !is_auto_prog_done(host)) {
417 host->pending_dpsm_reset = true;
418 goto out;
419 }
420
421 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
422 if (is_wait_for_tx_rx_active(host)) {
423 ktime_t start = ktime_get();
424
425 while (readl_relaxed(host->base + MMCISTATUS) &
426 (MCI_TXACTIVE | MCI_RXACTIVE)) {
427 /*
428 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
429 * cycles (~11us) after data transfer due to clock mux
430 * switching delays. Let's poll for 1ms and panic if
431 * still active.
432 */
433 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
434 pr_err("%s: %s still active\n",
435 mmc_hostname(host->mmc),
436 readl_relaxed(host->base + MMCISTATUS)
437 & MCI_TXACTIVE ? "TX" : "RX");
438 msmsdcc_dump_sdcc_state(host);
439 BUG();
440 }
441 }
442 }
443
444 writel_relaxed(0, host->base + MMCIDATACTRL);
445 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
446 host->pending_dpsm_reset = false;
447out:
448 return;
449}
450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451static int
San Mehat9d2bd732009-09-22 16:44:22 -0700452msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
453{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 int retval = 0;
455
San Mehat9d2bd732009-09-22 16:44:22 -0700456 BUG_ON(host->curr.data);
457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700459
460 if (mrq->data)
461 mrq->data->bytes_xfered = host->curr.data_xfered;
462 if (mrq->cmd->error == -ETIMEDOUT)
463 mdelay(5);
464
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530465 msmsdcc_reset_dpsm(host);
466
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530467 /* Clear current request information as current request has ended */
468 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
469
San Mehat9d2bd732009-09-22 16:44:22 -0700470 /*
471 * Need to drop the host lock here; mmc_request_done may call
472 * back into the driver...
473 */
474 spin_unlock(&host->lock);
475 mmc_request_done(host->mmc, mrq);
476 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477
478 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700479}
480
481static void
482msmsdcc_stop_data(struct msmsdcc_host *host)
483{
San Mehat9d2bd732009-09-22 16:44:22 -0700484 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530485 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530486 host->curr.wait_for_auto_prog_done = false;
487 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700488}
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700491{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 return host->core_memres->start + MMCIFIFO;
493}
494
495static inline unsigned int msmsdcc_get_min_sup_clk_rate(
496 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530497
Subhash Jadavanidd432952012-03-28 11:25:56 +0530498static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499{
500 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530501 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530502 udelay(host->reg_write_delay);
503 else if (readl_relaxed(host->base + MCI_STATUS2) &
504 MCI_MCLK_REG_WR_ACTIVE) {
505 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530506
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530507 start = ktime_get();
508 while (readl_relaxed(host->base + MCI_STATUS2) &
509 MCI_MCLK_REG_WR_ACTIVE) {
510 diff = ktime_sub(ktime_get(), start);
511 /* poll for max. 1 ms */
512 if (ktime_to_us(diff) > 1000) {
513 pr_warning("%s: previous reg. write is"
514 " still active\n",
515 mmc_hostname(host->mmc));
516 break;
517 }
518 }
519 }
San Mehat9d2bd732009-09-22 16:44:22 -0700520}
521
Subhash Jadavanidd432952012-03-28 11:25:56 +0530522static inline void msmsdcc_delay(struct msmsdcc_host *host)
523{
524 udelay(host->reg_write_delay);
525
San Mehat9d2bd732009-09-22 16:44:22 -0700526}
527
San Mehat56a8b5b2009-11-21 12:29:46 -0800528static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
530{
531 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530533 /*
534 * As after sending the command, we don't write any of the
535 * controller registers and just wait for the
536 * CMD_RESPOND_END/CMD_SENT/Command failure notication
537 * from Controller.
538 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800540}
541
542static void
543msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
544{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
548 writel_relaxed((unsigned int)host->curr.xfer_size,
549 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530551 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800552
San Mehat6ac9ea62009-12-02 17:24:58 -0800553 if (host->cmd_cmd) {
554 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800556 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800557}
558
San Mehat9d2bd732009-09-22 16:44:22 -0700559static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530560msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700561{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530562 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700563 unsigned long flags;
564 struct mmc_request *mrq;
565
566 spin_lock_irqsave(&host->lock, flags);
567 mrq = host->curr.mrq;
568 BUG_ON(!mrq);
569
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530570 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700571 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700572 goto out;
573 }
574
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530575 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700576 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700578 } else {
579 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530580 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700581 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530582 mmc_hostname(host->mmc), host->dma.result);
583 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700584 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530585 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530586 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 host->dma.err.flush[0], host->dma.err.flush[1],
588 host->dma.err.flush[2], host->dma.err.flush[3],
589 host->dma.err.flush[4],
590 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530591 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700592 if (!mrq->data->error)
593 mrq->data->error = -EIO;
594 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530595 if (!mrq->data->host_cookie)
596 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
597 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 if (host->curr.user_pages) {
600 struct scatterlist *sg = host->dma.sg;
601 int i;
602
603 for (i = 0; i < host->dma.num_ents; i++, sg++)
604 flush_dcache_page(sg_page(sg));
605 }
San Mehat9d2bd732009-09-22 16:44:22 -0700606
San Mehat9d2bd732009-09-22 16:44:22 -0700607 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800608 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700609
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530610 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
611 (host->curr.wait_for_auto_prog_done &&
612 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700613 /*
614 * If we've already gotten our DATAEND / DATABLKEND
615 * for this request, then complete it through here.
616 */
San Mehat9d2bd732009-09-22 16:44:22 -0700617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700619 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 host->curr.xfer_remain -= host->curr.xfer_size;
621 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700622 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700623 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700624 host->dummy_52_sent = 1;
625 msmsdcc_start_command(host, &dummy52cmd,
626 MCI_CPSM_PROGENA);
627 goto out;
628 }
629 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530630 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530631 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700632 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530633 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530635 /*
636 * Clear current request information as current
637 * request has ended
638 */
639 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700640 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641
San Mehat9d2bd732009-09-22 16:44:22 -0700642 mmc_request_done(host->mmc, mrq);
643 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530644 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
645 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700646 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530647 }
San Mehat9d2bd732009-09-22 16:44:22 -0700648 }
649
650out:
651 spin_unlock_irqrestore(&host->lock, flags);
652 return;
653}
654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
656/**
657 * Callback notification from SPS driver
658 *
659 * This callback function gets triggered called from
660 * SPS driver when requested SPS data transfer is
661 * completed.
662 *
663 * SPS driver invokes this callback in BAM irq context so
664 * SDCC driver schedule a tasklet for further processing
665 * this callback notification at later point of time in
666 * tasklet context and immediately returns control back
667 * to SPS driver.
668 *
669 * @nofity - Pointer to sps event notify sturcture
670 *
671 */
672static void
673msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
674{
675 struct msmsdcc_host *host =
676 (struct msmsdcc_host *)
677 ((struct sps_event_notify *)notify)->user;
678
679 host->sps.notify = *notify;
680 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
681 mmc_hostname(host->mmc), __func__, notify->event_id,
682 notify->data.transfer.iovec.addr,
683 notify->data.transfer.iovec.size,
684 notify->data.transfer.iovec.flags);
685 /* Schedule a tasklet for completing data transfer */
686 tasklet_schedule(&host->sps.tlet);
687}
688
689/**
690 * Tasklet handler for processing SPS callback event
691 *
692 * This function processing SPS event notification and
693 * checks if the SPS transfer is completed or not and
694 * then accordingly notifies status to MMC core layer.
695 *
696 * This function is called in tasklet context.
697 *
698 * @data - Pointer to sdcc driver data
699 *
700 */
701static void msmsdcc_sps_complete_tlet(unsigned long data)
702{
703 unsigned long flags;
704 int i, rc;
705 u32 data_xfered = 0;
706 struct mmc_request *mrq;
707 struct sps_iovec iovec;
708 struct sps_pipe *sps_pipe_handle;
709 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
710 struct sps_event_notify *notify = &host->sps.notify;
711
712 spin_lock_irqsave(&host->lock, flags);
713 if (host->sps.dir == DMA_FROM_DEVICE)
714 sps_pipe_handle = host->sps.prod.pipe_handle;
715 else
716 sps_pipe_handle = host->sps.cons.pipe_handle;
717 mrq = host->curr.mrq;
718
719 if (!mrq) {
720 spin_unlock_irqrestore(&host->lock, flags);
721 return;
722 }
723
724 pr_debug("%s: %s: sps event_id=%d\n",
725 mmc_hostname(host->mmc), __func__,
726 notify->event_id);
727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 /*
729 * Got End of transfer event!!! Check if all of the data
730 * has been transferred?
731 */
732 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
733 rc = sps_get_iovec(sps_pipe_handle, &iovec);
734 if (rc) {
735 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
736 mmc_hostname(host->mmc), __func__, rc, i);
737 break;
738 }
739 data_xfered += iovec.size;
740 }
741
742 if (data_xfered == host->curr.xfer_size) {
743 host->curr.data_xfered = host->curr.xfer_size;
744 host->curr.xfer_remain -= host->curr.xfer_size;
745 pr_debug("%s: Data xfer success. data_xfered=0x%x",
746 mmc_hostname(host->mmc),
747 host->curr.xfer_size);
748 } else {
749 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
750 " xfer_size=%d", mmc_hostname(host->mmc),
751 data_xfered, host->curr.xfer_size);
752 msmsdcc_reset_and_restore(host);
753 if (!mrq->data->error)
754 mrq->data->error = -EIO;
755 }
756
757 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530758 if (!mrq->data->host_cookie)
759 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
760 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 host->sps.sg = NULL;
762 host->sps.busy = 0;
763
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530764 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
765 (host->curr.wait_for_auto_prog_done &&
766 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 /*
768 * If we've already gotten our DATAEND / DATABLKEND
769 * for this request, then complete it through here.
770 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771
772 if (!mrq->data->error) {
773 host->curr.data_xfered = host->curr.xfer_size;
774 host->curr.xfer_remain -= host->curr.xfer_size;
775 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700776 if (host->dummy_52_needed) {
777 mrq->data->bytes_xfered = host->curr.data_xfered;
778 host->dummy_52_sent = 1;
779 msmsdcc_start_command(host, &dummy52cmd,
780 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700781 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700782 return;
783 }
784 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530785 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530786 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530788 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530790 /*
791 * Clear current request information as current
792 * request has ended
793 */
794 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795 spin_unlock_irqrestore(&host->lock, flags);
796
797 mmc_request_done(host->mmc, mrq);
798 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530799 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
800 || !mrq->sbc)) {
801 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 }
803 }
804 spin_unlock_irqrestore(&host->lock, flags);
805}
806
807/**
808 * Exit from current SPS data transfer
809 *
810 * This function exits from current SPS data transfer.
811 *
812 * This function should be called when error condition
813 * is encountered during data transfer.
814 *
815 * @host - Pointer to sdcc host structure
816 *
817 */
818static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
819{
820 struct mmc_request *mrq;
821
822 mrq = host->curr.mrq;
823 BUG_ON(!mrq);
824
825 msmsdcc_reset_and_restore(host);
826 if (!mrq->data->error)
827 mrq->data->error = -EIO;
828
829 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530830 if (!mrq->data->host_cookie)
831 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
832 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833
834 host->sps.sg = NULL;
835 host->sps.busy = 0;
836 if (host->curr.data)
837 msmsdcc_stop_data(host);
838
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530839 if (!mrq->data->stop || mrq->cmd->error ||
840 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530842 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
843 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844 msmsdcc_start_command(host, mrq->data->stop, 0);
845
846}
847#else
848static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
849static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
850static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
851#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
852
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530853static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530855static void
856msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
857 unsigned int result,
858 struct msm_dmov_errdata *err)
859{
860 struct msmsdcc_dma_data *dma_data =
861 container_of(cmd, struct msmsdcc_dma_data, hdr);
862 struct msmsdcc_host *host = dma_data->host;
863
864 dma_data->result = result;
865 if (err)
866 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
867
868 tasklet_schedule(&host->dma_tlet);
869}
870
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530871static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
872 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700873{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530874 bool ret = true;
875 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700876
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530877 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530878 /*
879 * BAM Mode: Fall back on PIO if size is less
880 * than or equal to SPS_MIN_XFER_SIZE bytes.
881 */
882 if (xfer_size <= SPS_MIN_XFER_SIZE)
883 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530884 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530885 /*
886 * ADM Mode: Fall back on PIO if size is less than FIFO size
887 * or not integer multiple of FIFO size
888 */
889 if (xfer_size % MCI_FIFOSIZE)
890 ret = false;
891 } else {
892 /* PIO Mode */
893 ret = false;
894 }
895
896 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700897}
898
899static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
900{
901 struct msmsdcc_nc_dmadata *nc;
902 dmov_box *box;
903 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700904 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530905 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700906 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530907 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700908
Krishna Konda25786ec2011-07-25 16:21:36 -0700909 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700911
Krishna Konda25786ec2011-07-25 16:21:36 -0700912 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700913
914 host->dma.sg = data->sg;
915 host->dma.num_ents = data->sg_len;
916
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530917 /* Prevent memory corruption */
918 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800919
San Mehat9d2bd732009-09-22 16:44:22 -0700920 nc = host->dma.nc;
921
San Mehat9d2bd732009-09-22 16:44:22 -0700922 if (data->flags & MMC_DATA_READ)
923 host->dma.dir = DMA_FROM_DEVICE;
924 else
925 host->dma.dir = DMA_TO_DEVICE;
926
Asutosh Dasaccacd42012-03-08 14:33:17 +0530927 if (!data->host_cookie) {
928 n = msmsdcc_prep_xfer(host, data);
929 if (unlikely(n < 0)) {
930 host->dma.sg = NULL;
931 host->dma.num_ents = 0;
932 return -ENOMEM;
933 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800934 }
San Mehat9d2bd732009-09-22 16:44:22 -0700935
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530936 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
937 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700938 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530939 for (i = 0; i < host->dma.num_ents; i++) {
940 len = sg_dma_len(sg);
941 offset = 0;
942
943 do {
944 /* Check if we can do DMA */
945 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
946 err = -ENOTSUPP;
947 goto unmap;
948 }
949
950 box->cmd = CMD_MODE_BOX;
951
952 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
953 len = MMC_MAX_DMA_BOX_LENGTH;
954 len -= len % data->blksz;
955 }
956 rows = (len % MCI_FIFOSIZE) ?
957 (len / MCI_FIFOSIZE) + 1 :
958 (len / MCI_FIFOSIZE);
959
960 if (data->flags & MMC_DATA_READ) {
961 box->src_row_addr = msmsdcc_fifo_addr(host);
962 box->dst_row_addr = sg_dma_address(sg) + offset;
963 box->src_dst_len = (MCI_FIFOSIZE << 16) |
964 (MCI_FIFOSIZE);
965 box->row_offset = MCI_FIFOSIZE;
966 box->num_rows = rows * ((1 << 16) + 1);
967 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
968 } else {
969 box->src_row_addr = sg_dma_address(sg) + offset;
970 box->dst_row_addr = msmsdcc_fifo_addr(host);
971 box->src_dst_len = (MCI_FIFOSIZE << 16) |
972 (MCI_FIFOSIZE);
973 box->row_offset = (MCI_FIFOSIZE << 16);
974 box->num_rows = rows * ((1 << 16) + 1);
975 box->cmd |= CMD_DST_CRCI(host->dma.crci);
976 }
977
978 offset += len;
979 len = sg_dma_len(sg) - offset;
980 box++;
981 box_cmd_cnt++;
982 } while (len);
983 sg++;
984 }
985 /* Mark last command */
986 box--;
987 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700988
989 /* location of command block must be 64 bit aligned */
990 BUG_ON(host->dma.cmd_busaddr & 0x07);
991
992 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
993 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
994 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
995 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
996
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530997 /* Flush all data to memory before starting dma */
998 mb();
999
1000unmap:
1001 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301002 if (!data->host_cookie)
1003 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1004 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301005 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1006 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001007 }
1008
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301009 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001010}
1011
Asutosh Dasaccacd42012-03-08 14:33:17 +05301012static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1013 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001014{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301015 int rc = 0;
1016 unsigned int dir;
1017
1018 /* Prevent memory corruption */
1019 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1020
1021 if (data->flags & MMC_DATA_READ)
1022 dir = DMA_FROM_DEVICE;
1023 else
1024 dir = DMA_TO_DEVICE;
1025
1026 /* Make sg buffers DMA ready */
1027 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1028 dir);
1029
1030 if (unlikely(rc != data->sg_len)) {
1031 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1032 mmc_hostname(host->mmc), rc);
1033 rc = -ENOMEM;
1034 goto dma_map_err;
1035 }
1036
1037 pr_debug("%s: %s: %s: sg_len=%d\n",
1038 mmc_hostname(host->mmc), __func__,
1039 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1040 data->sg_len);
1041
1042 goto out;
1043
1044dma_map_err:
1045 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1046 data->flags);
1047out:
1048 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001049}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1051/**
1052 * Submits data transfer request to SPS driver
1053 *
1054 * This function make sg (scatter gather) data buffers
1055 * DMA ready and then submits them to SPS driver for
1056 * transfer.
1057 *
1058 * @host - Pointer to sdcc host structure
1059 * @data - Pointer to mmc_data structure
1060 *
1061 * @return 0 if success else negative value
1062 */
1063static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301064 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001065{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 int rc = 0;
1067 u32 flags;
1068 int i;
1069 u32 addr, len, data_cnt;
1070 struct scatterlist *sg = data->sg;
1071 struct sps_pipe *sps_pipe_handle;
1072
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 host->sps.sg = data->sg;
1074 host->sps.num_ents = data->sg_len;
1075 host->sps.xfer_req_cnt = 0;
1076 if (data->flags & MMC_DATA_READ) {
1077 host->sps.dir = DMA_FROM_DEVICE;
1078 sps_pipe_handle = host->sps.prod.pipe_handle;
1079 } else {
1080 host->sps.dir = DMA_TO_DEVICE;
1081 sps_pipe_handle = host->sps.cons.pipe_handle;
1082 }
1083
Asutosh Dasaccacd42012-03-08 14:33:17 +05301084 if (!data->host_cookie) {
1085 rc = msmsdcc_prep_xfer(host, data);
1086 if (unlikely(rc < 0)) {
1087 host->dma.sg = NULL;
1088 host->dma.num_ents = 0;
1089 goto out;
1090 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 }
1092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 for (i = 0; i < data->sg_len; i++) {
1094 /*
1095 * Check if this is the last buffer to transfer?
1096 * If yes then set the INT and EOT flags.
1097 */
1098 len = sg_dma_len(sg);
1099 addr = sg_dma_address(sg);
1100 flags = 0;
1101 while (len > 0) {
1102 if (len > SPS_MAX_DESC_SIZE) {
1103 data_cnt = SPS_MAX_DESC_SIZE;
1104 } else {
1105 data_cnt = len;
1106 if (i == data->sg_len - 1)
1107 flags = SPS_IOVEC_FLAG_INT |
1108 SPS_IOVEC_FLAG_EOT;
1109 }
1110 rc = sps_transfer_one(sps_pipe_handle, addr,
1111 data_cnt, host, flags);
1112 if (rc) {
1113 pr_err("%s: sps_transfer_one() error! rc=%d,"
1114 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1115 mmc_hostname(host->mmc), rc,
1116 (u32)sps_pipe_handle, (u32)sg, i);
1117 goto dma_map_err;
1118 }
1119 addr += data_cnt;
1120 len -= data_cnt;
1121 host->sps.xfer_req_cnt++;
1122 }
1123 sg++;
1124 }
1125 goto out;
1126
1127dma_map_err:
1128 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301129 if (!data->host_cookie)
1130 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1131 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132out:
1133 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001134}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135#else
1136static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1137 struct mmc_data *data) { return 0; }
1138#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001139
1140static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001141msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1142 struct mmc_command *cmd, u32 *c)
1143{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301144 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 cmd->opcode, cmd->arg, cmd->flags);
1146
San Mehat56a8b5b2009-11-21 12:29:46 -08001147 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1148
1149 if (cmd->flags & MMC_RSP_PRESENT) {
1150 if (cmd->flags & MMC_RSP_136)
1151 *c |= MCI_CPSM_LONGRSP;
1152 *c |= MCI_CPSM_RESPONSE;
1153 }
1154
1155 if (/*interrupt*/0)
1156 *c |= MCI_CPSM_INTERRUPT;
1157
Asutosh Das05049132012-05-09 12:38:15 +05301158 /* DAT_CMD bit should be set for all ADTC */
1159 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001160 *c |= MCI_CSPM_DATCMD;
1161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301163 if (host->tuning_needed &&
1164 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1165
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301166 /*
1167 * For open ended block read operation (without CMD23),
1168 * AUTO_CMD19 bit should be set while sending the READ command.
1169 * For close ended block read operation (with CMD23),
1170 * AUTO_CMD19 bit should be set while sending CMD23.
1171 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301172 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1173 host->curr.mrq->cmd->opcode ==
1174 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301175 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301176 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1177 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301178 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1179 *c |= MCI_CSPM_AUTO_CMD19;
1180 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 }
1182
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301183 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1184 writel_relaxed((readl_relaxed(host->base +
1185 MCI_DLL_CONFIG) | MCI_CDR_EN),
1186 host->base + MCI_DLL_CONFIG);
1187 else
1188 /* Clear CDR_EN bit for non read operations */
1189 writel_relaxed((readl_relaxed(host->base +
1190 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1191 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301192
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301193 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1194 (cmd->opcode == MMC_SEND_STATUS &&
1195 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301196 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301198 }
1199
San Mehat56a8b5b2009-11-21 12:29:46 -08001200 if (cmd == cmd->mrq->stop)
1201 *c |= MCI_CSPM_MCIABORT;
1202
San Mehat56a8b5b2009-11-21 12:29:46 -08001203 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301204 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001206 }
1207 host->curr.cmd = cmd;
1208}
1209
1210static void
1211msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1212 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001213{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301214 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001215 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001217 unsigned int pio_irqmask = 0;
1218
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301219 BUG_ON(!data->sg);
1220 BUG_ON(!data->sg_len);
1221
San Mehat9d2bd732009-09-22 16:44:22 -07001222 host->curr.data = data;
1223 host->curr.xfer_size = data->blksz * data->blocks;
1224 host->curr.xfer_remain = host->curr.xfer_size;
1225 host->curr.data_xfered = 0;
1226 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301227 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001228
San Mehat9d2bd732009-09-22 16:44:22 -07001229 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1230
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301231 if (host->curr.wait_for_auto_prog_done)
1232 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001233
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301234 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301235 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301237 } else if (is_sps_mode(host)) {
Krishna Kondad337ddd2012-08-19 11:16:39 -07001238 if (!msmsdcc_sps_start_xfer(host, data)) {
1239 /* Now kick start DML transfer */
1240 mb();
1241 msmsdcc_dml_start_xfer(host, data);
1242 datactrl |= MCI_DPSM_DMAENABLE;
1243 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 }
1245 }
1246 }
1247
1248 /* Is data transfer in PIO mode required? */
1249 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001250 if (data->flags & MMC_DATA_READ) {
1251 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1252 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1253 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1254 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1256 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001257
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001258 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001259 }
1260
1261 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301262 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301263 else if (host->curr.use_wr_data_pend)
1264 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001265
San Mehat56a8b5b2009-11-21 12:29:46 -08001266 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001268 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301269 WARN(!timeout,
1270 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1271 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001272
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301273 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 /* Use ADM (Application Data Mover) HW for Data transfer */
1275 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001276 host->cmd_timeout = timeout;
1277 host->cmd_pio_irqmask = pio_irqmask;
1278 host->cmd_datactrl = datactrl;
1279 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1282 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001283 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001284
1285 if (cmd) {
1286 msmsdcc_start_command_deferred(host, cmd, &c);
1287 host->cmd_c = c;
1288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1290 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1291 host->base + MMCIMASK0);
1292 mb();
1293 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001294 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1301 (~(MCI_IRQ_PIO))) | pio_irqmask,
1302 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001304
1305 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301306 /* Delay between data/command */
1307 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001308 /* Daisy-chain the command if requested */
1309 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301310 } else {
1311 /*
1312 * We don't need delay after writing to DATA_CTRL
1313 * register if we are not writing to CMD register
1314 * immediately after this. As we already have delay
1315 * before sending the command, we just need mb() here.
1316 */
1317 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001318 }
San Mehat9d2bd732009-09-22 16:44:22 -07001319 }
1320}
1321
1322static void
1323msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1324{
San Mehat56a8b5b2009-11-21 12:29:46 -08001325 msmsdcc_start_command_deferred(host, cmd, &c);
1326 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001327}
1328
1329static void
1330msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1331 unsigned int status)
1332{
1333 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301335 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1336 || data->mrq->cmd->opcode ==
1337 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 pr_err("%s: Data CRC error\n",
1339 mmc_hostname(host->mmc));
1340 pr_err("%s: opcode 0x%.8x\n", __func__,
1341 data->mrq->cmd->opcode);
1342 pr_err("%s: blksz %d, blocks %d\n", __func__,
1343 data->blksz, data->blocks);
1344 data->error = -EILSEQ;
1345 }
San Mehat9d2bd732009-09-22 16:44:22 -07001346 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 /* CRC is optional for the bus test commands, not all
1348 * cards respond back with CRC. However controller
1349 * waits for the CRC and times out. Hence ignore the
1350 * data timeouts during the Bustest.
1351 */
1352 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1353 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301354 pr_err("%s: CMD%d: Data timeout\n",
1355 mmc_hostname(host->mmc),
1356 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301358 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 }
San Mehat9d2bd732009-09-22 16:44:22 -07001360 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001361 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001362 data->error = -EIO;
1363 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001364 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001365 data->error = -EIO;
1366 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001367 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001369 data->error = -EIO;
1370 }
San Mehat9d2bd732009-09-22 16:44:22 -07001371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001373 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 host->dummy_52_needed = 0;
1375}
San Mehat9d2bd732009-09-22 16:44:22 -07001376
1377static int
1378msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1379{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001381 uint32_t *ptr = (uint32_t *) buffer;
1382 int count = 0;
1383
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301384 if (remain % 4)
1385 remain = ((remain >> 2) + 1) << 2;
1386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1388
1389 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001390 ptr++;
1391 count += sizeof(uint32_t);
1392
1393 remain -= sizeof(uint32_t);
1394 if (remain == 0)
1395 break;
1396 }
1397 return count;
1398}
1399
1400static int
1401msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001403{
1404 void __iomem *base = host->base;
1405 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 while (readl_relaxed(base + MMCISTATUS) &
1409 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1410 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001411
San Mehat9d2bd732009-09-22 16:44:22 -07001412 count = min(remain, maxcnt);
1413
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301414 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1415 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001416 ptr += count;
1417 remain -= count;
1418
1419 if (remain == 0)
1420 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 }
1422 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001423
1424 return ptr - buffer;
1425}
1426
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001427/*
1428 * Copy up to a word (4 bytes) between a scatterlist
1429 * and a temporary bounce buffer when the word lies across
1430 * two pages. The temporary buffer can then be read to/
1431 * written from the FIFO once.
1432 */
1433static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001434{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001435 struct msmsdcc_pio_data *pio = &host->pio;
1436 unsigned int bytes_avail;
1437
1438 if (host->curr.data->flags & MMC_DATA_READ)
1439 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1440 pio->bounce_buf_len);
1441 else
1442 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1443 pio->bounce_buf_len);
1444
1445 while (pio->bounce_buf_len != 4) {
1446 if (!sg_miter_next(&pio->sg_miter))
1447 break;
1448 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1449 4 - pio->bounce_buf_len);
1450 if (host->curr.data->flags & MMC_DATA_READ)
1451 memcpy(pio->sg_miter.addr,
1452 &pio->bounce_buf[pio->bounce_buf_len],
1453 bytes_avail);
1454 else
1455 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1456 pio->sg_miter.addr, bytes_avail);
1457
1458 pio->sg_miter.consumed = bytes_avail;
1459 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001460 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001461}
1462
1463/*
1464 * Use sg_miter_next to return as many 4-byte aligned
1465 * chunks as possible, using a temporary 4 byte buffer
1466 * for alignment if necessary
1467 */
1468static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1469{
1470 struct msmsdcc_pio_data *pio = &host->pio;
1471 unsigned int length, rlength;
1472 char *buffer;
1473
1474 if (!sg_miter_next(&pio->sg_miter))
1475 return 0;
1476
1477 buffer = pio->sg_miter.addr;
1478 length = pio->sg_miter.length;
1479
1480 if (length < host->curr.xfer_remain) {
1481 rlength = round_down(length, 4);
1482 if (rlength) {
1483 /*
1484 * We have a 4-byte aligned chunk.
1485 * The rounding will be reflected by
1486 * a call to msmsdcc_sg_consumed
1487 */
1488 length = rlength;
1489 goto sg_next_end;
1490 }
1491 /*
1492 * We have a length less than 4 bytes. Check to
1493 * see if more buffer is available, and combine
1494 * to make 4 bytes if possible.
1495 */
1496 pio->bounce_buf_len = length;
1497 memset(pio->bounce_buf, 0, 4);
1498
1499 /*
1500 * On a read, get 4 bytes from FIFO, and distribute
1501 * (4-bouce_buf_len) bytes into consecutive
1502 * sgl buffers when msmsdcc_sg_consumed is called
1503 */
1504 if (host->curr.data->flags & MMC_DATA_READ) {
1505 buffer = pio->bounce_buf;
1506 length = 4;
1507 goto sg_next_end;
1508 } else {
1509 _msmsdcc_sg_consume_word(host);
1510 buffer = pio->bounce_buf;
1511 length = pio->bounce_buf_len;
1512 }
1513 }
1514
1515sg_next_end:
1516 *buf = buffer;
1517 *len = length;
1518 return 1;
1519}
1520
1521/*
1522 * Update sg_miter.consumed based on how many bytes were
1523 * consumed. If the bounce buffer was used to read from FIFO,
1524 * redistribute into sgls.
1525 */
1526static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1527 unsigned int length)
1528{
1529 struct msmsdcc_pio_data *pio = &host->pio;
1530
1531 if (host->curr.data->flags & MMC_DATA_READ) {
1532 if (length > pio->sg_miter.consumed)
1533 /*
1534 * consumed 4 bytes, but sgl
1535 * describes < 4 bytes
1536 */
1537 _msmsdcc_sg_consume_word(host);
1538 else
1539 pio->sg_miter.consumed = length;
1540 } else
1541 if (length < pio->sg_miter.consumed)
1542 pio->sg_miter.consumed = length;
1543}
1544
1545static void msmsdcc_sg_start(struct msmsdcc_host *host)
1546{
1547 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1548
1549 host->pio.bounce_buf_len = 0;
1550
1551 if (host->curr.data->flags & MMC_DATA_READ)
1552 sg_miter_flags |= SG_MITER_TO_SG;
1553 else
1554 sg_miter_flags |= SG_MITER_FROM_SG;
1555
1556 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1557 host->curr.data->sg_len, sg_miter_flags);
1558}
1559
1560static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1561{
1562 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001563}
1564
San Mehat1cd22962010-02-03 12:59:29 -08001565static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001566msmsdcc_pio_irq(int irq, void *dev_id)
1567{
1568 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001570 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001571 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001572 unsigned int remain;
1573 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001574
Murali Palnati36448a42011-09-02 15:06:18 +05301575 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301580 (MCI_IRQ_PIO)) == 0) {
1581 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301582 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301583 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584#if IRQ_DEBUG
1585 msmsdcc_print_status(host, "irq1-r", status);
1586#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001587 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001588
1589 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001590 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001591
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1593 | MCI_RXDATAAVLBL)))
1594 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001595
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001596 if (!msmsdcc_sg_next(host, &buffer, &remain))
1597 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001598
San Mehat9d2bd732009-09-22 16:44:22 -07001599 len = 0;
1600 if (status & MCI_RXACTIVE)
1601 len = msmsdcc_pio_read(host, buffer, remain);
1602 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301605 /* len might have aligned to 32bits above */
1606 if (len > remain)
1607 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001608
San Mehat9d2bd732009-09-22 16:44:22 -07001609 host->curr.xfer_remain -= len;
1610 host->curr.data_xfered += len;
1611 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001612 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 if (remain) /* Done with this page? */
1615 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001618 } while (1);
1619
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001620 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001621 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1624 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1625 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1626 host->base + MMCIMASK0);
1627 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301628 /*
1629 * back to back write to MASK0 register don't need
1630 * synchronization delay.
1631 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1633 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1634 }
1635 mb();
1636 } else if (!host->curr.xfer_remain) {
1637 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1638 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1639 mb();
1640 }
San Mehat9d2bd732009-09-22 16:44:22 -07001641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001643
1644 return IRQ_HANDLED;
1645}
1646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647static void
1648msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1649
1650static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1651 struct mmc_data *data)
1652{
1653 u32 loop_cnt = 0;
1654
1655 /*
1656 * For read commands with data less than fifo size, it is possible to
1657 * get DATAEND first and RXDATA_AVAIL might be set later because of
1658 * synchronization delay through the asynchronous RX FIFO. Thus, for
1659 * such cases, even after DATAEND interrupt is received software
1660 * should poll for RXDATA_AVAIL until the requested data is read out
1661 * of FIFO. This change is needed to get around this abnormal but
1662 * sometimes expected behavior of SDCC3 controller.
1663 *
1664 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1665 * after the data is loaded into RX FIFO. This would amount to less
1666 * than a microsecond and thus looping for 1000 times is good enough
1667 * for that delay.
1668 */
1669 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1670 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1671 spin_unlock(&host->lock);
1672 msmsdcc_pio_irq(1, host);
1673 spin_lock(&host->lock);
1674 }
1675 }
1676 if (loop_cnt == 1000) {
1677 pr_info("%s: Timed out while polling for Rx Data\n",
1678 mmc_hostname(host->mmc));
1679 data->error = -ETIMEDOUT;
1680 msmsdcc_reset_and_restore(host);
1681 }
1682}
1683
San Mehat9d2bd732009-09-22 16:44:22 -07001684static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1685{
1686 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001687
1688 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301689 if (mmc_resp_type(cmd))
1690 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1691 /*
1692 * Read rest of the response registers only if
1693 * long response is expected for this command
1694 */
1695 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1696 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1697 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1698 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1699 }
San Mehat9d2bd732009-09-22 16:44:22 -07001700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301702 pr_debug("%s: CMD%d: Command timeout\n",
1703 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001704 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301706 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301707 pr_err("%s: CMD%d: Command CRC error\n",
1708 mmc_hostname(host->mmc), cmd->opcode);
1709 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001710 cmd->error = -EILSEQ;
1711 }
1712
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301713 if (!cmd->error) {
1714 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1715 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1716 mod_timer(&host->req_tout_timer, (jiffies +
1717 msecs_to_jiffies(host->curr.req_tout_ms)));
1718 }
1719 }
1720
San Mehat9d2bd732009-09-22 16:44:22 -07001721 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301723 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001724 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301726 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 /* Stop current SPS transfer */
1728 msmsdcc_sps_exit_curr_xfer(host);
1729 }
San Mehat9d2bd732009-09-22 16:44:22 -07001730 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301731 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001732 msmsdcc_stop_data(host);
1733 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301734 } else { /* host->data == NULL */
1735 if (!cmd->error && host->prog_enable) {
1736 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301738 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301740 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301741 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301742 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301743 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001744 if (host->dummy_52_needed)
1745 host->dummy_52_needed = 0;
1746 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301748 msmsdcc_request_end(host, cmd->mrq);
1749 }
1750 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301751 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301752 if (cmd == host->curr.mrq->sbc)
1753 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1754 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1755 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301756 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001757 }
1758}
1759
San Mehat9d2bd732009-09-22 16:44:22 -07001760static irqreturn_t
1761msmsdcc_irq(int irq, void *dev_id)
1762{
1763 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001764 u32 status;
1765 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001767
1768 spin_lock(&host->lock);
1769
1770 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771 struct mmc_command *cmd;
1772 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 if (timer) {
1775 timer = 0;
1776 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001777 }
San Mehat9d2bd732009-09-22 16:44:22 -07001778
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301779 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 pr_debug("%s: %s: SDIO async irq received\n",
1781 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301782
1783 /*
1784 * Only async interrupt can come when clocks are off,
1785 * disable further interrupts and enable them when
1786 * clocks are on.
1787 */
1788 if (!host->sdcc_irq_disabled) {
1789 disable_irq_nosync(irq);
1790 host->sdcc_irq_disabled = 1;
1791 }
1792
1793 /*
1794 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1795 * will take care of signaling sdio irq during
1796 * mmc_sdio_resume().
1797 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301798 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301799 /*
1800 * This is a wakeup interrupt so hold wakelock
1801 * until SDCC resume is handled.
1802 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301804 } else {
1805 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301806 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301807 spin_lock(&host->lock);
1808 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301809 ret = 1;
1810 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 }
1812
1813 status = readl_relaxed(host->base + MMCISTATUS);
1814
1815 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1816 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001817 break;
1818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819#if IRQ_DEBUG
1820 msmsdcc_print_status(host, "irq0-r", status);
1821#endif
1822 status &= readl_relaxed(host->base + MMCIMASK0);
1823 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301824 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301825 if (host->clk_rate <=
1826 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301827 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828#if IRQ_DEBUG
1829 msmsdcc_print_status(host, "irq0-p", status);
1830#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 if (status & MCI_SDIOINTROPE) {
1833 if (host->sdcc_suspending)
1834 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301835 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301837 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001838 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001839 data = host->curr.data;
1840
1841 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1843 MCI_CMDTIMEOUT)) {
1844 if (status & MCI_CMDTIMEOUT)
1845 pr_debug("%s: dummy CMD52 timeout\n",
1846 mmc_hostname(host->mmc));
1847 if (status & MCI_CMDCRCFAIL)
1848 pr_debug("%s: dummy CMD52 CRC failed\n",
1849 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001850 host->dummy_52_sent = 0;
1851 host->dummy_52_needed = 0;
1852 if (data) {
1853 msmsdcc_stop_data(host);
1854 msmsdcc_request_end(host, data->mrq);
1855 }
1856 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 spin_unlock(&host->lock);
1858 return IRQ_HANDLED;
1859 }
1860 break;
1861 }
1862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 /*
1864 * Check for proper command response
1865 */
1866 cmd = host->curr.cmd;
1867 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1868 MCI_CMDTIMEOUT | MCI_PROGDONE |
1869 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1870 msmsdcc_do_cmdirq(host, status);
1871 }
1872
Sathish Ambley081d7842011-11-29 11:19:41 -08001873 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874 /* Check for data errors */
1875 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1876 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1877 msmsdcc_data_err(host, data, status);
1878 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301879 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001880 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301881 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 /* Stop current SPS transfer */
1883 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301884 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885 msmsdcc_reset_and_restore(host);
1886 if (host->curr.data)
1887 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301888 if (!data->stop || (host->curr.mrq->sbc
1889 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890 timer |=
1891 msmsdcc_request_end(host,
1892 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301893 else if ((host->curr.mrq->sbc
1894 && data->error) ||
1895 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 msmsdcc_start_command(host,
1897 data->stop,
1898 0);
1899 timer = 1;
1900 }
1901 }
1902 }
1903
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301904 /* Check for prog done */
1905 if (host->curr.wait_for_auto_prog_done &&
1906 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301907 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 /* Check for data done */
1910 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1911 host->curr.got_dataend = 1;
1912
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301913 if (host->curr.got_dataend &&
1914 (!host->curr.wait_for_auto_prog_done ||
1915 (host->curr.wait_for_auto_prog_done &&
1916 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 /*
1918 * If DMA is still in progress, we complete
1919 * via the completion handler
1920 */
1921 if (!host->dma.busy && !host->sps.busy) {
1922 /*
1923 * There appears to be an issue in the
1924 * controller where if you request a
1925 * small block transfer (< fifo size),
1926 * you may get your DATAEND/DATABLKEND
1927 * irq without the PIO data irq.
1928 *
1929 * Check to see if theres still data
1930 * to be read, and simulate a PIO irq.
1931 */
1932 if (data->flags & MMC_DATA_READ)
1933 msmsdcc_wait_for_rxdata(host,
1934 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 if (!data->error) {
1936 host->curr.data_xfered =
1937 host->curr.xfer_size;
1938 host->curr.xfer_remain -=
1939 host->curr.xfer_size;
1940 }
1941
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001942 if (!host->dummy_52_needed) {
1943 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301944 if (!data->stop ||
1945 (host->curr.mrq->sbc
1946 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001947 msmsdcc_request_end(
1948 host,
1949 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301950 else if ((host->curr.mrq->sbc
1951 && data->error) ||
1952 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001953 msmsdcc_start_command(
1954 host,
1955 data->stop, 0);
1956 timer = 1;
1957 }
1958 } else {
1959 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001961 &dummy52cmd,
1962 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 }
1964 }
1965 }
1966 }
1967
San Mehat9d2bd732009-09-22 16:44:22 -07001968 ret = 1;
1969 } while (status);
1970
1971 spin_unlock(&host->lock);
1972
San Mehat9d2bd732009-09-22 16:44:22 -07001973 return IRQ_RETVAL(ret);
1974}
1975
1976static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301977msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1978 bool is_first_request)
1979{
1980 struct msmsdcc_host *host = mmc_priv(mmc);
1981 struct mmc_data *data = mrq->data;
1982 int rc = 0;
1983
1984 if (unlikely(!data)) {
1985 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1986 __func__);
1987 return;
1988 }
1989 if (unlikely(data->host_cookie)) {
1990 /* Very wrong */
1991 data->host_cookie = 0;
1992 pr_err("%s: %s Request reposted for prepare\n",
1993 mmc_hostname(mmc), __func__);
1994 return;
1995 }
1996
1997 if (!msmsdcc_is_dma_possible(host, data))
1998 return;
1999
2000 rc = msmsdcc_prep_xfer(host, data);
2001 if (unlikely(rc < 0)) {
2002 data->host_cookie = 0;
2003 return;
2004 }
2005
2006 data->host_cookie = 1;
2007}
2008
2009static void
2010msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2011{
2012 struct msmsdcc_host *host = mmc_priv(mmc);
2013 unsigned int dir;
2014 struct mmc_data *data = mrq->data;
2015
2016 if (unlikely(!data)) {
2017 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2018 __func__);
2019 return;
2020 }
2021 if (data->flags & MMC_DATA_READ)
2022 dir = DMA_FROM_DEVICE;
2023 else
2024 dir = DMA_TO_DEVICE;
2025
2026 if (data->host_cookie)
2027 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2028 data->sg_len, dir);
2029
2030 data->host_cookie = 0;
2031}
2032
2033static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2035{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302036 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302038 if ((mrq->data->flags & MMC_DATA_READ) ||
2039 host->curr.use_wr_data_pend)
2040 msmsdcc_start_data(host, mrq->data,
2041 mrq->sbc ? mrq->sbc : mrq->cmd,
2042 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302043 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302044 msmsdcc_start_command(host,
2045 mrq->sbc ? mrq->sbc : mrq->cmd,
2046 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047 } else {
2048 msmsdcc_start_command(host, mrq->cmd, 0);
2049 }
2050}
2051
2052static void
San Mehat9d2bd732009-09-22 16:44:22 -07002053msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2054{
2055 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302056 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 /*
2059 * Get the SDIO AL client out of LPM.
2060 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002061 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 if (host->plat->is_sdio_al_client)
2063 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002064
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302065 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302066 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302067 msmsdcc_sps_pipes_reset_and_restore(host);
2068 host->sps.pipe_reset_pending = false;
2069 }
San Mehat9d2bd732009-09-22 16:44:22 -07002070
2071 spin_lock_irqsave(&host->lock, flags);
2072
San Mehat9d2bd732009-09-22 16:44:22 -07002073 if (host->eject) {
2074 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2075 mrq->cmd->error = 0;
2076 mrq->data->bytes_xfered = mrq->data->blksz *
2077 mrq->data->blocks;
2078 } else
2079 mrq->cmd->error = -ENOMEDIUM;
2080
2081 spin_unlock_irqrestore(&host->lock, flags);
2082 mmc_request_done(mmc, mrq);
2083 return;
2084 }
2085
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302086 /*
subhashjf181c292012-05-02 13:07:40 +05302087 * Don't start the request if SDCC is not in proper state to handle it
2088 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302089 if (!host->pwr || !atomic_read(&host->clks_on)
2090 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302091 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2092 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2093 __func__, mrq->cmd->opcode);
2094 msmsdcc_dump_sdcc_state(host);
2095 mrq->cmd->error = -EIO;
2096 if (mrq->data) {
2097 mrq->data->error = -EIO;
2098 mrq->data->bytes_xfered = 0;
2099 }
2100 spin_unlock_irqrestore(&host->lock, flags);
2101 mmc_request_done(mmc, mrq);
2102 return;
2103 }
2104
2105 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2106 " other request (CMD%d) is in progress\n",
2107 mmc_hostname(host->mmc), __func__,
2108 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2109
2110 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302111 * Set timeout value to 10 secs (or more in case of buggy cards)
2112 */
2113 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302114 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302115 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302116 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302117 /*
2118 * Kick the software request timeout timer here with the timeout
2119 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302120 */
2121 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302122 (jiffies +
2123 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002124
San Mehat9d2bd732009-09-22 16:44:22 -07002125 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302126 if (mrq->sbc) {
2127 mrq->sbc->mrq = mrq;
2128 mrq->sbc->data = mrq->data;
2129 }
2130
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302131 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302132 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302133 /*
2134 * Auto-prog done will be enabled for following cases:
2135 * mrq->sbc | mrq->stop
2136 * _____________|________________
2137 * True | Don't care
2138 * False | False (CMD24, ACMD25 use case)
2139 */
2140 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302141 host->curr.wait_for_auto_prog_done = true;
2142 } else {
2143 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2144 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 host->dummy_52_needed = 1;
2146 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302147
Subhash Jadavanif5277752011-10-12 16:47:52 +05302148 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2149 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2150 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002151 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302152
Subhash Jadavanif5277752011-10-12 16:47:52 +05302153 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302154
San Mehat9d2bd732009-09-22 16:44:22 -07002155 spin_unlock_irqrestore(&host->lock, flags);
2156}
2157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2159 int min_uV, int max_uV)
2160{
2161 int rc = 0;
2162
2163 if (vreg->set_voltage_sup) {
2164 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2165 if (rc) {
2166 pr_err("%s: regulator_set_voltage(%s) failed."
2167 " min_uV=%d, max_uV=%d, rc=%d\n",
2168 __func__, vreg->name, min_uV, max_uV, rc);
2169 }
2170 }
2171
2172 return rc;
2173}
2174
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302175static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2176{
2177 int rc = 0;
2178
2179 rc = regulator_get_voltage(vreg->reg);
2180 if (rc < 0)
2181 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2182 __func__, vreg->name, rc);
2183
2184 return rc;
2185}
2186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2188 int uA_load)
2189{
2190 int rc = 0;
2191
Krishna Kondafea60182011-11-01 16:01:34 -07002192 /* regulators that do not support regulator_set_voltage also
2193 do not support regulator_set_optimum_mode */
2194 if (vreg->set_voltage_sup) {
2195 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2196 if (rc < 0)
2197 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2198 "uA_load=%d) failed. rc=%d\n", __func__,
2199 vreg->name, uA_load, rc);
2200 else
2201 /* regulator_set_optimum_mode() can return non zero
2202 * value even for success case.
2203 */
2204 rc = 0;
2205 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206
2207 return rc;
2208}
2209
2210static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2211 struct device *dev)
2212{
2213 int rc = 0;
2214
2215 /* check if regulator is already initialized? */
2216 if (vreg->reg)
2217 goto out;
2218
2219 /* Get the regulator handle */
2220 vreg->reg = regulator_get(dev, vreg->name);
2221 if (IS_ERR(vreg->reg)) {
2222 rc = PTR_ERR(vreg->reg);
2223 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2224 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002225 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002227
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302228 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002229 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302230 /* sanity check */
2231 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2232 pr_err("%s: %s invalid constraints specified\n",
2233 __func__, vreg->name);
2234 rc = -EINVAL;
2235 }
2236 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238out:
2239 return rc;
2240}
2241
2242static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2243{
2244 if (vreg->reg)
2245 regulator_put(vreg->reg);
2246}
2247
2248/* This init function should be called only once for each SDCC slot */
2249static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2250{
2251 int rc = 0;
2252 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302253 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 struct device *dev = mmc_dev(host->mmc);
2255
2256 curr_slot = host->plat->vreg_data;
2257 if (!curr_slot)
2258 goto out;
2259
2260 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302261 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262
2263 if (is_init) {
2264 /*
2265 * Get the regulator handle from voltage regulator framework
2266 * and then try to set the voltage level for the regulator
2267 */
2268 if (curr_vdd_reg) {
2269 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2270 if (rc)
2271 goto out;
2272 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302273 if (curr_vdd_io_reg) {
2274 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 if (rc)
2276 goto vdd_reg_deinit;
2277 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002278 rc = msmsdcc_vreg_reset(host);
2279 if (rc)
2280 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2281 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 goto out;
2283 } else {
2284 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302285 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302287vdd_io_reg_deinit:
2288 if (curr_vdd_io_reg)
2289 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290vdd_reg_deinit:
2291 if (curr_vdd_reg)
2292 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2293out:
2294 return rc;
2295}
2296
2297static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2298{
2299 int rc = 0;
2300
Subhash Jadavanicc922692011-08-01 23:05:01 +05302301 /* Put regulator in HPM (high power mode) */
2302 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2303 if (rc < 0)
2304 goto out;
2305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306 if (!vreg->is_enabled) {
2307 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302308 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2309 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 if (rc)
2311 goto out;
2312
2313 rc = regulator_enable(vreg->reg);
2314 if (rc) {
2315 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2316 __func__, vreg->name, rc);
2317 goto out;
2318 }
2319 vreg->is_enabled = true;
2320 }
2321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322out:
2323 return rc;
2324}
2325
Krishna Konda3c4142d2012-06-27 11:01:56 -07002326static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327{
2328 int rc = 0;
2329
2330 /* Never disable regulator marked as always_on */
2331 if (vreg->is_enabled && !vreg->always_on) {
2332 rc = regulator_disable(vreg->reg);
2333 if (rc) {
2334 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2335 __func__, vreg->name, rc);
2336 goto out;
2337 }
2338 vreg->is_enabled = false;
2339
2340 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2341 if (rc < 0)
2342 goto out;
2343
2344 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302345 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 if (rc)
2347 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002348 } else if (vreg->is_enabled && vreg->always_on) {
2349 if (!is_init && vreg->lpm_sup) {
2350 /* Put always_on regulator in LPM (low power mode) */
2351 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2352 if (rc < 0)
2353 goto out;
2354 } else if (is_init && vreg->reset_at_init) {
2355 /**
2356 * The regulator might not actually be disabled if it
2357 * is shared and in use by other drivers.
2358 */
2359 rc = regulator_disable(vreg->reg);
2360 if (rc) {
2361 pr_err("%s: regulator_disable(%s) failed at " \
2362 "bootup. rc=%d\n", __func__,
2363 vreg->name, rc);
2364 goto out;
2365 }
2366 vreg->is_enabled = false;
2367 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 }
2369out:
2370 return rc;
2371}
2372
Krishna Konda3c4142d2012-06-27 11:01:56 -07002373static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2374 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375{
2376 int rc = 0, i;
2377 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302378 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379
2380 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302381 if (!curr_slot) {
2382 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302384 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385
Subhash Jadavani937c7502012-06-01 15:34:46 +05302386 vreg_table[0] = curr_slot->vdd_data;
2387 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388
2389 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2390 if (vreg_table[i]) {
2391 if (enable)
2392 rc = msmsdcc_vreg_enable(vreg_table[i]);
2393 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002394 rc = msmsdcc_vreg_disable(vreg_table[i],
2395 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 if (rc)
2397 goto out;
2398 }
2399 }
2400out:
2401 return rc;
2402}
2403
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002404/*
2405 * Reset vreg by ensuring it is off during probe. A call
2406 * to enable vreg is needed to balance disable vreg
2407 */
2408static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2409{
2410 int rc;
2411
Krishna Konda3c4142d2012-06-27 11:01:56 -07002412 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002413 if (rc)
2414 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002415 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002416 return rc;
2417}
2418
Subhash Jadavani937c7502012-06-01 15:34:46 +05302419enum vdd_io_level {
2420 /* set vdd_io_data->low_vol_level */
2421 VDD_IO_LOW,
2422 /* set vdd_io_data->high_vol_level */
2423 VDD_IO_HIGH,
2424 /*
2425 * set whatever there in voltage_level (third argument) of
2426 * msmsdcc_set_vdd_io_vol() function.
2427 */
2428 VDD_IO_SET_LEVEL,
2429};
2430
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302431/*
2432 * This function returns the current VDD IO voltage level.
2433 * Returns negative value if it fails to read the voltage level
2434 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2435 * regulator were not defined for host.
2436 */
2437static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2438{
2439 int rc = 0;
2440
2441 if (host->plat->vreg_data) {
2442 struct msm_mmc_reg_data *io_reg =
2443 host->plat->vreg_data->vdd_io_data;
2444
2445 /*
2446 * If vdd_io is not defined, then we can consider that
2447 * IO voltage is same as VDD.
2448 */
2449 if (!io_reg)
2450 io_reg = host->plat->vreg_data->vdd_data;
2451
2452 if (io_reg && io_reg->is_enabled)
2453 rc = msmsdcc_vreg_get_voltage(io_reg);
2454 }
2455
2456 return rc;
2457}
2458
2459/*
2460 * This function updates the IO pad power switch bit in MCI_CLK register
2461 * based on currrent IO pad voltage level.
2462 * NOTE: This function assumes that host lock was not taken by caller.
2463 */
2464static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2465{
2466 int rc = 0;
2467 unsigned long flags;
2468
2469 if (!is_io_pad_pwr_switch(host))
2470 return;
2471
2472 rc = msmsdcc_get_vdd_io_vol(host);
2473
2474 spin_lock_irqsave(&host->lock, flags);
2475 /*
2476 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2477 * the SDCC instances support the dual voltage pads.
2478 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2479 * bit before using the pads in 1.8V mode.
2480 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2481 * IO_PAD_PWR_SWITCH bit is a don't care.
2482 * But we don't have an option to know (by reading some SDCC register)
2483 * that a particular SDCC instance supports dual voltage pads or not,
2484 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2485 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2486 * is anyway ignored.
2487 */
2488 if (rc > 0 && rc < 2700000)
2489 host->io_pad_pwr_switch = 1;
2490 else
2491 host->io_pad_pwr_switch = 0;
2492
2493 if (atomic_read(&host->clks_on)) {
2494 if (host->io_pad_pwr_switch)
2495 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2496 IO_PAD_PWR_SWITCH),
2497 host->base + MMCICLOCK);
2498 else
2499 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2500 ~IO_PAD_PWR_SWITCH),
2501 host->base + MMCICLOCK);
2502 msmsdcc_sync_reg_wr(host);
2503 }
2504 spin_unlock_irqrestore(&host->lock, flags);
2505}
2506
Subhash Jadavani937c7502012-06-01 15:34:46 +05302507static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2508 enum vdd_io_level level,
2509 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510{
2511 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302512 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513
2514 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302515 struct msm_mmc_reg_data *vdd_io_reg =
2516 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517
Subhash Jadavani937c7502012-06-01 15:34:46 +05302518 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2519 switch (level) {
2520 case VDD_IO_LOW:
2521 set_level = vdd_io_reg->low_vol_level;
2522 break;
2523 case VDD_IO_HIGH:
2524 set_level = vdd_io_reg->high_vol_level;
2525 break;
2526 case VDD_IO_SET_LEVEL:
2527 set_level = voltage_level;
2528 break;
2529 default:
2530 pr_err("%s: %s: invalid argument level = %d",
2531 mmc_hostname(host->mmc), __func__,
2532 level);
2533 rc = -EINVAL;
2534 goto out;
2535 }
2536 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2537 set_level, set_level);
2538 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 }
2540
Subhash Jadavani937c7502012-06-01 15:34:46 +05302541out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302542 return rc;
2543}
2544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2546{
2547 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2548 return 1;
2549 return 0;
2550}
2551
Asutosh Dasf5298c32012-04-03 14:51:47 +05302552/*
2553 * Any function calling msmsdcc_setup_clocks must
2554 * acquire clk_mutex. May sleep.
2555 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302556static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302558 int rc = 0;
2559
2560 if (enable && !atomic_read(&host->clks_on)) {
2561 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2562 rc = clk_prepare_enable(host->bus_clk);
2563 if (rc) {
2564 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2565 mmc_hostname(host->mmc), __func__, rc);
2566 goto out;
2567 }
2568 }
2569 if (!IS_ERR(host->pclk)) {
2570 rc = clk_prepare_enable(host->pclk);
2571 if (rc) {
2572 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2573 mmc_hostname(host->mmc), __func__, rc);
2574 goto disable_bus;
2575 }
2576 }
2577 rc = clk_prepare_enable(host->clk);
2578 if (rc) {
2579 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2580 mmc_hostname(host->mmc), __func__, rc);
2581 goto disable_pclk;
2582 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302583 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302584 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302585 atomic_set(&host->clks_on, 1);
2586 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302587 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302588 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302589 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302591 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302592 if (!IS_ERR_OR_NULL(host->bus_clk))
2593 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302594 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302596 goto out;
2597
2598disable_pclk:
2599 if (!IS_ERR_OR_NULL(host->pclk))
2600 clk_disable_unprepare(host->pclk);
2601disable_bus:
2602 if (!IS_ERR_OR_NULL(host->bus_clk))
2603 clk_disable_unprepare(host->bus_clk);
2604out:
2605 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606}
2607
2608static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2609 unsigned int req_clk)
2610{
2611 unsigned int sel_clk = -1;
2612
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302613 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2614 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2615 goto out;
2616 }
2617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2619 unsigned char cnt;
2620
2621 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2622 if (host->plat->sup_clk_table[cnt] > req_clk)
2623 break;
2624 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2625 sel_clk = host->plat->sup_clk_table[cnt];
2626 break;
2627 } else
2628 sel_clk = host->plat->sup_clk_table[cnt];
2629 }
2630 } else {
2631 if ((req_clk < host->plat->msmsdcc_fmax) &&
2632 (req_clk > host->plat->msmsdcc_fmid))
2633 sel_clk = host->plat->msmsdcc_fmid;
2634 else
2635 sel_clk = req_clk;
2636 }
2637
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302638out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 return sel_clk;
2640}
2641
2642static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2643 struct msmsdcc_host *host)
2644{
2645 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2646 return host->plat->sup_clk_table[0];
2647 else
2648 return host->plat->msmsdcc_fmin;
2649}
2650
2651static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2652 struct msmsdcc_host *host)
2653{
2654 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2655 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2656 else
2657 return host->plat->msmsdcc_fmax;
2658}
2659
2660static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302661{
2662 struct msm_mmc_gpio_data *curr;
2663 int i, rc = 0;
2664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302666 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302667 if (!gpio_is_valid(curr->gpio[i].no)) {
2668 rc = -EINVAL;
2669 pr_err("%s: Invalid gpio = %d\n",
2670 mmc_hostname(host->mmc), curr->gpio[i].no);
2671 goto free_gpios;
2672 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302673 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 if (curr->gpio[i].is_always_on &&
2675 curr->gpio[i].is_enabled)
2676 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302677 rc = gpio_request(curr->gpio[i].no,
2678 curr->gpio[i].name);
2679 if (rc) {
2680 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2681 mmc_hostname(host->mmc),
2682 curr->gpio[i].no,
2683 curr->gpio[i].name, rc);
2684 goto free_gpios;
2685 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302687 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688 if (curr->gpio[i].is_always_on)
2689 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302690 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302692 }
2693 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302695
2696free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302697 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302698 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 curr->gpio[i].is_enabled = false;
2700 }
2701out:
2702 return rc;
2703}
2704
2705static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2706{
2707 struct msm_mmc_pad_data *curr;
2708 int i;
2709
2710 curr = host->plat->pin_data->pad_data;
2711 for (i = 0; i < curr->drv->size; i++) {
2712 if (enable)
2713 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2714 curr->drv->on[i].val);
2715 else
2716 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2717 curr->drv->off[i].val);
2718 }
2719
2720 for (i = 0; i < curr->pull->size; i++) {
2721 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002722 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 curr->pull->on[i].val);
2724 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002725 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726 curr->pull->off[i].val);
2727 }
2728
2729 return 0;
2730}
2731
2732static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2733{
2734 int rc = 0;
2735
2736 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2737 return 0;
2738
2739 if (host->plat->pin_data->is_gpio)
2740 rc = msmsdcc_setup_gpio(host, enable);
2741 else
2742 rc = msmsdcc_setup_pad(host, enable);
2743
2744 if (!rc)
2745 host->plat->pin_data->cfg_sts = enable;
2746
2747 return rc;
2748}
2749
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302750static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2751 unsigned mode)
2752{
2753 int ret = 0;
2754 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2755
2756 if (!pin)
2757 return 0;
2758
2759 switch (mode) {
2760 case SDC_DAT1_DISABLE:
2761 ret = msm_mpm_enable_pin(pin, 0);
2762 break;
2763 case SDC_DAT1_ENABLE:
2764 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2765 ret = msm_mpm_enable_pin(pin, 1);
2766 break;
2767 case SDC_DAT1_ENWAKE:
2768 ret = msm_mpm_set_pin_wake(pin, 1);
2769 break;
2770 case SDC_DAT1_DISWAKE:
2771 ret = msm_mpm_set_pin_wake(pin, 0);
2772 break;
2773 default:
2774 ret = -EINVAL;
2775 break;
2776 }
2777
2778 return ret;
2779}
2780
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302781static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2782{
2783 u32 pwr = 0;
2784 int ret = 0;
2785 struct mmc_host *mmc = host->mmc;
2786
2787 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2788 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2789 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002790 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302791
2792 if (ret) {
2793 pr_err("%s: Failed to setup voltage regulators\n",
2794 mmc_hostname(host->mmc));
2795 goto out;
2796 }
2797
2798 switch (ios->power_mode) {
2799 case MMC_POWER_OFF:
2800 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302801 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302802 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302803 * If VDD IO rail is always on, set low voltage for VDD
2804 * IO rail when slot is not in use (like when card is not
2805 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302806 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302807 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302808 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302809 msmsdcc_setup_pins(host, false);
2810 break;
2811 case MMC_POWER_UP:
2812 /* writing PWR_UP bit is redundant */
2813 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302814 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302815
Subhash Jadavani937c7502012-06-01 15:34:46 +05302816 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302817 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302818 msmsdcc_setup_pins(host, true);
2819 break;
2820 case MMC_POWER_ON:
2821 pwr = MCI_PWR_ON;
2822 break;
2823 }
2824
2825out:
2826 return pwr;
2827}
2828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2830{
2831 unsigned int wakeup_irq;
2832
2833 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2834 host->plat->sdiowakeup_irq :
2835 host->core_irqres->start;
2836
2837 if (!host->irq_wake_enabled) {
2838 enable_irq_wake(wakeup_irq);
2839 host->irq_wake_enabled = true;
2840 }
2841}
2842
2843static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2844{
2845 unsigned int wakeup_irq;
2846
2847 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2848 host->plat->sdiowakeup_irq :
2849 host->core_irqres->start;
2850
2851 if (host->irq_wake_enabled) {
2852 disable_irq_wake(wakeup_irq);
2853 host->irq_wake_enabled = false;
2854 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302855}
2856
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302857/* Returns required bandwidth in Bytes per Sec */
2858static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2859 struct mmc_ios *ios)
2860{
2861 unsigned int bw;
2862
2863 bw = host->clk_rate;
2864 /*
2865 * For DDR mode, SDCC controller clock will be at
2866 * the double rate than the actual clock that goes to card.
2867 */
2868 if (ios->bus_width == MMC_BUS_WIDTH_4)
2869 bw /= 2;
2870 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2871 bw /= 8;
2872
2873 return bw;
2874}
2875
2876static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2877 unsigned int bw)
2878{
2879 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2880 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2881 int i;
2882
2883 if (host->msm_bus_vote.is_max_bw_needed && bw)
2884 return host->msm_bus_vote.max_bw_vote;
2885
2886 for (i = 0; i < size; i++) {
2887 if (bw <= table[i])
2888 break;
2889 }
2890
2891 if (i && (i == size))
2892 i--;
2893
2894 return i;
2895}
2896
2897static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2898{
2899 int rc = 0;
2900 struct msm_bus_scale_pdata *use_cases;
2901
2902 if (host->plat->msm_bus_voting_data &&
2903 host->plat->msm_bus_voting_data->use_cases &&
2904 host->plat->msm_bus_voting_data->bw_vecs &&
2905 host->plat->msm_bus_voting_data->bw_vecs_size) {
2906 use_cases = host->plat->msm_bus_voting_data->use_cases;
2907 host->msm_bus_vote.client_handle =
2908 msm_bus_scale_register_client(use_cases);
2909 } else {
2910 return 0;
2911 }
2912
2913 if (!host->msm_bus_vote.client_handle) {
2914 pr_err("%s: msm_bus_scale_register_client() failed\n",
2915 mmc_hostname(host->mmc));
2916 rc = -EFAULT;
2917 } else {
2918 /* cache the vote index for minimum and maximum bandwidth */
2919 host->msm_bus_vote.min_bw_vote =
2920 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2921 host->msm_bus_vote.max_bw_vote =
2922 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2923 }
2924
2925 return rc;
2926}
2927
2928static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2929{
2930 if (host->msm_bus_vote.client_handle)
2931 msm_bus_scale_unregister_client(
2932 host->msm_bus_vote.client_handle);
2933}
2934
2935/*
2936 * This function must be called with host lock acquired.
2937 * Caller of this function should also ensure that msm bus client
2938 * handle is not null.
2939 */
2940static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2941 int vote,
2942 unsigned long flags)
2943{
2944 int rc = 0;
2945
2946 if (vote != host->msm_bus_vote.curr_vote) {
2947 spin_unlock_irqrestore(&host->lock, flags);
2948 rc = msm_bus_scale_client_update_request(
2949 host->msm_bus_vote.client_handle, vote);
2950 if (rc)
2951 pr_err("%s: msm_bus_scale_client_update_request() failed."
2952 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2953 mmc_hostname(host->mmc),
2954 host->msm_bus_vote.client_handle, vote, rc);
2955 spin_lock_irqsave(&host->lock, flags);
2956 if (!rc)
2957 host->msm_bus_vote.curr_vote = vote;
2958 }
2959
2960 return rc;
2961}
2962
2963/*
2964 * Internal work. Work to set 0 bandwidth for msm bus.
2965 */
2966static void msmsdcc_msm_bus_work(struct work_struct *work)
2967{
2968 struct msmsdcc_host *host = container_of(work,
2969 struct msmsdcc_host,
2970 msm_bus_vote.vote_work.work);
2971 unsigned long flags;
2972
2973 if (!host->msm_bus_vote.client_handle)
2974 return;
2975
2976 spin_lock_irqsave(&host->lock, flags);
2977 /* don't vote for 0 bandwidth if any request is in progress */
2978 if (!host->curr.mrq)
2979 msmsdcc_msm_bus_set_vote(host,
2980 host->msm_bus_vote.min_bw_vote, flags);
2981 else
2982 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2983 " bus voting to 0 bandwidth\n",
2984 mmc_hostname(host->mmc), __func__);
2985 spin_unlock_irqrestore(&host->lock, flags);
2986}
2987
2988/*
2989 * This function cancels any scheduled delayed work
2990 * and sets the bus vote based on ios argument.
2991 * If "ios" argument is NULL, bandwidth required is 0 else
2992 * calculate the bandwidth based on ios parameters.
2993 */
2994static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2995 struct msmsdcc_host *host,
2996 struct mmc_ios *ios)
2997{
2998 unsigned long flags;
2999 unsigned int bw;
3000 int vote;
3001
3002 if (!host->msm_bus_vote.client_handle)
3003 return;
3004
3005 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3006
3007 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3008 spin_lock_irqsave(&host->lock, flags);
3009 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3010 msmsdcc_msm_bus_set_vote(host, vote, flags);
3011 spin_unlock_irqrestore(&host->lock, flags);
3012}
3013
3014/* This function queues a work which will set the bandwidth requiement to 0 */
3015static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3016{
3017 unsigned long flags;
3018
3019 if (!host->msm_bus_vote.client_handle)
3020 return;
3021
3022 spin_lock_irqsave(&host->lock, flags);
3023 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3024 queue_delayed_work(system_nrt_wq,
3025 &host->msm_bus_vote.vote_work,
3026 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3027 spin_unlock_irqrestore(&host->lock, flags);
3028}
3029
San Mehat9d2bd732009-09-22 16:44:22 -07003030static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303031msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3032{
3033 struct mmc_host *mmc = host->mmc;
3034
3035 /*
3036 * SDIO_AL clients has different mechanism of handling LPM through
3037 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3038 * part of that. Here, we are interested only in clients like WLAN.
3039 */
3040 if (!(mmc->card && mmc_card_sdio(mmc->card))
3041 || host->plat->is_sdio_al_client)
3042 goto out;
3043
3044 if (!host->sdcc_suspended) {
3045 /*
3046 * When MSM is not in power collapse and we
3047 * are disabling clocks, enable bit 22 in MASK0
3048 * to handle asynchronous SDIO interrupts.
3049 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303050 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303051 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303052 mb();
3053 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303054 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303055 msmsdcc_sync_reg_wr(host);
3056 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303057 goto out;
3058 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3059 /*
3060 * Wakeup MSM only if SDIO function drivers set
3061 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3062 */
3063 goto out;
3064 }
3065
3066 if (enable_wakeup_irq) {
3067 if (!host->plat->sdiowakeup_irq) {
3068 /*
3069 * When there is no gpio line that can be configured
3070 * as wakeup interrupt handle it by configuring
3071 * asynchronous sdio interrupts and DAT1 line.
3072 */
3073 writel_relaxed(MCI_SDIOINTMASK,
3074 host->base + MMCIMASK0);
3075 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303076 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303077 /* configure sdcc core interrupt as wakeup interrupt */
3078 msmsdcc_enable_irq_wake(host);
3079 } else {
3080 /* Let gpio line handle wakeup interrupt */
3081 writel_relaxed(0, host->base + MMCIMASK0);
3082 mb();
3083 if (host->sdio_wakeupirq_disabled) {
3084 host->sdio_wakeupirq_disabled = 0;
3085 /* configure gpio line as wakeup interrupt */
3086 msmsdcc_enable_irq_wake(host);
3087 enable_irq(host->plat->sdiowakeup_irq);
3088 }
3089 }
3090 } else {
3091 if (!host->plat->sdiowakeup_irq) {
3092 /*
3093 * We may not have cleared bit 22 in the interrupt
3094 * handler as the clocks might be off at that time.
3095 */
3096 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303097 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303098 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303099 msmsdcc_disable_irq_wake(host);
3100 } else if (!host->sdio_wakeupirq_disabled) {
3101 disable_irq_nosync(host->plat->sdiowakeup_irq);
3102 msmsdcc_disable_irq_wake(host);
3103 host->sdio_wakeupirq_disabled = 1;
3104 }
3105 }
3106out:
3107 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003108}
3109
3110static void
3111msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3112{
3113 struct msmsdcc_host *host = mmc_priv(mmc);
3114 u32 clk = 0, pwr = 0;
3115 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003116 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003118
Sahitya Tummala7a892482011-01-18 11:22:49 +05303119
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303120 /*
3121 * Disable SDCC core interrupt until set_ios is completed.
3122 * This avoids any race conditions with interrupt raised
3123 * when turning on/off the clocks. One possible
3124 * scenario is SDIO operational interrupt while the clock
3125 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303126 * host->lock is being released intermittently below.
3127 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303128 */
3129
Asutosh Dasf5298c32012-04-03 14:51:47 +05303130 mutex_lock(&host->clk_mutex);
3131 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003132 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303133 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303134 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303135 host->sdcc_irq_disabled = 1;
3136 }
San Mehatd0719e52009-12-03 10:58:54 -08003137 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003138
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303139 /* Make sure sdcc core irq is synchronized */
3140 synchronize_irq(host->core_irqres->start);
3141
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303142 pwr = msmsdcc_setup_pwr(host, ios);
3143
3144 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003145 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303146 spin_unlock_irqrestore(&host->lock, flags);
3147 rc = msmsdcc_setup_clocks(host, true);
3148 if (rc)
3149 goto out;
3150 spin_lock_irqsave(&host->lock, flags);
3151 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3152 mb();
3153 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003156 /*
3157 * For DDR50 mode, controller needs clock rate to be
3158 * double than what is required on the SD card CLK pin.
3159 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303160 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161 /*
3162 * Make sure that we don't double the clock if
3163 * doubled clock rate is already set
3164 */
3165 if (!host->ddr_doubled_clk_rate ||
3166 (host->ddr_doubled_clk_rate &&
3167 (host->ddr_doubled_clk_rate != ios->clock))) {
3168 host->ddr_doubled_clk_rate =
3169 msmsdcc_get_sup_clk_rate(
3170 host, (ios->clock * 2));
3171 clock = host->ddr_doubled_clk_rate;
3172 }
3173 } else {
3174 host->ddr_doubled_clk_rate = 0;
3175 }
3176
3177 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303178 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003179 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303180 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303182 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003183 mmc_hostname(mmc), clock);
3184 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303185 host->reg_write_delay =
3186 (1 + ((3 * USEC_PER_SEC) /
3187 (host->clk_rate ? host->clk_rate :
3188 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003189 }
3190 /*
3191 * give atleast 2 MCLK cycles delay for clocks
3192 * and SDCC core to stabilize
3193 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303194 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003195 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003196 clk |= MCI_CLK_ENABLE;
3197 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003198 if (ios->bus_width == MMC_BUS_WIDTH_8)
3199 clk |= MCI_CLK_WIDEBUS_8;
3200 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3201 clk |= MCI_CLK_WIDEBUS_4;
3202 else
3203 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205 if (msmsdcc_is_pwrsave(host))
3206 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003210 host->tuning_needed = 0;
3211 /*
3212 * Select the controller timing mode according
3213 * to current bus speed mode
3214 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303215 if (host->clk_rate > (100 * 1000 * 1000) &&
3216 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3217 ios->timing == MMC_TIMING_MMC_HS200)) {
3218 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003219 clk |= (4 << 14);
3220 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303221 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 clk |= (3 << 14);
3223 } else {
3224 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003225 }
3226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3228 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003230 if (host->io_pad_pwr_switch)
3231 clk |= IO_PAD_PWR_SWITCH;
3232
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303233 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303234 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303235 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3236 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303237 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303239 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3240 host->pwr = pwr;
3241 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303242 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003243 }
San Mehat9d2bd732009-09-22 16:44:22 -07003244 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003245
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303246 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303247 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303248 spin_unlock_irqrestore(&host->lock, flags);
3249 /*
3250 * May get a wake-up interrupt the instant we disable the
3251 * clocks. This would disable the wake-up interrupt.
3252 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003253 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303254 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303256
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303257 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303258 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303259 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303260
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303261 /* Let interrupts be disabled if the host is powered off */
3262 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3263 enable_irq(host->core_irqres->start);
3264 host->sdcc_irq_disabled = 0;
3265 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003266 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303267out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303268 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003269}
3270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003271int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3272{
3273 struct msmsdcc_host *host = mmc_priv(mmc);
3274 u32 clk;
3275
3276 clk = readl_relaxed(host->base + MMCICLOCK);
3277 pr_debug("Changing to pwr_save=%d", pwrsave);
3278 if (pwrsave && msmsdcc_is_pwrsave(host))
3279 clk |= MCI_CLK_PWRSAVE;
3280 else
3281 clk &= ~MCI_CLK_PWRSAVE;
3282 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303283 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003284
3285 return 0;
3286}
3287
3288static int msmsdcc_get_ro(struct mmc_host *mmc)
3289{
3290 int status = -ENOSYS;
3291 struct msmsdcc_host *host = mmc_priv(mmc);
3292
3293 if (host->plat->wpswitch) {
3294 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303295 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003296 status = gpio_request(host->plat->wpswitch_gpio,
3297 "SD_WP_Switch");
3298 if (status) {
3299 pr_err("%s: %s: Failed to request GPIO %d\n",
3300 mmc_hostname(mmc), __func__,
3301 host->plat->wpswitch_gpio);
3302 } else {
3303 status = gpio_direction_input(
3304 host->plat->wpswitch_gpio);
3305 if (!status) {
3306 /*
3307 * Wait for atleast 300ms as debounce
3308 * time for GPIO input to stabilize.
3309 */
3310 msleep(300);
3311 status = gpio_get_value_cansleep(
3312 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303313 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 }
3315 gpio_free(host->plat->wpswitch_gpio);
3316 }
3317 }
3318
3319 if (status < 0)
3320 status = -ENOSYS;
3321 pr_debug("%s: Card read-only status %d\n", __func__, status);
3322
3323 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003324}
3325
3326static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3327{
3328 struct msmsdcc_host *host = mmc_priv(mmc);
3329 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303331 /*
3332 * We may come here with clocks turned off in that case don't
3333 * attempt to write into MASK0 register. While turning on the
3334 * clocks mci_irqenable will be written to MASK0 register.
3335 */
San Mehat9d2bd732009-09-22 16:44:22 -07003336
3337 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003338 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303340 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303341 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003342 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303343 mb();
3344 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345 } else {
3346 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303347 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303348 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303350 mb();
3351 }
San Mehat9d2bd732009-09-22 16:44:22 -07003352 }
3353 spin_unlock_irqrestore(&host->lock, flags);
3354}
3355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003356#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303357static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003358{
subhashj245831e2012-04-30 18:46:17 +05303359 struct device *dev = mmc_dev(host->mmc);
3360
Subhash Jadavani1371d192012-08-16 18:46:57 +05303361 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3362 mmc_hostname(host->mmc), host->sdcc_suspended,
3363 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303364 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3365 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3366 " request_pending=%d, request=%d\n",
3367 mmc_hostname(host->mmc), dev->power.runtime_status,
3368 atomic_read(&dev->power.usage_count),
3369 dev->power.is_suspended, dev->power.disable_depth,
3370 dev->power.runtime_error, dev->power.request_pending,
3371 dev->power.request);
3372}
3373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374static int msmsdcc_enable(struct mmc_host *mmc)
3375{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003376 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003378 struct msmsdcc_host *host = mmc_priv(mmc);
3379
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303380 msmsdcc_pm_qos_update_latency(host, 1);
3381
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003382 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303383 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003384
Subhash Jadavani1371d192012-08-16 18:46:57 +05303385 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003386 host->pending_resume = false;
3387 pm_runtime_get_noresume(dev);
3388 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303389 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003390 }
3391
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303392 if (dev->power.runtime_status == RPM_SUSPENDING) {
3393 if (mmc->suspend_task == current) {
3394 pm_runtime_get_noresume(dev);
3395 goto out;
3396 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303397 } else if (dev->power.runtime_status == RPM_RESUMING) {
3398 pm_runtime_get_noresume(dev);
3399 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303400 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303402 rc = pm_runtime_get_sync(dev);
3403
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303404skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303405 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303406 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3407 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303408 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303409 return rc;
3410 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303411out:
3412 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303413 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414}
3415
Steve Mucklef132c6c2012-06-06 18:30:57 -07003416static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417{
3418 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303419 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003420
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303421 msmsdcc_pm_qos_update_latency(host, 0);
3422
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303423 if (mmc->card && mmc_card_sdio(mmc->card)) {
3424 rc = 0;
3425 goto out;
3426 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303427
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303428 if (host->plat->disable_runtime_pm)
3429 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003430
3431 rc = pm_runtime_put_sync(mmc->parent);
3432
Subhash Jadavani1371d192012-08-16 18:46:57 +05303433 if (rc < 0) {
3434 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3435 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303436 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003437 return rc;
3438 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303439
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303440out:
3441 msmsdcc_msm_bus_queue_work(host);
3442 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443}
3444#else
subhashj245831e2012-04-30 18:46:17 +05303445static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3446
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303447static int msmsdcc_enable(struct mmc_host *mmc)
3448{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003449 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303450 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303451 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303452
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303453 msmsdcc_pm_qos_update_latency(host, 1);
3454
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303455 if (mmc->card && mmc_card_sdio(mmc->card)) {
3456 rc = 0;
3457 goto out;
3458 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003459
3460 if (host->sdcc_suspended && host->pending_resume) {
3461 host->pending_resume = false;
3462 rc = msmsdcc_runtime_resume(dev);
3463 goto out;
3464 }
3465
Asutosh Dasf5298c32012-04-03 14:51:47 +05303466 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303467 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303468 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303469
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003470out:
3471 if (rc < 0) {
3472 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3473 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303474 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003475 return rc;
3476 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303477 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303478 return 0;
3479}
3480
Steve Mucklef132c6c2012-06-06 18:30:57 -07003481static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303482{
3483 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303484 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303485
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303486 msmsdcc_pm_qos_update_latency(host, 0);
3487
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303488 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303489 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303490
Asutosh Dasf5298c32012-04-03 14:51:47 +05303491 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303492 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303493 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303494
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303495 if (rc) {
3496 msmsdcc_pm_qos_update_latency(host, 1);
3497 return rc;
3498 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303499out:
3500 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303501 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303502}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503#endif
3504
Subhash Jadavani937c7502012-06-01 15:34:46 +05303505static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3506 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003507{
3508 struct msmsdcc_host *host = mmc_priv(mmc);
3509 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303510 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511
Subhash Jadavani937c7502012-06-01 15:34:46 +05303512 switch (ios->signal_voltage) {
3513 case MMC_SIGNAL_VOLTAGE_330:
3514 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3515 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303516 if (!rc)
3517 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303518 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303519 case MMC_SIGNAL_VOLTAGE_180:
3520 break;
3521 case MMC_SIGNAL_VOLTAGE_120:
3522 /*
3523 * For eMMC cards, VDD_IO voltage range must be changed
3524 * only if it operates in HS200 SDR 1.2V mode or in
3525 * DDR 1.2V mode.
3526 */
3527 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303528 if (!rc)
3529 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303531 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003532 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303533 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003534 goto out;
3535 }
San Mehat9d2bd732009-09-22 16:44:22 -07003536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003537 /*
3538 * If we are here means voltage switch from high voltage to
3539 * low voltage is required
3540 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303541 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542
3543 /*
3544 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3545 * register until they become all zeros.
3546 */
3547 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303548 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3550 mmc_hostname(mmc), __func__);
3551 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003552 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003553
3554 /* Stop SD CLK output. */
3555 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3556 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303557 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003558 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003559
3560 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303561 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3562 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003563 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303564 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303565 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303568 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003569
3570 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3571 usleep_range(5000, 5500);
3572
3573 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303574 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003575 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3576 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303577 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578 spin_unlock_irqrestore(&host->lock, flags);
3579
3580 /*
3581 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3582 * don't become all ones within 1 ms then a Voltage Switch
3583 * sequence has failed and a power cycle to the card is required.
3584 * Otherwise Voltage Switch sequence is completed successfully.
3585 */
3586 usleep_range(1000, 1500);
3587
3588 spin_lock_irqsave(&host->lock, flags);
3589 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3590 != (0xF << 1)) {
3591 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3592 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303593 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003594 goto out_unlock;
3595 }
3596
3597out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303598 /* Enable PWRSAVE */
3599 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3600 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303601 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 spin_unlock_irqrestore(&host->lock, flags);
3603out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303604 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605}
3606
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303607static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610
3611 /* Program the MCLK value to MCLK_FREQ bit field */
3612 if (host->clk_rate <= 112000000)
3613 mclk_freq = 0;
3614 else if (host->clk_rate <= 125000000)
3615 mclk_freq = 1;
3616 else if (host->clk_rate <= 137000000)
3617 mclk_freq = 2;
3618 else if (host->clk_rate <= 150000000)
3619 mclk_freq = 3;
3620 else if (host->clk_rate <= 162000000)
3621 mclk_freq = 4;
3622 else if (host->clk_rate <= 175000000)
3623 mclk_freq = 5;
3624 else if (host->clk_rate <= 187000000)
3625 mclk_freq = 6;
3626 else if (host->clk_rate <= 200000000)
3627 mclk_freq = 7;
3628
3629 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3630 & ~(7 << 24)) | (mclk_freq << 24)),
3631 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632}
3633
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303634/* Initialize the DLL (Programmable Delay Line ) */
3635static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003637 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303638 unsigned long flags;
3639 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003640
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003642 /*
3643 * Make sure that clock is always enabled when DLL
3644 * tuning is in progress. Keeping PWRSAVE ON may
3645 * turn off the clock. So let's disable the PWRSAVE
3646 * here and re-enable it once tuning is completed.
3647 */
3648 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3649 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303650 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303651
3652 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3653 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3654 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3655
3656 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3657 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3658 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3659
3660 msmsdcc_cm_sdc4_dll_set_freq(host);
3661
3662 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3663 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3664 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3665
3666 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3667 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3668 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3669
3670 /* Set DLL_EN bit to 1. */
3671 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3672 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3673
3674 /* Set CK_OUT_EN bit to 1. */
3675 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3676 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3677
3678 wait_cnt = 50;
3679 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3680 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3681 /* max. wait for 50us sec for LOCK bit to be set */
3682 if (--wait_cnt == 0) {
3683 pr_err("%s: %s: DLL failed to LOCK\n",
3684 mmc_hostname(host->mmc), __func__);
3685 rc = -ETIMEDOUT;
3686 goto out;
3687 }
3688 /* wait for 1us before polling again */
3689 udelay(1);
3690 }
3691
3692out:
3693 /* re-enable PWRSAVE */
3694 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3695 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303696 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303697 spin_unlock_irqrestore(&host->lock, flags);
3698
3699 return rc;
3700}
3701
3702static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3703 u8 poll)
3704{
3705 int rc = 0;
3706 u32 wait_cnt = 50;
3707 u8 ck_out_en = 0;
3708
3709 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3710 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3711 MCI_CK_OUT_EN);
3712
3713 while (ck_out_en != poll) {
3714 if (--wait_cnt == 0) {
3715 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3716 mmc_hostname(host->mmc), __func__, poll);
3717 rc = -ETIMEDOUT;
3718 goto out;
3719 }
3720 udelay(1);
3721
3722 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3723 MCI_CK_OUT_EN);
3724 }
3725out:
3726 return rc;
3727}
3728
3729/*
3730 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3731 * calibration sequence. This function should be called before
3732 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3733 * commands (CMD17/CMD18).
3734 *
3735 * This function gets called when host spinlock acquired.
3736 */
3737static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3738{
3739 int rc = 0;
3740 u32 config;
3741
3742 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3743 config |= MCI_CDR_EN;
3744 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3745 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3746
3747 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3748 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3749 if (rc)
3750 goto err_out;
3751
3752 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3753 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3754 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3755
3756 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3757 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3758 if (rc)
3759 goto err_out;
3760
3761 goto out;
3762
3763err_out:
3764 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3765out:
3766 return rc;
3767}
3768
3769static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3770 u8 phase)
3771{
3772 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303773 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3774 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3775 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303776 unsigned long flags;
3777 u32 config;
3778
3779 spin_lock_irqsave(&host->lock, flags);
3780
3781 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3782 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3783 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3784 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3785
3786 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3787 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3788 if (rc)
3789 goto err_out;
3790
3791 /*
3792 * Write the selected DLL clock output phase (0 ... 15)
3793 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3794 */
3795 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3796 & ~(0xF << 20))
3797 | (grey_coded_phase_table[phase] << 20)),
3798 host->base + MCI_DLL_CONFIG);
3799
3800 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3801 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3802 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3803
3804 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3805 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3806 if (rc)
3807 goto err_out;
3808
3809 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3810 config |= MCI_CDR_EN;
3811 config &= ~MCI_CDR_EXT_EN;
3812 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3813 goto out;
3814
3815err_out:
3816 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3817 mmc_hostname(host->mmc), __func__, phase);
3818out:
3819 spin_unlock_irqrestore(&host->lock, flags);
3820 return rc;
3821}
3822
3823/*
3824 * Find out the greatest range of consecuitive selected
3825 * DLL clock output phases that can be used as sampling
3826 * setting for SD3.0 UHS-I card read operation (in SDR104
3827 * timing mode) or for eMMC4.5 card read operation (in HS200
3828 * timing mode).
3829 * Select the 3/4 of the range and configure the DLL with the
3830 * selected DLL clock output phase.
3831*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303832static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303833 u8 *phase_table, u8 total_phases)
3834{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303835 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303836 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303837 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3838 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303839 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303840 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3841 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303842
Subhash Jadavani6159c622012-03-15 19:05:55 +05303843 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303844 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3845 mmc_hostname(host->mmc), __func__, total_phases);
3846 return -EINVAL;
3847 }
3848
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303849 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303850 ranges[row_index][col_index] = phase_table[cnt];
3851 phases_per_row[row_index] += 1;
3852 col_index++;
3853
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303854 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303855 continue;
3856 /* check if next phase in phase_table is consecutive or not */
3857 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3858 row_index++;
3859 col_index = 0;
3860 }
3861 }
3862
Subhash Jadavani6159c622012-03-15 19:05:55 +05303863 if (row_index >= MAX_PHASES)
3864 return -EINVAL;
3865
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303866 /* Check if phase-0 is present in first valid window? */
3867 if (!ranges[0][0]) {
3868 phase_0_found = true;
3869 phase_0_raw_index = 0;
3870 /* Check if cycle exist between 2 valid windows */
3871 for (cnt = 1; cnt <= row_index; cnt++) {
3872 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303873 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303874 if (ranges[cnt][i] == 15) {
3875 phase_15_found = true;
3876 phase_15_raw_index = cnt;
3877 break;
3878 }
3879 }
3880 }
3881 }
3882 }
3883
3884 /* If 2 valid windows form cycle then merge them as single window */
3885 if (phase_0_found && phase_15_found) {
3886 /* number of phases in raw where phase 0 is present */
3887 u8 phases_0 = phases_per_row[phase_0_raw_index];
3888 /* number of phases in raw where phase 15 is present */
3889 u8 phases_15 = phases_per_row[phase_15_raw_index];
3890
Subhash Jadavani6159c622012-03-15 19:05:55 +05303891 if (phases_0 + phases_15 >= MAX_PHASES)
3892 /*
3893 * If there are more than 1 phase windows then total
3894 * number of phases in both the windows should not be
3895 * more than or equal to MAX_PHASES.
3896 */
3897 return -EINVAL;
3898
3899 /* Merge 2 cyclic windows */
3900 i = phases_15;
3901 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303902 ranges[phase_15_raw_index][i] =
3903 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303904 if (++i >= MAX_PHASES)
3905 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303906 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303907
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303908 phases_per_row[phase_0_raw_index] = 0;
3909 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3910 }
3911
3912 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303913 if (phases_per_row[cnt] > curr_max) {
3914 curr_max = phases_per_row[cnt];
3915 selected_row_index = cnt;
3916 }
3917 }
3918
Subhash Jadavani6159c622012-03-15 19:05:55 +05303919 i = ((curr_max * 3) / 4);
3920 if (i)
3921 i--;
3922
Subhash Jadavani34187042012-03-02 10:59:49 +05303923 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303924
Subhash Jadavani6159c622012-03-15 19:05:55 +05303925 if (ret >= MAX_PHASES) {
3926 ret = -EINVAL;
3927 pr_err("%s: %s: invalid phase selected=%d\n",
3928 mmc_hostname(host->mmc), __func__, ret);
3929 }
3930
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303931 return ret;
3932}
3933
Girish K Sa3f41692012-02-29 12:00:09 +05303934static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303935{
3936 int rc = 0;
3937 struct msmsdcc_host *host = mmc_priv(mmc);
3938 unsigned long flags;
3939 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303940 const u32 *tuning_block_pattern = tuning_block_64;
3941 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303942
3943 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3944
3945 /* Tuning is only required for SDR104 modes */
3946 if (!host->tuning_needed) {
3947 rc = 0;
3948 goto exit;
3949 }
3950
3951 spin_lock_irqsave(&host->lock, flags);
3952 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303953 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303954 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3955
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303956 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303957 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3958 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3959 tuning_block_pattern = tuning_block_128;
3960 size = sizeof(tuning_block_128);
3961 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303962 spin_unlock_irqrestore(&host->lock, flags);
3963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003964 /* first of all reset the tuning block */
3965 rc = msmsdcc_init_cm_sdc4_dll(host);
3966 if (rc)
3967 goto out;
3968
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303969 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970 if (!data_buf) {
3971 rc = -ENOMEM;
3972 goto out;
3973 }
3974
3975 phase = 0;
3976 do {
3977 struct mmc_command cmd = {0};
3978 struct mmc_data data = {0};
3979 struct mmc_request mrq = {
3980 .cmd = &cmd,
3981 .data = &data
3982 };
3983 struct scatterlist sg;
3984
3985 /* set the phase in delay line hw block */
3986 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3987 if (rc)
3988 goto kfree;
3989
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303990 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003991 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3992
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303993 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003994 data.blocks = 1;
3995 data.flags = MMC_DATA_READ;
3996 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3997
3998 data.sg = &sg;
3999 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304000 sg_init_one(&sg, data_buf, size);
4001 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004002 mmc_wait_for_req(mmc, &mrq);
4003
4004 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304005 !memcmp(data_buf, tuning_block_pattern, size)) {
4006 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304008 pr_debug("%s: %s: found good phase = %d\n",
4009 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 }
4011 } while (++phase < 16);
4012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004013 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304014 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304015 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304016 if (rc < 0)
4017 goto kfree;
4018 else
4019 phase = (u8)rc;
4020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 /*
4022 * Finally set the selected phase in delay
4023 * line hw block.
4024 */
4025 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4026 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304027 goto kfree;
4028 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4029 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 } else {
4031 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304032 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304034 msmsdcc_dump_sdcc_state(host);
4035 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004037
4038kfree:
4039 kfree(data_buf);
4040out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304041 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304042 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304043 spin_unlock_irqrestore(&host->lock, flags);
4044exit:
4045 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004046 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004047}
4048
Asutosh Dasebd7d092012-07-09 19:08:26 +05304049/*
4050 * Work around of the unavailability of a power_reset functionality in SD cards
4051 * by turning the OFF & back ON the regulators supplying the SD card.
4052 */
4053void msmsdcc_hw_reset(struct mmc_host *mmc)
4054{
4055 struct mmc_card *card = mmc->card;
4056 struct msmsdcc_host *host = mmc_priv(mmc);
4057 int rc;
4058
4059 /* Write-protection bits would be lost on a hardware reset in emmc */
4060 if (!card || !mmc_card_sd(card))
4061 return;
4062
4063 /*
4064 * Continuing on failing to disable regulator would lead to a panic
4065 * anyway, since the commands would fail and console would be flooded
4066 * with prints, eventually leading to a watchdog bark
4067 */
4068 rc = msmsdcc_setup_vreg(host, false, false);
4069 if (rc) {
4070 pr_err("%s: %s disable regulator: failed: %d\n",
4071 mmc_hostname(mmc), __func__, rc);
4072 BUG_ON(rc);
4073 }
4074
4075 /* 10ms delay for the supply to reach the desired voltage level */
4076 usleep_range(10000, 12000);
4077
4078 /*
4079 * Continuing on failing to enable regulator would lead to a panic
4080 * anyway, since the commands would fail and console would be flooded
4081 * with prints, eventually leading to a watchdog bark
4082 */
4083 rc = msmsdcc_setup_vreg(host, true, false);
4084 if (rc) {
4085 pr_err("%s: %s enable regulator: failed: %d\n",
4086 mmc_hostname(mmc), __func__, rc);
4087 BUG_ON(rc);
4088 }
4089
4090 /* 10ms delay for the supply to reach the desired voltage level */
4091 usleep_range(10000, 12000);
4092}
4093
San Mehat9d2bd732009-09-22 16:44:22 -07004094static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004095 .enable = msmsdcc_enable,
4096 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304097 .pre_req = msmsdcc_pre_req,
4098 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004099 .request = msmsdcc_request,
4100 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004101 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004102 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304103 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304104 .execute_tuning = msmsdcc_execute_tuning,
4105 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004106};
4107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108static unsigned int
4109msmsdcc_slot_status(struct msmsdcc_host *host)
4110{
4111 int status;
4112 unsigned int gpio_no = host->plat->status_gpio;
4113
4114 status = gpio_request(gpio_no, "SD_HW_Detect");
4115 if (status) {
4116 pr_err("%s: %s: Failed to request GPIO %d\n",
4117 mmc_hostname(host->mmc), __func__, gpio_no);
4118 } else {
4119 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004120 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004121 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004122 if (host->plat->is_status_gpio_active_low)
4123 status = !status;
4124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 gpio_free(gpio_no);
4126 }
4127 return status;
4128}
4129
San Mehat9d2bd732009-09-22 16:44:22 -07004130static void
4131msmsdcc_check_status(unsigned long data)
4132{
4133 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4134 unsigned int status;
4135
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304136 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004137 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004139 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 status = msmsdcc_slot_status(host);
4141
Krishna Konda941604a2012-01-10 17:46:34 -08004142 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004144 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004145 if (host->plat->status)
4146 pr_info("%s: Slot status change detected "
4147 "(%d -> %d)\n",
4148 mmc_hostname(host->mmc),
4149 host->oldstat, status);
4150 else if (host->plat->is_status_gpio_active_low)
4151 pr_info("%s: Slot status change detected "
4152 "(%d -> %d) and the card detect GPIO"
4153 " is ACTIVE_LOW\n",
4154 mmc_hostname(host->mmc),
4155 host->oldstat, status);
4156 else
4157 pr_info("%s: Slot status change detected "
4158 "(%d -> %d) and the card detect GPIO"
4159 " is ACTIVE_HIGH\n",
4160 mmc_hostname(host->mmc),
4161 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004162 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163 }
4164 host->oldstat = status;
4165 } else {
4166 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004167 }
San Mehat9d2bd732009-09-22 16:44:22 -07004168}
4169
4170static irqreturn_t
4171msmsdcc_platform_status_irq(int irq, void *dev_id)
4172{
4173 struct msmsdcc_host *host = dev_id;
4174
Girish K Sa3c76eb2011-10-11 11:44:09 +05304175 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004176 msmsdcc_check_status((unsigned long) host);
4177 return IRQ_HANDLED;
4178}
4179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004180static irqreturn_t
4181msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4182{
4183 struct msmsdcc_host *host = dev_id;
4184
4185 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4186 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304187 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304189 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190 wake_lock(&host->sdio_wlock);
4191 msmsdcc_disable_irq_wake(host);
4192 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304193 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194 }
4195 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304197 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304198 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304199 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 }
4201 spin_unlock(&host->lock);
4202
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304203out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004204 return IRQ_HANDLED;
4205}
4206
San Mehat9d2bd732009-09-22 16:44:22 -07004207static void
4208msmsdcc_status_notify_cb(int card_present, void *dev_id)
4209{
4210 struct msmsdcc_host *host = dev_id;
4211
Girish K Sa3c76eb2011-10-11 11:44:09 +05304212 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004213 card_present);
4214 msmsdcc_check_status((unsigned long) host);
4215}
4216
San Mehat9d2bd732009-09-22 16:44:22 -07004217static int
4218msmsdcc_init_dma(struct msmsdcc_host *host)
4219{
4220 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4221 host->dma.host = host;
4222 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004223 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004224
4225 if (!host->dmares)
4226 return -ENODEV;
4227
4228 host->dma.nc = dma_alloc_coherent(NULL,
4229 sizeof(struct msmsdcc_nc_dmadata),
4230 &host->dma.nc_busaddr,
4231 GFP_KERNEL);
4232 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004233 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004234 return -ENOMEM;
4235 }
4236 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4237 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4238 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4239 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4240 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004241 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004242
4243 return 0;
4244}
4245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004246#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4247/**
4248 * Allocate and Connect a SDCC peripheral's SPS endpoint
4249 *
4250 * This function allocates endpoint context and
4251 * connect it with memory endpoint by calling
4252 * appropriate SPS driver APIs.
4253 *
4254 * Also registers a SPS callback function with
4255 * SPS driver
4256 *
4257 * This function should only be called once typically
4258 * during driver probe.
4259 *
4260 * @host - Pointer to sdcc host structure
4261 * @ep - Pointer to sps endpoint data structure
4262 * @is_produce - 1 means Producer endpoint
4263 * 0 means Consumer endpoint
4264 *
4265 * @return - 0 if successful else negative value.
4266 *
4267 */
4268static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4269 struct msmsdcc_sps_ep_conn_data *ep,
4270 bool is_producer)
4271{
4272 int rc = 0;
4273 struct sps_pipe *sps_pipe_handle;
4274 struct sps_connect *sps_config = &ep->config;
4275 struct sps_register_event *sps_event = &ep->event;
4276
4277 /* Allocate endpoint context */
4278 sps_pipe_handle = sps_alloc_endpoint();
4279 if (!sps_pipe_handle) {
4280 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4281 mmc_hostname(host->mmc), is_producer);
4282 rc = -ENOMEM;
4283 goto out;
4284 }
4285
4286 /* Get default connection configuration for an endpoint */
4287 rc = sps_get_config(sps_pipe_handle, sps_config);
4288 if (rc) {
4289 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4290 " rc=%d", mmc_hostname(host->mmc),
4291 (u32)sps_pipe_handle, rc);
4292 goto get_config_err;
4293 }
4294
4295 /* Modify the default connection configuration */
4296 if (is_producer) {
4297 /*
4298 * For SDCC producer transfer, source should be
4299 * SDCC peripheral where as destination should
4300 * be system memory.
4301 */
4302 sps_config->source = host->sps.bam_handle;
4303 sps_config->destination = SPS_DEV_HANDLE_MEM;
4304 /* Producer pipe will handle this connection */
4305 sps_config->mode = SPS_MODE_SRC;
4306 sps_config->options =
4307 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4308 } else {
4309 /*
4310 * For SDCC consumer transfer, source should be
4311 * system memory where as destination should
4312 * SDCC peripheral
4313 */
4314 sps_config->source = SPS_DEV_HANDLE_MEM;
4315 sps_config->destination = host->sps.bam_handle;
4316 sps_config->mode = SPS_MODE_DEST;
4317 sps_config->options =
4318 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4319 }
4320
4321 /* Producer pipe index */
4322 sps_config->src_pipe_index = host->sps.src_pipe_index;
4323 /* Consumer pipe index */
4324 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4325 /*
4326 * This event thresold value is only significant for BAM-to-BAM
4327 * transfer. It's ignored for BAM-to-System mode transfer.
4328 */
4329 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304330
4331 /* Allocate maximum descriptor fifo size */
4332 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4333 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4335 sps_config->desc.size,
4336 &sps_config->desc.phys_base,
4337 GFP_KERNEL);
4338
Pratibhasagar V00b94332011-10-18 14:57:27 +05304339 if (!sps_config->desc.base) {
4340 rc = -ENOMEM;
4341 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4342 , mmc_hostname(host->mmc));
4343 goto get_config_err;
4344 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4346
4347 /* Establish connection between peripheral and memory endpoint */
4348 rc = sps_connect(sps_pipe_handle, sps_config);
4349 if (rc) {
4350 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4351 " rc=%d", mmc_hostname(host->mmc),
4352 (u32)sps_pipe_handle, rc);
4353 goto sps_connect_err;
4354 }
4355
4356 sps_event->mode = SPS_TRIGGER_CALLBACK;
4357 sps_event->options = SPS_O_EOT;
4358 sps_event->callback = msmsdcc_sps_complete_cb;
4359 sps_event->xfer_done = NULL;
4360 sps_event->user = (void *)host;
4361
4362 /* Register callback event for EOT (End of transfer) event. */
4363 rc = sps_register_event(sps_pipe_handle, sps_event);
4364 if (rc) {
4365 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4366 " rc=%d", mmc_hostname(host->mmc),
4367 (u32)sps_pipe_handle, rc);
4368 goto reg_event_err;
4369 }
4370 /* Now save the sps pipe handle */
4371 ep->pipe_handle = sps_pipe_handle;
4372 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4373 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4374 __func__, is_producer ? "READ" : "WRITE",
4375 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4376 goto out;
4377
4378reg_event_err:
4379 sps_disconnect(sps_pipe_handle);
4380sps_connect_err:
4381 dma_free_coherent(mmc_dev(host->mmc),
4382 sps_config->desc.size,
4383 sps_config->desc.base,
4384 sps_config->desc.phys_base);
4385get_config_err:
4386 sps_free_endpoint(sps_pipe_handle);
4387out:
4388 return rc;
4389}
4390
4391/**
4392 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4393 *
4394 * This function disconnect endpoint and deallocates
4395 * endpoint context.
4396 *
4397 * This function should only be called once typically
4398 * during driver remove.
4399 *
4400 * @host - Pointer to sdcc host structure
4401 * @ep - Pointer to sps endpoint data structure
4402 *
4403 */
4404static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4405 struct msmsdcc_sps_ep_conn_data *ep)
4406{
4407 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4408 struct sps_connect *sps_config = &ep->config;
4409 struct sps_register_event *sps_event = &ep->event;
4410
4411 sps_event->xfer_done = NULL;
4412 sps_event->callback = NULL;
4413 sps_register_event(sps_pipe_handle, sps_event);
4414 sps_disconnect(sps_pipe_handle);
4415 dma_free_coherent(mmc_dev(host->mmc),
4416 sps_config->desc.size,
4417 sps_config->desc.base,
4418 sps_config->desc.phys_base);
4419 sps_free_endpoint(sps_pipe_handle);
4420}
4421
4422/**
4423 * Reset SDCC peripheral's SPS endpoint
4424 *
4425 * This function disconnects an endpoint.
4426 *
4427 * This function should be called for reseting
4428 * SPS endpoint when data transfer error is
4429 * encountered during data transfer. This
4430 * can be considered as soft reset to endpoint.
4431 *
4432 * This function should only be called if
4433 * msmsdcc_sps_init() is already called.
4434 *
4435 * @host - Pointer to sdcc host structure
4436 * @ep - Pointer to sps endpoint data structure
4437 *
4438 * @return - 0 if successful else negative value.
4439 */
4440static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4441 struct msmsdcc_sps_ep_conn_data *ep)
4442{
4443 int rc = 0;
4444 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4445
4446 rc = sps_disconnect(sps_pipe_handle);
4447 if (rc) {
4448 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4449 " rc=%d", mmc_hostname(host->mmc), __func__,
4450 (u32)sps_pipe_handle, rc);
4451 goto out;
4452 }
4453 out:
4454 return rc;
4455}
4456
4457/**
4458 * Restore SDCC peripheral's SPS endpoint
4459 *
4460 * This function connects an endpoint.
4461 *
4462 * This function should be called for restoring
4463 * SPS endpoint after data transfer error is
4464 * encountered during data transfer. This
4465 * can be considered as soft reset to endpoint.
4466 *
4467 * This function should only be called if
4468 * msmsdcc_sps_reset_ep() is called before.
4469 *
4470 * @host - Pointer to sdcc host structure
4471 * @ep - Pointer to sps endpoint data structure
4472 *
4473 * @return - 0 if successful else negative value.
4474 */
4475static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4476 struct msmsdcc_sps_ep_conn_data *ep)
4477{
4478 int rc = 0;
4479 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4480 struct sps_connect *sps_config = &ep->config;
4481 struct sps_register_event *sps_event = &ep->event;
4482
4483 /* Establish connection between peripheral and memory endpoint */
4484 rc = sps_connect(sps_pipe_handle, sps_config);
4485 if (rc) {
4486 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4487 " rc=%d", mmc_hostname(host->mmc), __func__,
4488 (u32)sps_pipe_handle, rc);
4489 goto out;
4490 }
4491
4492 /* Register callback event for EOT (End of transfer) event. */
4493 rc = sps_register_event(sps_pipe_handle, sps_event);
4494 if (rc) {
4495 pr_err("%s: %s: sps_register_event() failed!!!"
4496 " pipe_handle=0x%x, rc=%d",
4497 mmc_hostname(host->mmc), __func__,
4498 (u32)sps_pipe_handle, rc);
4499 goto reg_event_err;
4500 }
4501 goto out;
4502
4503reg_event_err:
4504 sps_disconnect(sps_pipe_handle);
4505out:
4506 return rc;
4507}
4508
4509/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004510 * Handle BAM device's global error condition
4511 *
4512 * This is an error handler for the SDCC bam device
4513 *
4514 * This function is registered as a callback with SPS-BAM
4515 * driver and will called in case there are an errors for
4516 * the SDCC BAM deivce. Any error conditions in the BAM
4517 * device are global and will be result in this function
4518 * being called once per device.
4519 *
4520 * This function will be called from the sps driver's
4521 * interrupt context.
4522 *
4523 * @sps_cb_case - indicates what error it is
4524 * @user - Pointer to sdcc host structure
4525 */
4526static void
4527msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4528{
4529 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4530 struct mmc_request *mrq;
4531 unsigned long flags;
4532 int32_t error = 0;
4533
4534 BUG_ON(!host);
4535 BUG_ON(!is_sps_mode(host));
4536
4537 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4538 /**
4539 * Reset the all endpoints along with reseting the sps device.
4540 */
4541 host->sps.pipe_reset_pending = true;
4542 host->sps.reset_device = true;
4543
4544 pr_err("%s: BAM Global ERROR IRQ happened\n",
4545 mmc_hostname(host->mmc));
4546 error = EAGAIN;
4547 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4548 /**
4549 * This means that there was an AHB access error and
4550 * the address we are trying to read/write is something
4551 * we dont have priviliges to do so.
4552 */
4553 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4554 mmc_hostname(host->mmc));
4555 error = EACCES;
4556 } else {
4557 /**
4558 * This should not have happened ideally. If this happens
4559 * there is some seriously wrong.
4560 */
4561 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4562 mmc_hostname(host->mmc), (u32) sps_cb_case);
4563 error = EIO;
4564 }
4565
4566 spin_lock_irqsave(&host->lock, flags);
4567
4568 mrq = host->curr.mrq;
4569
4570 if (mrq && mrq->cmd) {
4571 msmsdcc_dump_sdcc_state(host);
4572
4573 if (!mrq->cmd->error)
4574 mrq->cmd->error = -error;
4575 if (host->curr.data) {
4576 if (mrq->data && !mrq->data->error)
4577 mrq->data->error = -error;
4578 host->curr.data_xfered = 0;
4579 if (host->sps.sg && is_sps_mode(host)) {
4580 /* Stop current SPS transfer */
4581 msmsdcc_sps_exit_curr_xfer(host);
4582 } else {
4583 /* this condition should not have happened */
4584 pr_err("%s: something is seriously wrong. "\
4585 "Funtion: %s, line: %d\n",
4586 mmc_hostname(host->mmc),
4587 __func__, __LINE__);
4588 }
4589 } else {
4590 /* this condition should not have happened */
4591 pr_err("%s: something is seriously wrong. Funtion: "\
4592 "%s, line: %d\n", mmc_hostname(host->mmc),
4593 __func__, __LINE__);
4594 }
4595 }
4596 spin_unlock_irqrestore(&host->lock, flags);
4597}
4598
4599/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004600 * Initialize SPS HW connected with SDCC core
4601 *
4602 * This function register BAM HW resources with
4603 * SPS driver and then initialize 2 SPS endpoints
4604 *
4605 * This function should only be called once typically
4606 * during driver probe.
4607 *
4608 * @host - Pointer to sdcc host structure
4609 *
4610 * @return - 0 if successful else negative value.
4611 *
4612 */
4613static int msmsdcc_sps_init(struct msmsdcc_host *host)
4614{
4615 int rc = 0;
4616 struct sps_bam_props bam = {0};
4617
4618 host->bam_base = ioremap(host->bam_memres->start,
4619 resource_size(host->bam_memres));
4620 if (!host->bam_base) {
4621 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4622 " size=0x%x", mmc_hostname(host->mmc),
4623 host->bam_memres->start,
4624 (host->bam_memres->end -
4625 host->bam_memres->start));
4626 rc = -ENOMEM;
4627 goto out;
4628 }
4629
4630 bam.phys_addr = host->bam_memres->start;
4631 bam.virt_addr = host->bam_base;
4632 /*
4633 * This event thresold value is only significant for BAM-to-BAM
4634 * transfer. It's ignored for BAM-to-System mode transfer.
4635 */
4636 bam.event_threshold = 0x10; /* Pipe event threshold */
4637 /*
4638 * This threshold controls when the BAM publish
4639 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304640 * SPS HW will be used for data transfer size even
4641 * less than SDCC FIFO size. So let's set BAM summing
4642 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004643 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304644 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004645 /* SPS driver wll handle the SDCC BAM IRQ */
4646 bam.irq = (u32)host->bam_irqres->start;
4647 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004648 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4649 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004650
4651 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4652 (u32)bam.phys_addr);
4653 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4654 (u32)bam.virt_addr);
4655
4656 /* Register SDCC Peripheral BAM device to SPS driver */
4657 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4658 if (rc) {
4659 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4660 mmc_hostname(host->mmc), rc);
4661 goto reg_bam_err;
4662 }
4663 pr_info("%s: BAM device registered. bam_handle=0x%x",
4664 mmc_hostname(host->mmc), host->sps.bam_handle);
4665
4666 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4667 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4668
4669 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4670 SPS_PROD_PERIPHERAL);
4671 if (rc)
4672 goto sps_reset_err;
4673 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4674 SPS_CONS_PERIPHERAL);
4675 if (rc)
4676 goto cons_conn_err;
4677
4678 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4679 mmc_hostname(host->mmc),
4680 (unsigned long long)host->bam_memres->start,
4681 (unsigned int)host->bam_irqres->start);
4682 goto out;
4683
4684cons_conn_err:
4685 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4686sps_reset_err:
4687 sps_deregister_bam_device(host->sps.bam_handle);
4688reg_bam_err:
4689 iounmap(host->bam_base);
4690out:
4691 return rc;
4692}
4693
4694/**
4695 * De-initialize SPS HW connected with SDCC core
4696 *
4697 * This function deinitialize SPS endpoints and then
4698 * deregisters BAM resources from SPS driver.
4699 *
4700 * This function should only be called once typically
4701 * during driver remove.
4702 *
4703 * @host - Pointer to sdcc host structure
4704 *
4705 */
4706static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4707{
4708 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4709 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4710 sps_deregister_bam_device(host->sps.bam_handle);
4711 iounmap(host->bam_base);
4712}
4713#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4714
4715static ssize_t
4716show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4717{
4718 struct mmc_host *mmc = dev_get_drvdata(dev);
4719 struct msmsdcc_host *host = mmc_priv(mmc);
4720 int poll;
4721 unsigned long flags;
4722
4723 spin_lock_irqsave(&host->lock, flags);
4724 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4725 spin_unlock_irqrestore(&host->lock, flags);
4726
4727 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4728}
4729
4730static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304731store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004732 const char *buf, size_t count)
4733{
4734 struct mmc_host *mmc = dev_get_drvdata(dev);
4735 struct msmsdcc_host *host = mmc_priv(mmc);
4736 int value;
4737 unsigned long flags;
4738
4739 sscanf(buf, "%d", &value);
4740
4741 spin_lock_irqsave(&host->lock, flags);
4742 if (value) {
4743 mmc->caps |= MMC_CAP_NEEDS_POLL;
4744 mmc_detect_change(host->mmc, 0);
4745 } else {
4746 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4747 }
4748#ifdef CONFIG_HAS_EARLYSUSPEND
4749 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4750#endif
4751 spin_unlock_irqrestore(&host->lock, flags);
4752 return count;
4753}
4754
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304755static ssize_t
4756show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4757 char *buf)
4758{
4759 struct mmc_host *mmc = dev_get_drvdata(dev);
4760 struct msmsdcc_host *host = mmc_priv(mmc);
4761
4762 return snprintf(buf, PAGE_SIZE, "%u\n",
4763 host->msm_bus_vote.is_max_bw_needed);
4764}
4765
4766static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304767store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304768 const char *buf, size_t count)
4769{
4770 struct mmc_host *mmc = dev_get_drvdata(dev);
4771 struct msmsdcc_host *host = mmc_priv(mmc);
4772 uint32_t value;
4773 unsigned long flags;
4774
4775 if (!kstrtou32(buf, 0, &value)) {
4776 spin_lock_irqsave(&host->lock, flags);
4777 host->msm_bus_vote.is_max_bw_needed = !!value;
4778 spin_unlock_irqrestore(&host->lock, flags);
4779 }
4780
4781 return count;
4782}
4783
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304784static ssize_t
4785show_idle_timeout(struct device *dev, struct device_attribute *attr,
4786 char *buf)
4787{
4788 struct mmc_host *mmc = dev_get_drvdata(dev);
4789 struct msmsdcc_host *host = mmc_priv(mmc);
4790
4791 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4792 host->idle_tout_ms / 1000);
4793}
4794
4795static ssize_t
4796store_idle_timeout(struct device *dev, struct device_attribute *attr,
4797 const char *buf, size_t count)
4798{
4799 struct mmc_host *mmc = dev_get_drvdata(dev);
4800 struct msmsdcc_host *host = mmc_priv(mmc);
4801 unsigned int long flags;
4802 int timeout; /* in secs */
4803
4804 if (!kstrtou32(buf, 0, &timeout)
4805 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4806 spin_lock_irqsave(&host->lock, flags);
4807 host->idle_tout_ms = timeout * 1000;
4808 spin_unlock_irqrestore(&host->lock, flags);
4809 }
4810 return count;
4811}
4812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004813#ifdef CONFIG_HAS_EARLYSUSPEND
4814static void msmsdcc_early_suspend(struct early_suspend *h)
4815{
4816 struct msmsdcc_host *host =
4817 container_of(h, struct msmsdcc_host, early_suspend);
4818 unsigned long flags;
4819
4820 spin_lock_irqsave(&host->lock, flags);
4821 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4822 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4823 spin_unlock_irqrestore(&host->lock, flags);
4824};
4825static void msmsdcc_late_resume(struct early_suspend *h)
4826{
4827 struct msmsdcc_host *host =
4828 container_of(h, struct msmsdcc_host, early_suspend);
4829 unsigned long flags;
4830
4831 if (host->polling_enabled) {
4832 spin_lock_irqsave(&host->lock, flags);
4833 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4834 mmc_detect_change(host->mmc, 0);
4835 spin_unlock_irqrestore(&host->lock, flags);
4836 }
4837};
4838#endif
4839
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304840static void msmsdcc_print_regs(const char *name, void __iomem *base,
4841 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304842{
4843 unsigned int i;
4844
4845 if (!base)
4846 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304847
4848 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4849 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304850 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304851 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4852 (u32)readl_relaxed(base + i*4),
4853 (u32)readl_relaxed(base + ((i+1)*4)),
4854 (u32)readl_relaxed(base + ((i+2)*4)),
4855 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304856 }
4857}
4858
4859static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4860{
4861 /* Dump current state of SDCC clocks, power and irq */
4862 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304863 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304864 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304865 mmc_hostname(host->mmc),
4866 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304867 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304868 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4869 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4870
4871 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304872 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304873 msmsdcc_print_regs("SDCC-CORE", host->base,
4874 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304875
4876 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304877 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304878 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304879 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304880 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4881 mmc_hostname(host->mmc), host->dma.busy,
4882 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304883 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304884 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304885 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4886 host->dml_memres->start,
4887 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304888 pr_info("%s: SPS mode: busy=%d\n",
4889 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304890 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304891
4892 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4893 mmc_hostname(host->mmc), host->curr.xfer_size,
4894 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304895 }
4896
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304897 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304898 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4899 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4900 host->curr.got_dataend, host->prog_enable,
4901 host->curr.wait_for_auto_prog_done,
4902 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304903 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304904}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004906static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4907{
4908 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4909 struct mmc_request *mrq;
4910 unsigned long flags;
4911
4912 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004913 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004914 pr_info("%s: %s: dummy CMD52 timeout\n",
4915 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004916 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004917 }
4918
4919 mrq = host->curr.mrq;
4920
4921 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304922 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4923 mrq->cmd->opcode);
4924 msmsdcc_dump_sdcc_state(host);
4925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004926 if (!mrq->cmd->error)
4927 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304928 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004929 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004930 if (mrq->data && !mrq->data->error)
4931 mrq->data->error = -ETIMEDOUT;
4932 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304933 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004934 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304935 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936 /* Stop current SPS transfer */
4937 msmsdcc_sps_exit_curr_xfer(host);
4938 } else {
4939 msmsdcc_reset_and_restore(host);
4940 msmsdcc_stop_data(host);
4941 if (mrq->data && mrq->data->stop)
4942 msmsdcc_start_command(host,
4943 mrq->data->stop, 0);
4944 else
4945 msmsdcc_request_end(host, mrq);
4946 }
4947 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304948 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304949 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004950 msmsdcc_reset_and_restore(host);
4951 msmsdcc_request_end(host, mrq);
4952 }
4953 }
4954 spin_unlock_irqrestore(&host->lock, flags);
4955}
4956
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304957/*
4958 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4959 *
4960 * @dev: device node from which the property value is to be read.
4961 * @prop_name: name of the property to be searched.
4962 * @out_array: filled array returned to caller
4963 * @len: filled array size returned to caller
4964 * @size: expected size of the array
4965 *
4966 * If expected "size" doesn't match with "len" an error is returned. If
4967 * expected size is zero, the length of actual array is returned provided
4968 * return value is zero.
4969 *
4970 * RETURNS:
4971 * zero on success, negative error if failed.
4972 */
4973static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4974 u32 **out_array, int *len, int size)
4975{
4976 int ret = 0;
4977 u32 *array = NULL;
4978 struct device_node *np = dev->of_node;
4979
4980 if (of_get_property(np, prop_name, len)) {
4981 size_t sz;
4982 sz = *len = *len / sizeof(*array);
4983
4984 if (sz > 0 && !(size > 0 && (sz != size))) {
4985 array = devm_kzalloc(dev, sz * sizeof(*array),
4986 GFP_KERNEL);
4987 if (!array) {
4988 dev_err(dev, "%s: no memory\n", prop_name);
4989 ret = -ENOMEM;
4990 goto out;
4991 }
4992
4993 ret = of_property_read_u32_array(np, prop_name,
4994 array, sz);
4995 if (ret < 0) {
4996 dev_err(dev, "%s: error reading array %d\n",
4997 prop_name, ret);
4998 goto out;
4999 }
5000 } else {
5001 dev_err(dev, "%s invalid size\n", prop_name);
5002 ret = -EINVAL;
5003 goto out;
5004 }
5005 } else {
5006 dev_err(dev, "%s not specified\n", prop_name);
5007 ret = -EINVAL;
5008 goto out;
5009 }
5010 *out_array = array;
5011out:
5012 if (ret)
5013 *len = 0;
5014 return ret;
5015}
5016
5017static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5018 struct msm_mmc_pad_pull_data **pad_pull_data)
5019{
5020 int ret = 0, base = 0, len, i;
5021 u32 *tmp;
5022 struct msm_mmc_pad_pull_data *pull_data;
5023 struct msm_mmc_pad_pull *pull;
5024
5025 switch (id) {
5026 case 1:
5027 base = TLMM_PULL_SDC1_CLK;
5028 break;
5029 case 2:
5030 base = TLMM_PULL_SDC2_CLK;
5031 break;
5032 case 3:
5033 base = TLMM_PULL_SDC3_CLK;
5034 break;
5035 case 4:
5036 base = TLMM_PULL_SDC4_CLK;
5037 break;
5038 default:
5039 dev_err(dev, "%s: Invalid slot id\n", __func__);
5040 ret = -EINVAL;
5041 goto err;
5042 }
5043
5044 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5045 GFP_KERNEL);
5046 if (!pull_data) {
5047 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5048 ret = -ENOMEM;
5049 goto err;
5050 }
5051 pull_data->size = 3; /* array size for clk, cmd, data */
5052
5053 /* Allocate on, off configs for clk, cmd, data */
5054 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5055 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5056 if (!pull) {
5057 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5058 ret = -ENOMEM;
5059 goto err;
5060 }
5061 pull_data->on = pull;
5062 pull_data->off = pull + pull_data->size;
5063
5064 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5065 &tmp, &len, pull_data->size);
5066 if (!ret) {
5067 for (i = 0; i < len; i++) {
5068 pull_data->on[i].no = base + i;
5069 pull_data->on[i].val = tmp[i];
5070 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5071 i, pull_data->on[i].val);
5072 }
5073 } else {
5074 goto err;
5075 }
5076
5077 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5078 &tmp, &len, pull_data->size);
5079 if (!ret) {
5080 for (i = 0; i < len; i++) {
5081 pull_data->off[i].no = base + i;
5082 pull_data->off[i].val = tmp[i];
5083 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5084 i, pull_data->off[i].val);
5085 }
5086 } else {
5087 goto err;
5088 }
5089
5090 *pad_pull_data = pull_data;
5091err:
5092 return ret;
5093}
5094
5095static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5096 struct msm_mmc_pad_drv_data **pad_drv_data)
5097{
5098 int ret = 0, base = 0, len, i;
5099 u32 *tmp;
5100 struct msm_mmc_pad_drv_data *drv_data;
5101 struct msm_mmc_pad_drv *drv;
5102
5103 switch (id) {
5104 case 1:
5105 base = TLMM_HDRV_SDC1_CLK;
5106 break;
5107 case 2:
5108 base = TLMM_HDRV_SDC2_CLK;
5109 break;
5110 case 3:
5111 base = TLMM_HDRV_SDC3_CLK;
5112 break;
5113 case 4:
5114 base = TLMM_HDRV_SDC4_CLK;
5115 break;
5116 default:
5117 dev_err(dev, "%s: Invalid slot id\n", __func__);
5118 ret = -EINVAL;
5119 goto err;
5120 }
5121
5122 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5123 GFP_KERNEL);
5124 if (!drv_data) {
5125 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5126 ret = -ENOMEM;
5127 goto err;
5128 }
5129 drv_data->size = 3; /* array size for clk, cmd, data */
5130
5131 /* Allocate on, off configs for clk, cmd, data */
5132 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5133 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5134 if (!drv) {
5135 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5136 ret = -ENOMEM;
5137 goto err;
5138 }
5139 drv_data->on = drv;
5140 drv_data->off = drv + drv_data->size;
5141
5142 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5143 &tmp, &len, drv_data->size);
5144 if (!ret) {
5145 for (i = 0; i < len; i++) {
5146 drv_data->on[i].no = base + i;
5147 drv_data->on[i].val = tmp[i];
5148 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5149 i, drv_data->on[i].val);
5150 }
5151 } else {
5152 goto err;
5153 }
5154
5155 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5156 &tmp, &len, drv_data->size);
5157 if (!ret) {
5158 for (i = 0; i < len; i++) {
5159 drv_data->off[i].no = base + i;
5160 drv_data->off[i].val = tmp[i];
5161 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5162 i, drv_data->off[i].val);
5163 }
5164 } else {
5165 goto err;
5166 }
5167
5168 *pad_drv_data = drv_data;
5169err:
5170 return ret;
5171}
5172
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305173static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5174 struct mmc_platform_data *pdata)
5175{
5176 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5177 struct device_node *np = dev->of_node;
5178
5179 pdata->status_gpio = of_get_named_gpio_flags(np,
5180 "cd-gpios", 0, &flags);
5181 if (gpio_is_valid(pdata->status_gpio)) {
5182 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5183 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5184 }
5185
5186 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5187 "wp-gpios", 0, &flags);
5188 if (gpio_is_valid(pdata->wpswitch_gpio))
5189 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5190}
5191
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305192static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5193 struct mmc_platform_data *pdata)
5194{
5195 int ret = 0, id = 0, cnt, i;
5196 struct msm_mmc_pin_data *pin_data;
5197 struct device_node *np = dev->of_node;
5198
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305199 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5200
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305201 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5202 if (!pin_data) {
5203 dev_err(dev, "No memory for pin_data\n");
5204 ret = -ENOMEM;
5205 goto err;
5206 }
5207
5208 cnt = of_gpio_count(np);
5209 if (cnt > 0) {
5210 pin_data->is_gpio = true;
5211
5212 pin_data->gpio_data = devm_kzalloc(dev,
5213 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5214 if (!pin_data->gpio_data) {
5215 dev_err(dev, "No memory for gpio_data\n");
5216 ret = -ENOMEM;
5217 goto err;
5218 }
5219 pin_data->gpio_data->size = cnt;
5220 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5221 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5222 if (!pin_data->gpio_data->gpio) {
5223 dev_err(dev, "No memory for gpio\n");
5224 ret = -ENOMEM;
5225 goto err;
5226 }
5227
5228 for (i = 0; i < cnt; i++) {
5229 const char *name = NULL;
5230 char result[32];
5231 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5232 of_property_read_string_index(np,
5233 "qcom,sdcc-gpio-names", i, &name);
5234
5235 snprintf(result, 32, "%s-%s",
5236 dev_name(dev), name ? name : "?");
5237 pin_data->gpio_data->gpio[i].name = result;
5238 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5239 pin_data->gpio_data->gpio[i].name,
5240 pin_data->gpio_data->gpio[i].no);
5241 }
5242 } else {
5243 pin_data->pad_data = devm_kzalloc(dev,
5244 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5245 if (!pin_data->pad_data) {
5246 dev_err(dev, "No memory for pin_data->pad_data\n");
5247 ret = -ENOMEM;
5248 goto err;
5249 }
5250
5251 of_property_read_u32(np, "cell-index", &id);
5252
5253 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5254 &pin_data->pad_data->pull);
5255 if (ret)
5256 goto err;
5257 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5258 &pin_data->pad_data->drv);
5259 if (ret)
5260 goto err;
5261 }
5262
5263 pdata->pin_data = pin_data;
5264err:
5265 if (ret)
5266 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5267 return ret;
5268}
5269
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305270#define MAX_PROP_SIZE 32
5271static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5272 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5273{
5274 int len, ret = 0;
5275 const __be32 *prop;
5276 char prop_name[MAX_PROP_SIZE];
5277 struct msm_mmc_reg_data *vreg;
5278 struct device_node *np = dev->of_node;
5279
5280 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5281 if (of_parse_phandle(np, prop_name, 0)) {
5282 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5283 if (!vreg) {
5284 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5285 ret = -ENOMEM;
5286 goto err;
5287 }
5288
5289 vreg->name = vreg_name;
5290
5291 snprintf(prop_name, MAX_PROP_SIZE,
5292 "qcom,sdcc-%s-always_on", vreg_name);
5293 if (of_get_property(np, prop_name, NULL))
5294 vreg->always_on = true;
5295
5296 snprintf(prop_name, MAX_PROP_SIZE,
5297 "qcom,sdcc-%s-lpm_sup", vreg_name);
5298 if (of_get_property(np, prop_name, NULL))
5299 vreg->lpm_sup = true;
5300
5301 snprintf(prop_name, MAX_PROP_SIZE,
5302 "qcom,sdcc-%s-voltage_level", vreg_name);
5303 prop = of_get_property(np, prop_name, &len);
5304 if (!prop || (len != (2 * sizeof(__be32)))) {
5305 dev_warn(dev, "%s %s property\n",
5306 prop ? "invalid format" : "no", prop_name);
5307 } else {
5308 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5309 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5310 }
5311
5312 snprintf(prop_name, MAX_PROP_SIZE,
5313 "qcom,sdcc-%s-current_level", vreg_name);
5314 prop = of_get_property(np, prop_name, &len);
5315 if (!prop || (len != (2 * sizeof(__be32)))) {
5316 dev_warn(dev, "%s %s property\n",
5317 prop ? "invalid format" : "no", prop_name);
5318 } else {
5319 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5320 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5321 }
5322
5323 *vreg_data = vreg;
5324 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5325 vreg->name, vreg->always_on ? "always_on," : "",
5326 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5327 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5328 }
5329
5330err:
5331 return ret;
5332}
5333
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305334static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5335{
5336 int i, ret;
5337 struct mmc_platform_data *pdata;
5338 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005339 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305340 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005341 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305342
5343 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5344 if (!pdata) {
5345 dev_err(dev, "could not allocate memory for platform data\n");
5346 goto err;
5347 }
5348
5349 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5350 if (bus_width == 8) {
5351 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5352 } else if (bus_width == 4) {
5353 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5354 } else {
5355 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5356 pdata->mmc_bus_width = 0;
5357 }
5358
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305359 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5360 &sup_voltages, &sup_volt_len, 0);
5361 if (!ret) {
5362 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305363 u32 mask;
5364
5365 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5366 sup_voltages[i + 1]);
5367 if (!mask)
5368 dev_err(dev, "Invalide voltage range %d\n", i);
5369 pdata->ocr_mask |= mask;
5370 }
5371 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305372 }
5373
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305374 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5375 &clk_table, &clk_table_len, 0);
5376 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305377 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305378 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305379 }
5380
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305381 pdata->vreg_data = devm_kzalloc(dev,
5382 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5383 if (!pdata->vreg_data) {
5384 dev_err(dev, "could not allocate memory for vreg_data\n");
5385 goto err;
5386 }
5387
5388 if (msmsdcc_dt_parse_vreg_info(dev,
5389 &pdata->vreg_data->vdd_data, "vdd"))
5390 goto err;
5391
5392 if (msmsdcc_dt_parse_vreg_info(dev,
5393 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5394 goto err;
5395
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305396 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5397 goto err;
5398
Devin Kim9ccbff52012-07-16 20:55:14 -07005399 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5400
5401 for (i = 0; i < len; i++) {
5402 const char *name = NULL;
5403
5404 of_property_read_string_index(np,
5405 "qcom,sdcc-bus-speed-mode", i, &name);
5406 if (!name)
5407 continue;
5408
5409 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5410 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5411 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5412 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5413 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5414 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5415 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5416 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5417 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5418 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5419 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5420 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5421 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5422 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5423 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5424 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5425 | MMC_CAP_UHS_DDR50;
5426 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5427 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5428 | MMC_CAP_UHS_DDR50;
5429 }
5430
5431 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5432 if (current_limit == 800)
5433 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5434 else if (current_limit == 600)
5435 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5436 else if (current_limit == 400)
5437 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5438 else if (current_limit == 200)
5439 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5440
5441 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5442 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305443 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5444 pdata->nonremovable = true;
5445 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5446 pdata->disable_cmd23 = true;
5447
5448 return pdata;
5449err:
5450 return NULL;
5451}
5452
San Mehat9d2bd732009-09-22 16:44:22 -07005453static int
5454msmsdcc_probe(struct platform_device *pdev)
5455{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305456 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005457 struct msmsdcc_host *host;
5458 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005459 unsigned long flags;
5460 struct resource *core_irqres = NULL;
5461 struct resource *bam_irqres = NULL;
5462 struct resource *core_memres = NULL;
5463 struct resource *dml_memres = NULL;
5464 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005465 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005466 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305467 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005468
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305469 if (pdev->dev.of_node) {
5470 plat = msmsdcc_populate_pdata(&pdev->dev);
5471 of_property_read_u32((&pdev->dev)->of_node,
5472 "cell-index", &pdev->id);
5473 } else {
5474 plat = pdev->dev.platform_data;
5475 }
San Mehat9d2bd732009-09-22 16:44:22 -07005476
5477 /* must have platform data */
5478 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005479 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005480 ret = -EINVAL;
5481 goto out;
5482 }
5483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005484 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005485 return -EINVAL;
5486
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305487 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5488 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5489 return -EINVAL;
5490 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005491
San Mehat9d2bd732009-09-22 16:44:22 -07005492 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005493 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005494 return -ENXIO;
5495 }
5496
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305497 core_memres = platform_get_resource_byname(pdev,
5498 IORESOURCE_MEM, "core_mem");
5499 bam_memres = platform_get_resource_byname(pdev,
5500 IORESOURCE_MEM, "bam_mem");
5501 dml_memres = platform_get_resource_byname(pdev,
5502 IORESOURCE_MEM, "dml_mem");
5503 core_irqres = platform_get_resource_byname(pdev,
5504 IORESOURCE_IRQ, "core_irq");
5505 bam_irqres = platform_get_resource_byname(pdev,
5506 IORESOURCE_IRQ, "bam_irq");
5507 dmares = platform_get_resource_byname(pdev,
5508 IORESOURCE_DMA, "dma_chnl");
5509 dma_crci_res = platform_get_resource_byname(pdev,
5510 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005512 if (!core_irqres || !core_memres) {
5513 pr_err("%s: Invalid sdcc core resource\n", __func__);
5514 return -ENXIO;
5515 }
5516
5517 /*
5518 * Both BAM and DML memory resource should be preset.
5519 * BAM IRQ resource should also be present.
5520 */
5521 if ((bam_memres && !dml_memres) ||
5522 (!bam_memres && dml_memres) ||
5523 ((bam_memres && dml_memres) && !bam_irqres)) {
5524 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005525 return -ENXIO;
5526 }
5527
5528 /*
5529 * Setup our host structure
5530 */
San Mehat9d2bd732009-09-22 16:44:22 -07005531 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5532 if (!mmc) {
5533 ret = -ENOMEM;
5534 goto out;
5535 }
5536
5537 host = mmc_priv(mmc);
5538 host->pdev_id = pdev->id;
5539 host->plat = plat;
5540 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005541 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305542
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305543 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305544 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005545 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305546 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005548 host->base = ioremap(core_memres->start,
5549 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005550 if (!host->base) {
5551 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305552 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005553 }
5554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005555 host->core_irqres = core_irqres;
5556 host->bam_irqres = bam_irqres;
5557 host->core_memres = core_memres;
5558 host->dml_memres = dml_memres;
5559 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005560 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005561 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005562 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305563 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005565#ifdef CONFIG_MMC_EMBEDDED_SDIO
5566 if (plat->embedded_sdio)
5567 mmc_set_embedded_sdio_data(mmc,
5568 &plat->embedded_sdio->cis,
5569 &plat->embedded_sdio->cccr,
5570 plat->embedded_sdio->funcs,
5571 plat->embedded_sdio->num_funcs);
5572#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005573
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305574 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5575 (unsigned long)host);
5576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005577 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5578 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305579 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005580 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305581 ret = msmsdcc_init_dma(host);
5582 if (ret)
5583 goto ioremap_free;
5584 } else {
5585 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005586 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305587 }
San Mehat9d2bd732009-09-22 16:44:22 -07005588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005589 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305590 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005591 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305592 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5593 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5594 /* Vote for max. clk rate for max. performance */
5595 ret = clk_set_rate(host->bus_clk, INT_MAX);
5596 if (ret)
5597 goto bus_clk_put;
5598 ret = clk_prepare_enable(host->bus_clk);
5599 if (ret)
5600 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005601 }
5602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005603 /*
5604 * Setup main peripheral bus clock
5605 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005606 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005607 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305608 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005609 if (ret)
5610 goto pclk_put;
5611
5612 host->pclk_rate = clk_get_rate(host->pclk);
5613 }
5614
5615 /*
5616 * Setup SDC MMC clock
5617 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005618 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005619 if (IS_ERR(host->clk)) {
5620 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005621 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005622 }
5623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005624 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305625 if (ret) {
5626 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5627 goto clk_put;
5628 }
5629
Asutosh Dasf5298c32012-04-03 14:51:47 +05305630 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005631 if (ret)
5632 goto clk_put;
5633
San Mehat9d2bd732009-09-22 16:44:22 -07005634 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305635 if (!host->clk_rate)
5636 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305637
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305638 set_default_hw_caps(host);
5639
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305640 /*
5641 * Set the register write delay according to min. clock frequency
5642 * supported and update later when the host->clk_rate changes.
5643 */
5644 host->reg_write_delay =
5645 (1 + ((3 * USEC_PER_SEC) /
5646 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005647
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305648 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305649 /* Apply Hard reset to SDCC to put it in power on default state */
5650 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005651
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005652#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305653 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005654 if (host->plat->cpu_dma_latency)
5655 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5656 else
5657 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5658 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305659 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5660
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305661 ret = msmsdcc_msm_bus_register(host);
5662 if (ret)
5663 goto pm_qos_remove;
5664
5665 if (host->msm_bus_vote.client_handle)
5666 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5667 msmsdcc_msm_bus_work);
5668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005669 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005670 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005671 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005672 goto clk_disable;
5673 }
5674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005675
5676 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305677 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005678 /* Initialize SPS */
5679 ret = msmsdcc_sps_init(host);
5680 if (ret)
5681 goto vreg_deinit;
5682 /* Initialize DML */
5683 ret = msmsdcc_dml_init(host);
5684 if (ret)
5685 goto sps_exit;
5686 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305687 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005688
San Mehat9d2bd732009-09-22 16:44:22 -07005689 /*
5690 * Setup MMC host structure
5691 */
5692 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005693 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5694 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005695 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305696 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005698 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5699 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005700 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305701 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305702 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305703 /*
5704 * If we send the CMD23 before multi block write/read command
5705 * then we need not to send CMD12 at the end of the transfer.
5706 * If we don't send the CMD12 then only way to detect the PROG_DONE
5707 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5708 * controller. So let's enable the CMD23 for SDCC4 only.
5709 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305710 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305711 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005713 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005714 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005715 /*
5716 * XPC controls the maximum current in the default speed mode of SDXC
5717 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5718 * XPC=1 means 150mA (max.) and speed class is supported.
5719 */
5720 if (plat->xpc_cap)
5721 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5722 MMC_CAP_SET_XPC_180);
5723
Devin Kim9b67ee02012-07-16 21:13:05 -07005724 /* packed write */
5725 mmc->caps2 |= plat->packed_write;
5726
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305727 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005728 mmc->caps2 |= MMC_CAP2_SANITIZE;
5729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005730 if (plat->nonremovable)
5731 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005732 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005733
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005734 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005736 if (plat->is_sdio_al_client)
5737 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005738
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305739 mmc->max_segs = msmsdcc_get_nr_sg(host);
5740 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5741 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005742
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305743 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005744 mmc->max_seg_size = mmc->max_req_size;
5745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005746 writel_relaxed(0, host->base + MMCIMASK0);
5747 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305748 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005750 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5751 mb();
5752 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005754 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5755 DRIVER_NAME " (cmd)", host);
5756 if (ret)
5757 goto dml_exit;
5758
5759 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5760 DRIVER_NAME " (pio)", host);
5761 if (ret)
5762 goto irq_free;
5763
5764 /*
5765 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5766 * IRQ is un-necessarily being monitored by MPM (Modem power
5767 * management block) during idle-power collapse. The MPM will be
5768 * configured to monitor the DATA1 GPIO line with level-low trigger
5769 * and thus depending on the GPIO status, it prevents TCXO shutdown
5770 * during idle-power collapse.
5771 */
5772 disable_irq(core_irqres->start);
5773 host->sdcc_irq_disabled = 1;
5774
5775 if (plat->sdiowakeup_irq) {
5776 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5777 mmc_hostname(mmc));
5778 ret = request_irq(plat->sdiowakeup_irq,
5779 msmsdcc_platform_sdiowakeup_irq,
5780 IRQF_SHARED | IRQF_TRIGGER_LOW,
5781 DRIVER_NAME "sdiowakeup", host);
5782 if (ret) {
5783 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5784 plat->sdiowakeup_irq, ret);
5785 goto pio_irq_free;
5786 } else {
5787 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305788 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005789 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305790 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005791 }
5792 spin_unlock_irqrestore(&host->lock, flags);
5793 }
5794 }
5795
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305796 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005797 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5798 mmc_hostname(mmc));
5799 }
5800
5801 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5802 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005803 /*
5804 * Setup card detect change
5805 */
5806
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305807 if (!plat->status_gpio)
5808 plat->status_gpio = -ENOENT;
5809 if (!plat->wpswitch_gpio)
5810 plat->wpswitch_gpio = -ENOENT;
5811
5812 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005813 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005814 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005815 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005816 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005817
Krishna Konda941604a2012-01-10 17:46:34 -08005818 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005819 }
San Mehat9d2bd732009-09-22 16:44:22 -07005820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005821 if (plat->status_irq) {
5822 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005823 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005824 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005825 DRIVER_NAME " (slot)",
5826 host);
5827 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005828 pr_err("Unable to get slot IRQ %d (%d)\n",
5829 plat->status_irq, ret);
5830 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005831 }
5832 } else if (plat->register_status_notify) {
5833 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5834 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005835 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005836 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005837
5838 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005839
5840 ret = pm_runtime_set_active(&(pdev)->dev);
5841 if (ret < 0)
5842 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5843 __func__, ret);
5844 /*
5845 * There is no notion of suspend/resume for SD/MMC/SDIO
5846 * cards. So host can be suspended/resumed with out
5847 * worrying about its children.
5848 */
5849 pm_suspend_ignore_children(&(pdev)->dev, true);
5850
5851 /*
5852 * MMC/SD/SDIO bus suspend/resume operations are defined
5853 * only for the slots that will be used for non-removable
5854 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5855 * defined. Otherwise, they simply become card removal and
5856 * insertion events during suspend and resume respectively.
5857 * Hence, enable run-time PM only for slots for which bus
5858 * suspend/resume operations are defined.
5859 */
5860#ifdef CONFIG_MMC_UNSAFE_RESUME
5861 /*
5862 * If this capability is set, MMC core will enable/disable host
5863 * for every claim/release operation on a host. We use this
5864 * notification to increment/decrement runtime pm usage count.
5865 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005866 pm_runtime_enable(&(pdev)->dev);
5867#else
5868 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005869 pm_runtime_enable(&(pdev)->dev);
5870 }
5871#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305872 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005873 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5874 (unsigned long)host);
5875
San Mehat9d2bd732009-09-22 16:44:22 -07005876 mmc_add_host(mmc);
5877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005878#ifdef CONFIG_HAS_EARLYSUSPEND
5879 host->early_suspend.suspend = msmsdcc_early_suspend;
5880 host->early_suspend.resume = msmsdcc_late_resume;
5881 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5882 register_early_suspend(&host->early_suspend);
5883#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005884
Krishna Konda25786ec2011-07-25 16:21:36 -07005885 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5886 " dmacrcri %d\n", mmc_hostname(mmc),
5887 (unsigned long long)core_memres->start,
5888 (unsigned int) core_irqres->start,
5889 (unsigned int) plat->status_irq, host->dma.channel,
5890 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005891
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305892 pr_info("%s: Controller capabilities: 0x%.8x\n",
5893 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005894 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5895 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5896 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5897 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5898 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5899 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5900 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5901 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5902 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5903 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5904 host->eject);
5905 pr_info("%s: Power save feature enable = %d\n",
5906 mmc_hostname(mmc), msmsdcc_pwrsave);
5907
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305908 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005909 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005910 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005911 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005912 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005913 mmc_hostname(mmc), host->dma.cmd_busaddr,
5914 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305915 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005916 pr_info("%s: SPS-BAM data transfer mode available\n",
5917 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005918 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005919 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005921#if defined(CONFIG_DEBUG_FS)
5922 msmsdcc_dbg_createhost(host);
5923#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305924
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305925 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5926 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5927 sysfs_attr_init(&host->max_bus_bw.attr);
5928 host->max_bus_bw.attr.name = "max_bus_bw";
5929 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5930 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305931 if (ret)
5932 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305933
5934 if (!plat->status_irq) {
5935 host->polling.show = show_polling;
5936 host->polling.store = store_polling;
5937 sysfs_attr_init(&host->polling.attr);
5938 host->polling.attr.name = "polling";
5939 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5940 ret = device_create_file(&pdev->dev, &host->polling);
5941 if (ret)
5942 goto remove_max_bus_bw_file;
5943 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305944 host->idle_timeout.show = show_idle_timeout;
5945 host->idle_timeout.store = store_idle_timeout;
5946 sysfs_attr_init(&host->idle_timeout.attr);
5947 host->idle_timeout.attr.name = "idle_timeout";
5948 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5949 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5950 if (ret)
5951 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005952 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005953
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305954 remove_polling_file:
5955 if (!plat->status_irq)
5956 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305957 remove_max_bus_bw_file:
5958 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005959 platform_irq_free:
5960 del_timer_sync(&host->req_tout_timer);
5961 pm_runtime_disable(&(pdev)->dev);
5962 pm_runtime_set_suspended(&(pdev)->dev);
5963
5964 if (plat->status_irq)
5965 free_irq(plat->status_irq, host);
5966 sdiowakeup_irq_free:
5967 wake_lock_destroy(&host->sdio_suspend_wlock);
5968 if (plat->sdiowakeup_irq)
5969 free_irq(plat->sdiowakeup_irq, host);
5970 pio_irq_free:
5971 if (plat->sdiowakeup_irq)
5972 wake_lock_destroy(&host->sdio_wlock);
5973 free_irq(core_irqres->start, host);
5974 irq_free:
5975 free_irq(core_irqres->start, host);
5976 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305977 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 msmsdcc_dml_exit(host);
5979 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305980 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005981 msmsdcc_sps_exit(host);
5982 vreg_deinit:
5983 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005984 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005985 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305986 msmsdcc_msm_bus_unregister(host);
5987 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005988 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305989 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005990 clk_put:
5991 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005992 pclk_disable:
5993 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305994 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005995 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005996 if (!IS_ERR(host->pclk))
5997 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305998 if (!IS_ERR_OR_NULL(host->bus_clk))
5999 clk_disable_unprepare(host->bus_clk);
6000 bus_clk_put:
6001 if (!IS_ERR_OR_NULL(host->bus_clk))
6002 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306003 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006004 if (host->dmares)
6005 dma_free_coherent(NULL,
6006 sizeof(struct msmsdcc_nc_dmadata),
6007 host->dma.nc, host->dma.nc_busaddr);
6008 }
6009 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306010 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006011 host_free:
6012 mmc_free_host(mmc);
6013 out:
6014 return ret;
6015}
6016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006017static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006018{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006019 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6020 struct mmc_platform_data *plat;
6021 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006023 if (!mmc)
6024 return -ENXIO;
6025
6026 if (pm_runtime_suspended(&(pdev)->dev))
6027 pm_runtime_resume(&(pdev)->dev);
6028
6029 host = mmc_priv(mmc);
6030
6031 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6032 plat = host->plat;
6033
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306034 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006035 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306036 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306037 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006038
6039 del_timer_sync(&host->req_tout_timer);
6040 tasklet_kill(&host->dma_tlet);
6041 tasklet_kill(&host->sps.tlet);
6042 mmc_remove_host(mmc);
6043
6044 if (plat->status_irq)
6045 free_irq(plat->status_irq, host);
6046
6047 wake_lock_destroy(&host->sdio_suspend_wlock);
6048 if (plat->sdiowakeup_irq) {
6049 wake_lock_destroy(&host->sdio_wlock);
6050 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6051 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006052 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006053
6054 free_irq(host->core_irqres->start, host);
6055 free_irq(host->core_irqres->start, host);
6056
6057 clk_put(host->clk);
6058 if (!IS_ERR(host->pclk))
6059 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306060 if (!IS_ERR_OR_NULL(host->bus_clk))
6061 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006062
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006063 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306064 pm_qos_remove_request(&host->pm_qos_req_dma);
6065
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306066 if (host->msm_bus_vote.client_handle) {
6067 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6068 msmsdcc_msm_bus_unregister(host);
6069 }
6070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006071 msmsdcc_vreg_init(host, false);
6072
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306073 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006074 if (host->dmares)
6075 dma_free_coherent(NULL,
6076 sizeof(struct msmsdcc_nc_dmadata),
6077 host->dma.nc, host->dma.nc_busaddr);
6078 }
6079
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306080 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006081 msmsdcc_dml_exit(host);
6082 msmsdcc_sps_exit(host);
6083 }
6084
6085 iounmap(host->base);
6086 mmc_free_host(mmc);
6087
6088#ifdef CONFIG_HAS_EARLYSUSPEND
6089 unregister_early_suspend(&host->early_suspend);
6090#endif
6091 pm_runtime_disable(&(pdev)->dev);
6092 pm_runtime_set_suspended(&(pdev)->dev);
6093
6094 return 0;
6095}
6096
6097#ifdef CONFIG_MSM_SDIO_AL
6098int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6099{
6100 struct msmsdcc_host *host = mmc_priv(mmc);
6101 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306102 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103
Asutosh Dasf5298c32012-04-03 14:51:47 +05306104 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006105 spin_lock_irqsave(&host->lock, flags);
6106 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6107 enable ? "En" : "Dis");
6108
6109 if (enable) {
6110 if (!host->sdcc_irq_disabled) {
6111 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306112 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006113 host->sdcc_irq_disabled = 1;
6114 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306115 rc = msmsdcc_setup_clocks(host, false);
6116 if (rc)
6117 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006118
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306119 if (host->plat->sdio_lpm_gpio_setup &&
6120 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006121 spin_unlock_irqrestore(&host->lock, flags);
6122 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6123 spin_lock_irqsave(&host->lock, flags);
6124 host->sdio_gpio_lpm = 1;
6125 }
6126
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306127 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006128 msmsdcc_enable_irq_wake(host);
6129 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306130 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006131 }
6132 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306133 rc = msmsdcc_setup_clocks(host, true);
6134 if (rc)
6135 goto out;
6136
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306137 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006138 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306139 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 msmsdcc_disable_irq_wake(host);
6141 }
6142
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306143 if (host->plat->sdio_lpm_gpio_setup &&
6144 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006145 spin_unlock_irqrestore(&host->lock, flags);
6146 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6147 spin_lock_irqsave(&host->lock, flags);
6148 host->sdio_gpio_lpm = 0;
6149 }
6150
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306151 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006152 writel_relaxed(host->mci_irqenable,
6153 host->base + MMCIMASK0);
6154 mb();
6155 enable_irq(host->core_irqres->start);
6156 host->sdcc_irq_disabled = 0;
6157 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006158 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306159out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006160 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306161 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306162 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006163}
6164#else
6165int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6166{
6167 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006168}
6169#endif
6170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306172#ifdef CONFIG_MMC_CLKGATE
6173static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6174{
6175 struct mmc_host *mmc = host->mmc;
6176 unsigned long flags;
6177
6178 mmc_host_clk_hold(mmc);
6179 spin_lock_irqsave(&mmc->clk_lock, flags);
6180 mmc->clk_old = mmc->ios.clock;
6181 mmc->ios.clock = 0;
6182 mmc->clk_gated = true;
6183 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6184 mmc_set_ios(mmc);
6185 mmc_host_clk_release(mmc);
6186}
6187
6188static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6189{
6190 struct mmc_host *mmc = host->mmc;
6191
6192 mmc_host_clk_hold(mmc);
6193 mmc->ios.clock = host->clk_rate;
6194 mmc_set_ios(mmc);
6195 mmc_host_clk_release(mmc);
6196}
6197#else
6198static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6199{
6200 struct mmc_host *mmc = host->mmc;
6201
6202 mmc->ios.clock = 0;
6203 mmc_set_ios(mmc);
6204}
6205
6206static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6207{
6208 struct mmc_host *mmc = host->mmc;
6209
6210 mmc->ios.clock = host->clk_rate;
6211 mmc_set_ios(mmc);
6212}
6213#endif
6214
San Mehat9d2bd732009-09-22 16:44:22 -07006215static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006216msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006217{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006218 struct mmc_host *mmc = dev_get_drvdata(dev);
6219 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006220 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306221 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006222
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306223 if (host->plat->is_sdio_al_client) {
6224 rc = 0;
6225 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006226 }
San Mehat9d2bd732009-09-22 16:44:22 -07006227
Sahitya Tummala7661a452011-07-18 13:28:35 +05306228 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006229 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006230 host->sdcc_suspending = 1;
6231 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006233 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006234 * MMC core thinks that host is disabled by now since
6235 * runtime suspend is scheduled after msmsdcc_disable()
6236 * is called. Thus, MMC core will try to enable the host
6237 * while suspending it. This results in a synchronous
6238 * runtime resume request while in runtime suspending
6239 * context and hence inorder to complete this resume
6240 * requet, it will wait for suspend to be complete,
6241 * but runtime suspend also can not proceed further
6242 * until the host is resumed. Thus, it leads to a hang.
6243 * Hence, increase the pm usage count before suspending
6244 * the host so that any resume requests after this will
6245 * simple become pm usage counter increment operations.
6246 */
6247 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306248 /* If there is pending detect work abort runtime suspend */
6249 if (unlikely(work_busy(&mmc->detect.work)))
6250 rc = -EAGAIN;
6251 else
6252 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006253 pm_runtime_put_noidle(dev);
6254
6255 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306256 spin_lock_irqsave(&host->lock, flags);
6257 host->sdcc_suspended = true;
6258 spin_unlock_irqrestore(&host->lock, flags);
6259 if (mmc->card && mmc_card_sdio(mmc->card) &&
6260 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006261 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306262 * If SDIO function driver doesn't want
6263 * to power off the card, atleast turn off
6264 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006265 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306266 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006267 }
6268 }
6269 host->sdcc_suspending = 0;
6270 mmc->suspend_task = NULL;
6271 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6272 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006273 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306274 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306275out:
6276 /* set bus bandwidth to 0 immediately */
6277 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006278 return rc;
6279}
6280
6281static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006282msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006283{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006284 struct mmc_host *mmc = dev_get_drvdata(dev);
6285 struct msmsdcc_host *host = mmc_priv(mmc);
6286 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006288 if (host->plat->is_sdio_al_client)
6289 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006290
Sahitya Tummala7661a452011-07-18 13:28:35 +05306291 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006292 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306293 if (mmc->card && mmc_card_sdio(mmc->card) &&
6294 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306295 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306296 }
San Mehat9d2bd732009-09-22 16:44:22 -07006297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006298 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006300 /*
6301 * FIXME: Clearing of flags must be handled in clients
6302 * resume handler.
6303 */
6304 spin_lock_irqsave(&host->lock, flags);
6305 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306306 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006307 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006309 /*
6310 * After resuming the host wait for sometime so that
6311 * the SDIO work will be processed.
6312 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306313 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306314 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006315 host->plat->sdiowakeup_irq) &&
6316 wake_lock_active(&host->sdio_wlock))
6317 wake_lock_timeout(&host->sdio_wlock, 1);
6318 }
6319
6320 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006321 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306322 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306323 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006324 return 0;
6325}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006326
6327static int msmsdcc_runtime_idle(struct device *dev)
6328{
6329 struct mmc_host *mmc = dev_get_drvdata(dev);
6330 struct msmsdcc_host *host = mmc_priv(mmc);
6331
6332 if (host->plat->is_sdio_al_client)
6333 return 0;
6334
6335 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306336 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006337
6338 return -EAGAIN;
6339}
6340
6341static int msmsdcc_pm_suspend(struct device *dev)
6342{
6343 struct mmc_host *mmc = dev_get_drvdata(dev);
6344 struct msmsdcc_host *host = mmc_priv(mmc);
6345 int rc = 0;
6346
6347 if (host->plat->is_sdio_al_client)
6348 return 0;
6349
6350
6351 if (host->plat->status_irq)
6352 disable_irq(host->plat->status_irq);
6353
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006354 if (!pm_runtime_suspended(dev))
6355 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006356
6357 return rc;
6358}
6359
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306360static int msmsdcc_suspend_noirq(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 /*
6367 * After platform suspend there may be active request
6368 * which might have enabled clocks. For example, in SDIO
6369 * case, ksdioirq thread might have scheduled after sdcc
6370 * suspend but before system freeze. In that case abort
6371 * suspend and retry instead of keeping the clocks on
6372 * during suspend and not allowing TCXO.
6373 */
6374
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306375 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306376 pr_warn("%s: clocks are on after suspend, aborting system "
6377 "suspend\n", mmc_hostname(mmc));
6378 rc = -EAGAIN;
6379 }
6380
6381 return rc;
6382}
6383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006384static int msmsdcc_pm_resume(struct device *dev)
6385{
6386 struct mmc_host *mmc = dev_get_drvdata(dev);
6387 struct msmsdcc_host *host = mmc_priv(mmc);
6388 int rc = 0;
6389
6390 if (host->plat->is_sdio_al_client)
6391 return 0;
6392
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006393 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306394 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306395 /*
6396 * As runtime PM is enabled before calling the device's platform resume
6397 * callback, we use the pm_runtime_suspended API to know if SDCC is
6398 * really runtime suspended or not and set the pending_resume flag only
6399 * if its not runtime suspended.
6400 */
6401 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006402 host->pending_resume = true;
6403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006404 if (host->plat->status_irq) {
6405 msmsdcc_check_status((unsigned long)host);
6406 enable_irq(host->plat->status_irq);
6407 }
6408
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006409 return rc;
6410}
6411
Daniel Walker08ecfde2010-06-23 12:32:20 -07006412#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006413static int msmsdcc_runtime_suspend(struct device *dev)
6414{
6415 return 0;
6416}
6417static int msmsdcc_runtime_idle(struct device *dev)
6418{
6419 return 0;
6420}
6421static int msmsdcc_pm_suspend(struct device *dev)
6422{
6423 return 0;
6424}
6425static int msmsdcc_pm_resume(struct device *dev)
6426{
6427 return 0;
6428}
6429static int msmsdcc_suspend_noirq(struct device *dev)
6430{
6431 return 0;
6432}
6433static int msmsdcc_runtime_resume(struct device *dev)
6434{
6435 return 0;
6436}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006437#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006439static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6440 .runtime_suspend = msmsdcc_runtime_suspend,
6441 .runtime_resume = msmsdcc_runtime_resume,
6442 .runtime_idle = msmsdcc_runtime_idle,
6443 .suspend = msmsdcc_pm_suspend,
6444 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306445 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006446};
6447
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306448static const struct of_device_id msmsdcc_dt_match[] = {
6449 {.compatible = "qcom,msm-sdcc"},
6450
6451};
6452MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6453
San Mehat9d2bd732009-09-22 16:44:22 -07006454static struct platform_driver msmsdcc_driver = {
6455 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006456 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006457 .driver = {
6458 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006459 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306460 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006461 },
6462};
6463
6464static int __init msmsdcc_init(void)
6465{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006466#if defined(CONFIG_DEBUG_FS)
6467 int ret = 0;
6468 ret = msmsdcc_dbg_init();
6469 if (ret) {
6470 pr_err("Failed to create debug fs dir \n");
6471 return ret;
6472 }
6473#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006474 return platform_driver_register(&msmsdcc_driver);
6475}
San Mehat9d2bd732009-09-22 16:44:22 -07006476
San Mehat9d2bd732009-09-22 16:44:22 -07006477static void __exit msmsdcc_exit(void)
6478{
6479 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006480
6481#if defined(CONFIG_DEBUG_FS)
6482 debugfs_remove(debugfs_file);
6483 debugfs_remove(debugfs_dir);
6484#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006485}
6486
6487module_init(msmsdcc_init);
6488module_exit(msmsdcc_exit);
6489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006490MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006491MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006492
6493#if defined(CONFIG_DEBUG_FS)
6494
6495static int
6496msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6497{
6498 file->private_data = inode->i_private;
6499 return 0;
6500}
6501
6502static ssize_t
6503msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6504 size_t count, loff_t *ppos)
6505{
6506 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006507 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006508 int max, i;
6509
6510 i = 0;
6511 max = sizeof(buf) - 1;
6512
6513 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6514 host->curr.cmd, host->curr.data);
6515 if (host->curr.cmd) {
6516 struct mmc_command *cmd = host->curr.cmd;
6517
6518 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6519 cmd->opcode, cmd->arg, cmd->flags);
6520 }
6521 if (host->curr.data) {
6522 struct mmc_data *data = host->curr.data;
6523 i += scnprintf(buf + i, max - i,
6524 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6525 data->timeout_ns, data->timeout_clks,
6526 data->blksz, data->blocks, data->error,
6527 data->flags);
6528 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6529 host->curr.xfer_size, host->curr.xfer_remain,
6530 host->curr.data_xfered, host->dma.sg);
6531 }
6532
6533 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6534}
6535
6536static const struct file_operations msmsdcc_dbg_state_ops = {
6537 .read = msmsdcc_dbg_state_read,
6538 .open = msmsdcc_dbg_state_open,
6539};
6540
6541static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6542{
6543 if (debugfs_dir) {
6544 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6545 0644, debugfs_dir, host,
6546 &msmsdcc_dbg_state_ops);
6547 }
6548}
6549
6550static int __init msmsdcc_dbg_init(void)
6551{
6552 int err;
6553
6554 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6555 if (IS_ERR(debugfs_dir)) {
6556 err = PTR_ERR(debugfs_dir);
6557 debugfs_dir = NULL;
6558 return err;
6559 }
6560
6561 return 0;
6562}
6563#endif