blob: 08f5ab992f4d72c688937a40554ebde52898b470 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
Sujit Reddy Thumma38459152012-06-26 00:07:59 +053023#include <linux/of_gpio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070024#include <linux/device.h>
25#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070027#include <linux/delay.h>
28#include <linux/err.h>
29#include <linux/highmem.h>
30#include <linux/log2.h>
31#include <linux/mmc/host.h>
32#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080034#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070035#include <linux/clk.h>
36#include <linux/scatterlist.h>
37#include <linux/platform_device.h>
38#include <linux/dma-mapping.h>
39#include <linux/debugfs.h>
40#include <linux/io.h>
41#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <linux/pm_runtime.h>
43#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053044#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045#include <linux/regulator/consumer.h>
46#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070047#include <linux/pm_qos.h>
San Mehat9d2bd732009-09-22 16:44:22 -070048
49#include <asm/cacheflush.h>
50#include <asm/div64.h>
51#include <asm/sizes.h>
52
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070054#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053055#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053058#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053059#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070060
San Mehat9d2bd732009-09-22 16:44:22 -070061#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070063
64#define DRIVER_NAME "msm-sdcc"
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066#define DBG(host, fmt, args...) \
67 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
68
69#define IRQ_DEBUG 0
70#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
71#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
72#define SPS_CONS_PERIPHERAL 0
73#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053074/* Use SPS only if transfer size is more than this macro */
75#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053077#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
78
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079#if defined(CONFIG_DEBUG_FS)
80static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
81static struct dentry *debugfs_dir;
82static struct dentry *debugfs_file;
83static int msmsdcc_dbg_init(void);
84#endif
85
Asutosh Dasaccacd42012-03-08 14:33:17 +053086static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
87 *data);
88
Subhash Jadavani8766e352011-11-30 11:30:32 +053089static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070090static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092static struct mmc_command dummy52cmd;
93static struct mmc_request dummy52mrq = {
94 .cmd = &dummy52cmd,
95 .data = NULL,
96 .stop = NULL,
97};
98static struct mmc_command dummy52cmd = {
99 .opcode = SD_IO_RW_DIRECT,
100 .flags = MMC_RSP_PRESENT,
101 .data = NULL,
102 .mrq = &dummy52mrq,
103};
104/*
105 * An array holding the Tuning pattern to compare with when
106 * executing a tuning cycle.
107 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530108static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
110 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
111 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
112 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
113};
San Mehat9d2bd732009-09-22 16:44:22 -0700114
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530115static const u32 tuning_block_128[] = {
116 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
117 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
118 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
119 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
120 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
121 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
122 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
123 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
124};
San Mehat865c8062009-11-13 13:42:06 -0800125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126#if IRQ_DEBUG == 1
127static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
128 "dattimeout", "txunderrun", "rxoverrun",
129 "cmdrespend", "cmdsent", "dataend", NULL,
130 "datablkend", "cmdactive", "txactive",
131 "rxactive", "txhalfempty", "rxhalffull",
132 "txfifofull", "rxfifofull", "txfifoempty",
133 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
134 "sdiointr", "progdone", "atacmdcompl",
135 "sdiointrope", "ccstimeout", NULL, NULL,
136 NULL, NULL, NULL };
137
138static void
139msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800140{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
144 for (i = 0; i < 32; i++) {
145 if (status & (1 << i))
146 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800149}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150#endif
San Mehat865c8062009-11-13 13:42:06 -0800151
San Mehat9d2bd732009-09-22 16:44:22 -0700152static void
153msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
154 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530155static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530156static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530157static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800158static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800159static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700160static int msmsdcc_runtime_resume(struct device *dev);
San Mehat9d2bd732009-09-22 16:44:22 -0700161
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530162static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530163{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530164 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530165
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530166 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530167 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530168 } else { /* DMA or PIO mode */
169 if (NR_SG > MAX_NR_SG_DMA_PIO)
170 ret = MAX_NR_SG_DMA_PIO;
171 }
172
173 return ret;
174}
175
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530176/* Prevent idle power collapse(pc) while operating in peripheral mode */
177static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
178{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700179 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530180 return;
181
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530182 if (vote)
183 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700184 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530185 else
186 pm_qos_update_request(&host->pm_qos_req_dma,
187 PM_QOS_DEFAULT_VALUE);
188}
189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
191static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
192 struct msmsdcc_sps_ep_conn_data *ep);
193static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
194 struct msmsdcc_sps_ep_conn_data *ep);
195#else
196static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
197 struct msmsdcc_sps_ep_conn_data *ep,
198 bool is_producer) { return 0; }
199static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep) { }
201static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
202 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530203{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 return 0;
205}
206static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
207 struct msmsdcc_sps_ep_conn_data *ep)
208{
209 return 0;
210}
211static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
212static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
213#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530216 * Apply soft reset to all SDCC BAM pipes
217 *
218 * This function applies soft reset to SDCC BAM pipe.
219 *
220 * This function should be called to recover from error
221 * conditions encountered during CMD/DATA tranfsers with card.
222 *
223 * @host - Pointer to driver's host structure
224 *
225 */
226static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
227{
228 int rc;
229
230 /* Reset all SDCC BAM pipes */
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
236 if (rc)
237 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
238 mmc_hostname(host->mmc), rc);
239
Krishna Konda5af8f972012-05-14 16:15:24 -0700240 if (host->sps.reset_device) {
241 rc = sps_device_reset(host->sps.bam_handle);
242 if (rc)
243 pr_err("%s: sps_device_reset error=%d\n",
244 mmc_hostname(host->mmc), rc);
245 host->sps.reset_device = false;
246 }
247
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530248 /* Restore all BAM pipes connections */
249 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
250 if (rc)
251 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
252 mmc_hostname(host->mmc), rc);
253 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
254 if (rc)
255 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
256 mmc_hostname(host->mmc), rc);
257}
258
259/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 * Apply soft reset
261 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530262 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 *
264 * This function should be called to recover from error
265 * conditions encountered with CMD/DATA tranfsers with card.
266 *
267 * Soft reset should only be used with SDCC controller v4.
268 *
269 * @host - Pointer to driver's host structure
270 *
271 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530275 * Reset controller state machines without resetting
276 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530278 if (is_sw_reset_save_config(host)) {
279 ktime_t start;
280
281 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
282 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
283 msmsdcc_sync_reg_wr(host);
284
285 start = ktime_get();
286 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
287 /*
288 * SW reset can take upto 10HCLK + 15MCLK cycles.
289 * Calculating based on min clk rates (hclk = 27MHz,
290 * mclk = 400KHz) it comes to ~40us. Let's poll for
291 * max. 1ms for reset completion.
292 */
293 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
294 pr_err("%s: %s failed\n",
295 mmc_hostname(host->mmc), __func__);
296 BUG();
297 }
298 }
299 } else {
300 writel_relaxed(0, host->base + MMCICOMMAND);
301 msmsdcc_sync_reg_wr(host);
302 writel_relaxed(0, host->base + MMCIDATACTRL);
303 msmsdcc_sync_reg_wr(host);
304 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530305}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530306
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530307static void msmsdcc_hard_reset(struct msmsdcc_host *host)
308{
309 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530310
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530311 /*
312 * Reset SDCC controller to power on default state.
313 * Don't issue a reset request to clock control block if
314 * SDCC controller itself can support hard reset.
315 */
316 if (is_sw_hard_reset(host)) {
317 ktime_t start;
318
319 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
320 | MCI_SW_RST, host->base + MMCIPOWER);
321 msmsdcc_sync_reg_wr(host);
322
323 start = ktime_get();
324 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
325 /*
326 * See comment in msmsdcc_soft_reset() on choosing 1ms
327 * poll timeout.
328 */
329 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
330 pr_err("%s: %s failed\n",
331 mmc_hostname(host->mmc), __func__);
332 BUG();
333 }
334 }
335 } else {
336 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
337 if (ret)
338 pr_err("%s: Clock assert failed at %u Hz" \
339 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530340 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530341
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530342 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
343 if (ret)
344 pr_err("%s: Clock deassert failed at %u Hz" \
345 " with err %d\n", mmc_hostname(host->mmc),
346 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530347
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530348 mb();
349 /* Give some delay for clock reset to propogate to controller */
350 msmsdcc_delay(host);
351 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530352}
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
355{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530356 if (is_soft_reset(host)) {
357 if (is_sps_mode(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530358 /* Reset DML first */
359 msmsdcc_dml_reset(host);
360 /*
361 * delay the SPS pipe reset in thread context as
362 * sps_connect/sps_disconnect APIs can be called
363 * only from non-atomic context.
364 */
365 host->sps.pipe_reset_pending = true;
366 }
367 mb();
368 msmsdcc_soft_reset(host);
369
370 pr_debug("%s: Applied soft reset to Controller\n",
371 mmc_hostname(host->mmc));
372
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530373 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530374 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 } else {
376 /* Give Clock reset (hard reset) to controller */
377 u32 mci_clk = 0;
378 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379
380 /* Save the controller state */
381 mci_clk = readl_relaxed(host->base + MMCICLOCK);
382 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530383 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530386 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 pr_debug("%s: Controller has been reinitialized\n",
388 mmc_hostname(host->mmc));
389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 /* Restore the contoller state */
391 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530392 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530396 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530398
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700399 if (host->dummy_52_needed)
400 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401}
402
403static int
San Mehat9d2bd732009-09-22 16:44:22 -0700404msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
405{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 int retval = 0;
407
San Mehat9d2bd732009-09-22 16:44:22 -0700408 BUG_ON(host->curr.data);
409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700411
412 if (mrq->data)
413 mrq->data->bytes_xfered = host->curr.data_xfered;
414 if (mrq->cmd->error == -ETIMEDOUT)
415 mdelay(5);
416
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530417 /* Clear current request information as current request has ended */
418 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
419
San Mehat9d2bd732009-09-22 16:44:22 -0700420 /*
421 * Need to drop the host lock here; mmc_request_done may call
422 * back into the driver...
423 */
424 spin_unlock(&host->lock);
425 mmc_request_done(host->mmc, mrq);
426 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427
428 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700429}
430
431static void
432msmsdcc_stop_data(struct msmsdcc_host *host)
433{
San Mehat9d2bd732009-09-22 16:44:22 -0700434 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530435 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530436 host->curr.wait_for_auto_prog_done = false;
437 host->curr.got_auto_prog_done = false;
Krishna Konda9d1679c2012-06-04 22:44:28 -0700438 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530439 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700440}
441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700443{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 return host->core_memres->start + MMCIFIFO;
445}
446
447static inline unsigned int msmsdcc_get_min_sup_clk_rate(
448 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530449
Subhash Jadavanidd432952012-03-28 11:25:56 +0530450static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451{
452 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530453 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530454 udelay(host->reg_write_delay);
455 else if (readl_relaxed(host->base + MCI_STATUS2) &
456 MCI_MCLK_REG_WR_ACTIVE) {
457 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530458
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530459 start = ktime_get();
460 while (readl_relaxed(host->base + MCI_STATUS2) &
461 MCI_MCLK_REG_WR_ACTIVE) {
462 diff = ktime_sub(ktime_get(), start);
463 /* poll for max. 1 ms */
464 if (ktime_to_us(diff) > 1000) {
465 pr_warning("%s: previous reg. write is"
466 " still active\n",
467 mmc_hostname(host->mmc));
468 break;
469 }
470 }
471 }
San Mehat9d2bd732009-09-22 16:44:22 -0700472}
473
Subhash Jadavanidd432952012-03-28 11:25:56 +0530474static inline void msmsdcc_delay(struct msmsdcc_host *host)
475{
476 udelay(host->reg_write_delay);
477
San Mehat9d2bd732009-09-22 16:44:22 -0700478}
479
San Mehat56a8b5b2009-11-21 12:29:46 -0800480static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
482{
483 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530485 /*
486 * As after sending the command, we don't write any of the
487 * controller registers and just wait for the
488 * CMD_RESPOND_END/CMD_SENT/Command failure notication
489 * from Controller.
490 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800492}
493
494static void
495msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
496{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
500 writel_relaxed((unsigned int)host->curr.xfer_size,
501 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530503 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800504
San Mehat6ac9ea62009-12-02 17:24:58 -0800505 if (host->cmd_cmd) {
506 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800508 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800509}
510
San Mehat9d2bd732009-09-22 16:44:22 -0700511static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530512msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700513{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530514 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700515 unsigned long flags;
516 struct mmc_request *mrq;
517
518 spin_lock_irqsave(&host->lock, flags);
519 mrq = host->curr.mrq;
520 BUG_ON(!mrq);
521
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530522 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700523 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700524 goto out;
525 }
526
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530527 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700528 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700530 } else {
531 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530532 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700533 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530534 mmc_hostname(host->mmc), host->dma.result);
535 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700536 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530537 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530538 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 host->dma.err.flush[0], host->dma.err.flush[1],
540 host->dma.err.flush[2], host->dma.err.flush[3],
541 host->dma.err.flush[4],
542 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530543 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700544 if (!mrq->data->error)
545 mrq->data->error = -EIO;
546 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530547 if (!mrq->data->host_cookie)
548 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
549 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 if (host->curr.user_pages) {
552 struct scatterlist *sg = host->dma.sg;
553 int i;
554
555 for (i = 0; i < host->dma.num_ents; i++, sg++)
556 flush_dcache_page(sg_page(sg));
557 }
San Mehat9d2bd732009-09-22 16:44:22 -0700558
San Mehat9d2bd732009-09-22 16:44:22 -0700559 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800560 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700561
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530562 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
563 (host->curr.wait_for_auto_prog_done &&
564 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700565 /*
566 * If we've already gotten our DATAEND / DATABLKEND
567 * for this request, then complete it through here.
568 */
San Mehat9d2bd732009-09-22 16:44:22 -0700569
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700571 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 host->curr.xfer_remain -= host->curr.xfer_size;
573 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700574 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700575 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700576 host->dummy_52_sent = 1;
577 msmsdcc_start_command(host, &dummy52cmd,
578 MCI_CPSM_PROGENA);
579 goto out;
580 }
581 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530582 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530583 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700584 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530586 /*
587 * Clear current request information as current
588 * request has ended
589 */
590 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700591 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592
San Mehat9d2bd732009-09-22 16:44:22 -0700593 mmc_request_done(host->mmc, mrq);
594 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530595 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
596 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700597 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530598 }
San Mehat9d2bd732009-09-22 16:44:22 -0700599 }
600
601out:
602 spin_unlock_irqrestore(&host->lock, flags);
603 return;
604}
605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
607/**
608 * Callback notification from SPS driver
609 *
610 * This callback function gets triggered called from
611 * SPS driver when requested SPS data transfer is
612 * completed.
613 *
614 * SPS driver invokes this callback in BAM irq context so
615 * SDCC driver schedule a tasklet for further processing
616 * this callback notification at later point of time in
617 * tasklet context and immediately returns control back
618 * to SPS driver.
619 *
620 * @nofity - Pointer to sps event notify sturcture
621 *
622 */
623static void
624msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
625{
626 struct msmsdcc_host *host =
627 (struct msmsdcc_host *)
628 ((struct sps_event_notify *)notify)->user;
629
630 host->sps.notify = *notify;
631 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
632 mmc_hostname(host->mmc), __func__, notify->event_id,
633 notify->data.transfer.iovec.addr,
634 notify->data.transfer.iovec.size,
635 notify->data.transfer.iovec.flags);
636 /* Schedule a tasklet for completing data transfer */
637 tasklet_schedule(&host->sps.tlet);
638}
639
640/**
641 * Tasklet handler for processing SPS callback event
642 *
643 * This function processing SPS event notification and
644 * checks if the SPS transfer is completed or not and
645 * then accordingly notifies status to MMC core layer.
646 *
647 * This function is called in tasklet context.
648 *
649 * @data - Pointer to sdcc driver data
650 *
651 */
652static void msmsdcc_sps_complete_tlet(unsigned long data)
653{
654 unsigned long flags;
655 int i, rc;
656 u32 data_xfered = 0;
657 struct mmc_request *mrq;
658 struct sps_iovec iovec;
659 struct sps_pipe *sps_pipe_handle;
660 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
661 struct sps_event_notify *notify = &host->sps.notify;
662
663 spin_lock_irqsave(&host->lock, flags);
664 if (host->sps.dir == DMA_FROM_DEVICE)
665 sps_pipe_handle = host->sps.prod.pipe_handle;
666 else
667 sps_pipe_handle = host->sps.cons.pipe_handle;
668 mrq = host->curr.mrq;
669
670 if (!mrq) {
671 spin_unlock_irqrestore(&host->lock, flags);
672 return;
673 }
674
675 pr_debug("%s: %s: sps event_id=%d\n",
676 mmc_hostname(host->mmc), __func__,
677 notify->event_id);
678
679 if (msmsdcc_is_dml_busy(host)) {
680 /* oops !!! this should never happen. */
681 pr_err("%s: %s: Received SPS EOT event"
682 " but DML HW is still busy !!!\n",
683 mmc_hostname(host->mmc), __func__);
684 }
685 /*
686 * Got End of transfer event!!! Check if all of the data
687 * has been transferred?
688 */
689 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
690 rc = sps_get_iovec(sps_pipe_handle, &iovec);
691 if (rc) {
692 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
693 mmc_hostname(host->mmc), __func__, rc, i);
694 break;
695 }
696 data_xfered += iovec.size;
697 }
698
699 if (data_xfered == host->curr.xfer_size) {
700 host->curr.data_xfered = host->curr.xfer_size;
701 host->curr.xfer_remain -= host->curr.xfer_size;
702 pr_debug("%s: Data xfer success. data_xfered=0x%x",
703 mmc_hostname(host->mmc),
704 host->curr.xfer_size);
705 } else {
706 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
707 " xfer_size=%d", mmc_hostname(host->mmc),
708 data_xfered, host->curr.xfer_size);
709 msmsdcc_reset_and_restore(host);
710 if (!mrq->data->error)
711 mrq->data->error = -EIO;
712 }
713
714 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530715 if (!mrq->data->host_cookie)
716 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
717 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 host->sps.sg = NULL;
719 host->sps.busy = 0;
720
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530721 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
722 (host->curr.wait_for_auto_prog_done &&
723 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 /*
725 * If we've already gotten our DATAEND / DATABLKEND
726 * for this request, then complete it through here.
727 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728
729 if (!mrq->data->error) {
730 host->curr.data_xfered = host->curr.xfer_size;
731 host->curr.xfer_remain -= host->curr.xfer_size;
732 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700733 if (host->dummy_52_needed) {
734 mrq->data->bytes_xfered = host->curr.data_xfered;
735 host->dummy_52_sent = 1;
736 msmsdcc_start_command(host, &dummy52cmd,
737 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700738 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700739 return;
740 }
741 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530742 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530743 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 mrq->data->bytes_xfered = host->curr.data_xfered;
745 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530746 /*
747 * Clear current request information as current
748 * request has ended
749 */
750 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 spin_unlock_irqrestore(&host->lock, flags);
752
753 mmc_request_done(host->mmc, mrq);
754 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530755 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
756 || !mrq->sbc)) {
757 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 }
759 }
760 spin_unlock_irqrestore(&host->lock, flags);
761}
762
763/**
764 * Exit from current SPS data transfer
765 *
766 * This function exits from current SPS data transfer.
767 *
768 * This function should be called when error condition
769 * is encountered during data transfer.
770 *
771 * @host - Pointer to sdcc host structure
772 *
773 */
774static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
775{
776 struct mmc_request *mrq;
777
778 mrq = host->curr.mrq;
779 BUG_ON(!mrq);
780
781 msmsdcc_reset_and_restore(host);
782 if (!mrq->data->error)
783 mrq->data->error = -EIO;
784
785 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530786 if (!mrq->data->host_cookie)
787 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
788 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789
790 host->sps.sg = NULL;
791 host->sps.busy = 0;
792 if (host->curr.data)
793 msmsdcc_stop_data(host);
794
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530795 if (!mrq->data->stop || mrq->cmd->error ||
796 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530798 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
799 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 msmsdcc_start_command(host, mrq->data->stop, 0);
801
802}
803#else
804static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
805static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
806static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
807#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
808
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530809static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530811static void
812msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
813 unsigned int result,
814 struct msm_dmov_errdata *err)
815{
816 struct msmsdcc_dma_data *dma_data =
817 container_of(cmd, struct msmsdcc_dma_data, hdr);
818 struct msmsdcc_host *host = dma_data->host;
819
820 dma_data->result = result;
821 if (err)
822 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
823
824 tasklet_schedule(&host->dma_tlet);
825}
826
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530827static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
828 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700829{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530830 bool ret = true;
831 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700832
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530833 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530834 /*
835 * BAM Mode: Fall back on PIO if size is less
836 * than or equal to SPS_MIN_XFER_SIZE bytes.
837 */
838 if (xfer_size <= SPS_MIN_XFER_SIZE)
839 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530840 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530841 /*
842 * ADM Mode: Fall back on PIO if size is less than FIFO size
843 * or not integer multiple of FIFO size
844 */
845 if (xfer_size % MCI_FIFOSIZE)
846 ret = false;
847 } else {
848 /* PIO Mode */
849 ret = false;
850 }
851
852 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700853}
854
855static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
856{
857 struct msmsdcc_nc_dmadata *nc;
858 dmov_box *box;
859 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700860 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530861 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700862 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530863 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700864
Krishna Konda25786ec2011-07-25 16:21:36 -0700865 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700867
Krishna Konda25786ec2011-07-25 16:21:36 -0700868 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700869
870 host->dma.sg = data->sg;
871 host->dma.num_ents = data->sg_len;
872
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530873 /* Prevent memory corruption */
874 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800875
San Mehat9d2bd732009-09-22 16:44:22 -0700876 nc = host->dma.nc;
877
San Mehat9d2bd732009-09-22 16:44:22 -0700878 if (data->flags & MMC_DATA_READ)
879 host->dma.dir = DMA_FROM_DEVICE;
880 else
881 host->dma.dir = DMA_TO_DEVICE;
882
Asutosh Dasaccacd42012-03-08 14:33:17 +0530883 if (!data->host_cookie) {
884 n = msmsdcc_prep_xfer(host, data);
885 if (unlikely(n < 0)) {
886 host->dma.sg = NULL;
887 host->dma.num_ents = 0;
888 return -ENOMEM;
889 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800890 }
San Mehat9d2bd732009-09-22 16:44:22 -0700891
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530892 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
893 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700894 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530895 for (i = 0; i < host->dma.num_ents; i++) {
896 len = sg_dma_len(sg);
897 offset = 0;
898
899 do {
900 /* Check if we can do DMA */
901 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
902 err = -ENOTSUPP;
903 goto unmap;
904 }
905
906 box->cmd = CMD_MODE_BOX;
907
908 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
909 len = MMC_MAX_DMA_BOX_LENGTH;
910 len -= len % data->blksz;
911 }
912 rows = (len % MCI_FIFOSIZE) ?
913 (len / MCI_FIFOSIZE) + 1 :
914 (len / MCI_FIFOSIZE);
915
916 if (data->flags & MMC_DATA_READ) {
917 box->src_row_addr = msmsdcc_fifo_addr(host);
918 box->dst_row_addr = sg_dma_address(sg) + offset;
919 box->src_dst_len = (MCI_FIFOSIZE << 16) |
920 (MCI_FIFOSIZE);
921 box->row_offset = MCI_FIFOSIZE;
922 box->num_rows = rows * ((1 << 16) + 1);
923 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
924 } else {
925 box->src_row_addr = sg_dma_address(sg) + offset;
926 box->dst_row_addr = msmsdcc_fifo_addr(host);
927 box->src_dst_len = (MCI_FIFOSIZE << 16) |
928 (MCI_FIFOSIZE);
929 box->row_offset = (MCI_FIFOSIZE << 16);
930 box->num_rows = rows * ((1 << 16) + 1);
931 box->cmd |= CMD_DST_CRCI(host->dma.crci);
932 }
933
934 offset += len;
935 len = sg_dma_len(sg) - offset;
936 box++;
937 box_cmd_cnt++;
938 } while (len);
939 sg++;
940 }
941 /* Mark last command */
942 box--;
943 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -0700944
945 /* location of command block must be 64 bit aligned */
946 BUG_ON(host->dma.cmd_busaddr & 0x07);
947
948 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
949 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
950 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
951 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
952
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530953 /* Flush all data to memory before starting dma */
954 mb();
955
956unmap:
957 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530958 if (!data->host_cookie)
959 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
960 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530961 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
962 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -0700963 }
964
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530965 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700966}
967
Asutosh Dasaccacd42012-03-08 14:33:17 +0530968static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
969 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800970{
Asutosh Dasaccacd42012-03-08 14:33:17 +0530971 int rc = 0;
972 unsigned int dir;
973
974 /* Prevent memory corruption */
975 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
976
977 if (data->flags & MMC_DATA_READ)
978 dir = DMA_FROM_DEVICE;
979 else
980 dir = DMA_TO_DEVICE;
981
982 /* Make sg buffers DMA ready */
983 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
984 dir);
985
986 if (unlikely(rc != data->sg_len)) {
987 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
988 mmc_hostname(host->mmc), rc);
989 rc = -ENOMEM;
990 goto dma_map_err;
991 }
992
993 pr_debug("%s: %s: %s: sg_len=%d\n",
994 mmc_hostname(host->mmc), __func__,
995 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
996 data->sg_len);
997
998 goto out;
999
1000dma_map_err:
1001 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1002 data->flags);
1003out:
1004 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001005}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1007/**
1008 * Submits data transfer request to SPS driver
1009 *
1010 * This function make sg (scatter gather) data buffers
1011 * DMA ready and then submits them to SPS driver for
1012 * transfer.
1013 *
1014 * @host - Pointer to sdcc host structure
1015 * @data - Pointer to mmc_data structure
1016 *
1017 * @return 0 if success else negative value
1018 */
1019static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301020 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001021{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 int rc = 0;
1023 u32 flags;
1024 int i;
1025 u32 addr, len, data_cnt;
1026 struct scatterlist *sg = data->sg;
1027 struct sps_pipe *sps_pipe_handle;
1028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 host->sps.sg = data->sg;
1030 host->sps.num_ents = data->sg_len;
1031 host->sps.xfer_req_cnt = 0;
1032 if (data->flags & MMC_DATA_READ) {
1033 host->sps.dir = DMA_FROM_DEVICE;
1034 sps_pipe_handle = host->sps.prod.pipe_handle;
1035 } else {
1036 host->sps.dir = DMA_TO_DEVICE;
1037 sps_pipe_handle = host->sps.cons.pipe_handle;
1038 }
1039
Asutosh Dasaccacd42012-03-08 14:33:17 +05301040 if (!data->host_cookie) {
1041 rc = msmsdcc_prep_xfer(host, data);
1042 if (unlikely(rc < 0)) {
1043 host->dma.sg = NULL;
1044 host->dma.num_ents = 0;
1045 goto out;
1046 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 }
1048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 for (i = 0; i < data->sg_len; i++) {
1050 /*
1051 * Check if this is the last buffer to transfer?
1052 * If yes then set the INT and EOT flags.
1053 */
1054 len = sg_dma_len(sg);
1055 addr = sg_dma_address(sg);
1056 flags = 0;
1057 while (len > 0) {
1058 if (len > SPS_MAX_DESC_SIZE) {
1059 data_cnt = SPS_MAX_DESC_SIZE;
1060 } else {
1061 data_cnt = len;
1062 if (i == data->sg_len - 1)
1063 flags = SPS_IOVEC_FLAG_INT |
1064 SPS_IOVEC_FLAG_EOT;
1065 }
1066 rc = sps_transfer_one(sps_pipe_handle, addr,
1067 data_cnt, host, flags);
1068 if (rc) {
1069 pr_err("%s: sps_transfer_one() error! rc=%d,"
1070 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1071 mmc_hostname(host->mmc), rc,
1072 (u32)sps_pipe_handle, (u32)sg, i);
1073 goto dma_map_err;
1074 }
1075 addr += data_cnt;
1076 len -= data_cnt;
1077 host->sps.xfer_req_cnt++;
1078 }
1079 sg++;
1080 }
1081 goto out;
1082
1083dma_map_err:
1084 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301085 if (!data->host_cookie)
1086 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1087 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088out:
1089 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001090}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091#else
1092static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1093 struct mmc_data *data) { return 0; }
1094#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001095
1096static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001097msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1098 struct mmc_command *cmd, u32 *c)
1099{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301100 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 cmd->opcode, cmd->arg, cmd->flags);
1102
San Mehat56a8b5b2009-11-21 12:29:46 -08001103 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1104
1105 if (cmd->flags & MMC_RSP_PRESENT) {
1106 if (cmd->flags & MMC_RSP_136)
1107 *c |= MCI_CPSM_LONGRSP;
1108 *c |= MCI_CPSM_RESPONSE;
1109 }
1110
1111 if (/*interrupt*/0)
1112 *c |= MCI_CPSM_INTERRUPT;
1113
Asutosh Das05049132012-05-09 12:38:15 +05301114 /* DAT_CMD bit should be set for all ADTC */
1115 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001116 *c |= MCI_CSPM_DATCMD;
1117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301119 if (host->tuning_needed &&
1120 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1121
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301122 /*
1123 * For open ended block read operation (without CMD23),
1124 * AUTO_CMD19 bit should be set while sending the READ command.
1125 * For close ended block read operation (with CMD23),
1126 * AUTO_CMD19 bit should be set while sending CMD23.
1127 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301128 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1129 host->curr.mrq->cmd->opcode ==
1130 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301131 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301132 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1133 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301134 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1135 *c |= MCI_CSPM_AUTO_CMD19;
1136 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 }
1138
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301139 /* Clear CDR_EN bit for write operations */
1140 if (host->tuning_needed && cmd->mrq->data &&
1141 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1142 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1143 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1144
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301145 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301146 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301148 }
1149
San Mehat56a8b5b2009-11-21 12:29:46 -08001150 if (cmd == cmd->mrq->stop)
1151 *c |= MCI_CSPM_MCIABORT;
1152
San Mehat56a8b5b2009-11-21 12:29:46 -08001153 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301154 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001156 }
1157 host->curr.cmd = cmd;
1158}
1159
1160static void
1161msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1162 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001163{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301164 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001165 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001167 unsigned int pio_irqmask = 0;
1168
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301169 BUG_ON(!data->sg);
1170 BUG_ON(!data->sg_len);
1171
San Mehat9d2bd732009-09-22 16:44:22 -07001172 host->curr.data = data;
1173 host->curr.xfer_size = data->blksz * data->blocks;
1174 host->curr.xfer_remain = host->curr.xfer_size;
1175 host->curr.data_xfered = 0;
1176 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301177 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001178
San Mehat9d2bd732009-09-22 16:44:22 -07001179 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1180
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301181 if (host->curr.wait_for_auto_prog_done)
1182 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001183
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301184 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301185 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301187 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 if (!msmsdcc_is_dml_busy(host)) {
1189 if (!msmsdcc_sps_start_xfer(host, data)) {
1190 /* Now kick start DML transfer */
1191 mb();
1192 msmsdcc_dml_start_xfer(host, data);
1193 datactrl |= MCI_DPSM_DMAENABLE;
1194 host->sps.busy = 1;
1195 }
1196 } else {
1197 /*
1198 * Can't proceed with new transfer as
1199 * previous trasnfer is already in progress.
1200 * There is no point of going into PIO mode
1201 * as well. Is this a time to do kernel panic?
1202 */
1203 pr_err("%s: %s: DML HW is busy!!!"
1204 " Can't perform new SPS transfers"
1205 " now\n", mmc_hostname(host->mmc),
1206 __func__);
1207 }
1208 }
1209 }
1210
1211 /* Is data transfer in PIO mode required? */
1212 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001213 if (data->flags & MMC_DATA_READ) {
1214 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1215 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1216 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1217 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1219 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001220
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001221 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001222 }
1223
1224 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301225 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301226 else if (host->curr.use_wr_data_pend)
1227 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001228
San Mehat56a8b5b2009-11-21 12:29:46 -08001229 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001231 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301232 WARN(!timeout,
1233 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1234 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001235
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301236 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 /* Use ADM (Application Data Mover) HW for Data transfer */
1238 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001239 host->cmd_timeout = timeout;
1240 host->cmd_pio_irqmask = pio_irqmask;
1241 host->cmd_datactrl = datactrl;
1242 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1245 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001246 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001247
1248 if (cmd) {
1249 msmsdcc_start_command_deferred(host, cmd, &c);
1250 host->cmd_c = c;
1251 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1253 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1254 host->base + MMCIMASK0);
1255 mb();
1256 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001257 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1264 (~(MCI_IRQ_PIO))) | pio_irqmask,
1265 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001267
1268 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301269 /* Delay between data/command */
1270 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001271 /* Daisy-chain the command if requested */
1272 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301273 } else {
1274 /*
1275 * We don't need delay after writing to DATA_CTRL
1276 * register if we are not writing to CMD register
1277 * immediately after this. As we already have delay
1278 * before sending the command, we just need mb() here.
1279 */
1280 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001281 }
San Mehat9d2bd732009-09-22 16:44:22 -07001282 }
1283}
1284
1285static void
1286msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1287{
San Mehat56a8b5b2009-11-21 12:29:46 -08001288 msmsdcc_start_command_deferred(host, cmd, &c);
1289 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001290}
1291
1292static void
1293msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1294 unsigned int status)
1295{
1296 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301298 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1299 || data->mrq->cmd->opcode ==
1300 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 pr_err("%s: Data CRC error\n",
1302 mmc_hostname(host->mmc));
1303 pr_err("%s: opcode 0x%.8x\n", __func__,
1304 data->mrq->cmd->opcode);
1305 pr_err("%s: blksz %d, blocks %d\n", __func__,
1306 data->blksz, data->blocks);
1307 data->error = -EILSEQ;
1308 }
San Mehat9d2bd732009-09-22 16:44:22 -07001309 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 /* CRC is optional for the bus test commands, not all
1311 * cards respond back with CRC. However controller
1312 * waits for the CRC and times out. Hence ignore the
1313 * data timeouts during the Bustest.
1314 */
1315 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1316 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301317 pr_err("%s: CMD%d: Data timeout\n",
1318 mmc_hostname(host->mmc),
1319 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301321 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 }
San Mehat9d2bd732009-09-22 16:44:22 -07001323 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001324 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001325 data->error = -EIO;
1326 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001327 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001328 data->error = -EIO;
1329 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001330 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001332 data->error = -EIO;
1333 }
San Mehat9d2bd732009-09-22 16:44:22 -07001334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001336 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 host->dummy_52_needed = 0;
1338}
San Mehat9d2bd732009-09-22 16:44:22 -07001339
1340static int
1341msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1342{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001344 uint32_t *ptr = (uint32_t *) buffer;
1345 int count = 0;
1346
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301347 if (remain % 4)
1348 remain = ((remain >> 2) + 1) << 2;
1349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1351
1352 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001353 ptr++;
1354 count += sizeof(uint32_t);
1355
1356 remain -= sizeof(uint32_t);
1357 if (remain == 0)
1358 break;
1359 }
1360 return count;
1361}
1362
1363static int
1364msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001366{
1367 void __iomem *base = host->base;
1368 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 while (readl_relaxed(base + MMCISTATUS) &
1372 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1373 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001374
San Mehat9d2bd732009-09-22 16:44:22 -07001375 count = min(remain, maxcnt);
1376
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301377 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1378 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001379 ptr += count;
1380 remain -= count;
1381
1382 if (remain == 0)
1383 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 }
1385 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001386
1387 return ptr - buffer;
1388}
1389
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001390/*
1391 * Copy up to a word (4 bytes) between a scatterlist
1392 * and a temporary bounce buffer when the word lies across
1393 * two pages. The temporary buffer can then be read to/
1394 * written from the FIFO once.
1395 */
1396static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001397{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001398 struct msmsdcc_pio_data *pio = &host->pio;
1399 unsigned int bytes_avail;
1400
1401 if (host->curr.data->flags & MMC_DATA_READ)
1402 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1403 pio->bounce_buf_len);
1404 else
1405 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1406 pio->bounce_buf_len);
1407
1408 while (pio->bounce_buf_len != 4) {
1409 if (!sg_miter_next(&pio->sg_miter))
1410 break;
1411 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1412 4 - pio->bounce_buf_len);
1413 if (host->curr.data->flags & MMC_DATA_READ)
1414 memcpy(pio->sg_miter.addr,
1415 &pio->bounce_buf[pio->bounce_buf_len],
1416 bytes_avail);
1417 else
1418 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1419 pio->sg_miter.addr, bytes_avail);
1420
1421 pio->sg_miter.consumed = bytes_avail;
1422 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001423 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001424}
1425
1426/*
1427 * Use sg_miter_next to return as many 4-byte aligned
1428 * chunks as possible, using a temporary 4 byte buffer
1429 * for alignment if necessary
1430 */
1431static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1432{
1433 struct msmsdcc_pio_data *pio = &host->pio;
1434 unsigned int length, rlength;
1435 char *buffer;
1436
1437 if (!sg_miter_next(&pio->sg_miter))
1438 return 0;
1439
1440 buffer = pio->sg_miter.addr;
1441 length = pio->sg_miter.length;
1442
1443 if (length < host->curr.xfer_remain) {
1444 rlength = round_down(length, 4);
1445 if (rlength) {
1446 /*
1447 * We have a 4-byte aligned chunk.
1448 * The rounding will be reflected by
1449 * a call to msmsdcc_sg_consumed
1450 */
1451 length = rlength;
1452 goto sg_next_end;
1453 }
1454 /*
1455 * We have a length less than 4 bytes. Check to
1456 * see if more buffer is available, and combine
1457 * to make 4 bytes if possible.
1458 */
1459 pio->bounce_buf_len = length;
1460 memset(pio->bounce_buf, 0, 4);
1461
1462 /*
1463 * On a read, get 4 bytes from FIFO, and distribute
1464 * (4-bouce_buf_len) bytes into consecutive
1465 * sgl buffers when msmsdcc_sg_consumed is called
1466 */
1467 if (host->curr.data->flags & MMC_DATA_READ) {
1468 buffer = pio->bounce_buf;
1469 length = 4;
1470 goto sg_next_end;
1471 } else {
1472 _msmsdcc_sg_consume_word(host);
1473 buffer = pio->bounce_buf;
1474 length = pio->bounce_buf_len;
1475 }
1476 }
1477
1478sg_next_end:
1479 *buf = buffer;
1480 *len = length;
1481 return 1;
1482}
1483
1484/*
1485 * Update sg_miter.consumed based on how many bytes were
1486 * consumed. If the bounce buffer was used to read from FIFO,
1487 * redistribute into sgls.
1488 */
1489static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1490 unsigned int length)
1491{
1492 struct msmsdcc_pio_data *pio = &host->pio;
1493
1494 if (host->curr.data->flags & MMC_DATA_READ) {
1495 if (length > pio->sg_miter.consumed)
1496 /*
1497 * consumed 4 bytes, but sgl
1498 * describes < 4 bytes
1499 */
1500 _msmsdcc_sg_consume_word(host);
1501 else
1502 pio->sg_miter.consumed = length;
1503 } else
1504 if (length < pio->sg_miter.consumed)
1505 pio->sg_miter.consumed = length;
1506}
1507
1508static void msmsdcc_sg_start(struct msmsdcc_host *host)
1509{
1510 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1511
1512 host->pio.bounce_buf_len = 0;
1513
1514 if (host->curr.data->flags & MMC_DATA_READ)
1515 sg_miter_flags |= SG_MITER_TO_SG;
1516 else
1517 sg_miter_flags |= SG_MITER_FROM_SG;
1518
1519 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1520 host->curr.data->sg_len, sg_miter_flags);
1521}
1522
1523static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1524{
1525 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001526}
1527
San Mehat1cd22962010-02-03 12:59:29 -08001528static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001529msmsdcc_pio_irq(int irq, void *dev_id)
1530{
1531 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001533 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001534 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001535 unsigned int remain;
1536 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001537
Murali Palnati36448a42011-09-02 15:06:18 +05301538 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301543 (MCI_IRQ_PIO)) == 0) {
1544 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301545 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301546 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547#if IRQ_DEBUG
1548 msmsdcc_print_status(host, "irq1-r", status);
1549#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001550 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001551
1552 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001553 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1556 | MCI_RXDATAAVLBL)))
1557 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001558
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001559 if (!msmsdcc_sg_next(host, &buffer, &remain))
1560 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001561
San Mehat9d2bd732009-09-22 16:44:22 -07001562 len = 0;
1563 if (status & MCI_RXACTIVE)
1564 len = msmsdcc_pio_read(host, buffer, remain);
1565 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001567
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301568 /* len might have aligned to 32bits above */
1569 if (len > remain)
1570 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001571
San Mehat9d2bd732009-09-22 16:44:22 -07001572 host->curr.xfer_remain -= len;
1573 host->curr.data_xfered += len;
1574 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001575 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 if (remain) /* Done with this page? */
1578 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001581 } while (1);
1582
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001583 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001584 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1587 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1588 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1589 host->base + MMCIMASK0);
1590 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301591 /*
1592 * back to back write to MASK0 register don't need
1593 * synchronization delay.
1594 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1596 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1597 }
1598 mb();
1599 } else if (!host->curr.xfer_remain) {
1600 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1601 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1602 mb();
1603 }
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001606
1607 return IRQ_HANDLED;
1608}
1609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610static void
1611msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1612
1613static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1614 struct mmc_data *data)
1615{
1616 u32 loop_cnt = 0;
1617
1618 /*
1619 * For read commands with data less than fifo size, it is possible to
1620 * get DATAEND first and RXDATA_AVAIL might be set later because of
1621 * synchronization delay through the asynchronous RX FIFO. Thus, for
1622 * such cases, even after DATAEND interrupt is received software
1623 * should poll for RXDATA_AVAIL until the requested data is read out
1624 * of FIFO. This change is needed to get around this abnormal but
1625 * sometimes expected behavior of SDCC3 controller.
1626 *
1627 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1628 * after the data is loaded into RX FIFO. This would amount to less
1629 * than a microsecond and thus looping for 1000 times is good enough
1630 * for that delay.
1631 */
1632 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1633 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1634 spin_unlock(&host->lock);
1635 msmsdcc_pio_irq(1, host);
1636 spin_lock(&host->lock);
1637 }
1638 }
1639 if (loop_cnt == 1000) {
1640 pr_info("%s: Timed out while polling for Rx Data\n",
1641 mmc_hostname(host->mmc));
1642 data->error = -ETIMEDOUT;
1643 msmsdcc_reset_and_restore(host);
1644 }
1645}
1646
San Mehat9d2bd732009-09-22 16:44:22 -07001647static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1648{
1649 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001650
1651 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301652 if (mmc_resp_type(cmd))
1653 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1654 /*
1655 * Read rest of the response registers only if
1656 * long response is expected for this command
1657 */
1658 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1659 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1660 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1661 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1662 }
San Mehat9d2bd732009-09-22 16:44:22 -07001663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301665 pr_debug("%s: CMD%d: Command timeout\n",
1666 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001667 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301669 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301670 pr_err("%s: CMD%d: Command CRC error\n",
1671 mmc_hostname(host->mmc), cmd->opcode);
1672 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001673 cmd->error = -EILSEQ;
1674 }
1675
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301676 if (!cmd->error) {
1677 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1678 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1679 mod_timer(&host->req_tout_timer, (jiffies +
1680 msecs_to_jiffies(host->curr.req_tout_ms)));
1681 }
1682 }
1683
San Mehat9d2bd732009-09-22 16:44:22 -07001684 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001685 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301686 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001687 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301689 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690 /* Stop current SPS transfer */
1691 msmsdcc_sps_exit_curr_xfer(host);
1692 }
San Mehat9d2bd732009-09-22 16:44:22 -07001693 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301694 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001695 msmsdcc_stop_data(host);
1696 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301697 } else { /* host->data == NULL */
1698 if (!cmd->error && host->prog_enable) {
1699 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301701 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301703 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301704 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301705 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301706 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001707 if (host->dummy_52_needed)
1708 host->dummy_52_needed = 0;
1709 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301711 msmsdcc_request_end(host, cmd->mrq);
1712 }
1713 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301714 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301715 if (cmd == host->curr.mrq->sbc)
1716 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1717 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1718 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301719 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001720 }
1721}
1722
San Mehat9d2bd732009-09-22 16:44:22 -07001723static irqreturn_t
1724msmsdcc_irq(int irq, void *dev_id)
1725{
1726 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001727 u32 status;
1728 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001730
1731 spin_lock(&host->lock);
1732
1733 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 struct mmc_command *cmd;
1735 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 if (timer) {
1738 timer = 0;
1739 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001740 }
San Mehat9d2bd732009-09-22 16:44:22 -07001741
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301742 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 pr_debug("%s: %s: SDIO async irq received\n",
1744 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301745
1746 /*
1747 * Only async interrupt can come when clocks are off,
1748 * disable further interrupts and enable them when
1749 * clocks are on.
1750 */
1751 if (!host->sdcc_irq_disabled) {
1752 disable_irq_nosync(irq);
1753 host->sdcc_irq_disabled = 1;
1754 }
1755
1756 /*
1757 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1758 * will take care of signaling sdio irq during
1759 * mmc_sdio_resume().
1760 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301761 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301762 /*
1763 * This is a wakeup interrupt so hold wakelock
1764 * until SDCC resume is handled.
1765 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301767 } else {
1768 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301769 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301770 spin_lock(&host->lock);
1771 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301772 ret = 1;
1773 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 }
1775
1776 status = readl_relaxed(host->base + MMCISTATUS);
1777
1778 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1779 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001780 break;
1781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001782#if IRQ_DEBUG
1783 msmsdcc_print_status(host, "irq0-r", status);
1784#endif
1785 status &= readl_relaxed(host->base + MMCIMASK0);
1786 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301787 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301788 if (host->clk_rate <=
1789 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301790 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791#if IRQ_DEBUG
1792 msmsdcc_print_status(host, "irq0-p", status);
1793#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795 if (status & MCI_SDIOINTROPE) {
1796 if (host->sdcc_suspending)
1797 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301798 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301800 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001801 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001802 data = host->curr.data;
1803
1804 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1806 MCI_CMDTIMEOUT)) {
1807 if (status & MCI_CMDTIMEOUT)
1808 pr_debug("%s: dummy CMD52 timeout\n",
1809 mmc_hostname(host->mmc));
1810 if (status & MCI_CMDCRCFAIL)
1811 pr_debug("%s: dummy CMD52 CRC failed\n",
1812 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001813 host->dummy_52_sent = 0;
1814 host->dummy_52_needed = 0;
1815 if (data) {
1816 msmsdcc_stop_data(host);
1817 msmsdcc_request_end(host, data->mrq);
1818 }
1819 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 spin_unlock(&host->lock);
1821 return IRQ_HANDLED;
1822 }
1823 break;
1824 }
1825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 /*
1827 * Check for proper command response
1828 */
1829 cmd = host->curr.cmd;
1830 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1831 MCI_CMDTIMEOUT | MCI_PROGDONE |
1832 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1833 msmsdcc_do_cmdirq(host, status);
1834 }
1835
Sathish Ambley081d7842011-11-29 11:19:41 -08001836 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 /* Check for data errors */
1838 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1839 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1840 msmsdcc_data_err(host, data, status);
1841 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301842 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001843 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301844 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 /* Stop current SPS transfer */
1846 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301847 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 msmsdcc_reset_and_restore(host);
1849 if (host->curr.data)
1850 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301851 if (!data->stop || (host->curr.mrq->sbc
1852 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 timer |=
1854 msmsdcc_request_end(host,
1855 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301856 else if ((host->curr.mrq->sbc
1857 && data->error) ||
1858 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 msmsdcc_start_command(host,
1860 data->stop,
1861 0);
1862 timer = 1;
1863 }
1864 }
1865 }
1866
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301867 /* Check for prog done */
1868 if (host->curr.wait_for_auto_prog_done &&
1869 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301870 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 /* Check for data done */
1873 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1874 host->curr.got_dataend = 1;
1875
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301876 if (host->curr.got_dataend &&
1877 (!host->curr.wait_for_auto_prog_done ||
1878 (host->curr.wait_for_auto_prog_done &&
1879 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 /*
1881 * If DMA is still in progress, we complete
1882 * via the completion handler
1883 */
1884 if (!host->dma.busy && !host->sps.busy) {
1885 /*
1886 * There appears to be an issue in the
1887 * controller where if you request a
1888 * small block transfer (< fifo size),
1889 * you may get your DATAEND/DATABLKEND
1890 * irq without the PIO data irq.
1891 *
1892 * Check to see if theres still data
1893 * to be read, and simulate a PIO irq.
1894 */
1895 if (data->flags & MMC_DATA_READ)
1896 msmsdcc_wait_for_rxdata(host,
1897 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 if (!data->error) {
1899 host->curr.data_xfered =
1900 host->curr.xfer_size;
1901 host->curr.xfer_remain -=
1902 host->curr.xfer_size;
1903 }
1904
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001905 if (!host->dummy_52_needed) {
1906 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301907 if (!data->stop ||
1908 (host->curr.mrq->sbc
1909 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001910 msmsdcc_request_end(
1911 host,
1912 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301913 else if ((host->curr.mrq->sbc
1914 && data->error) ||
1915 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001916 msmsdcc_start_command(
1917 host,
1918 data->stop, 0);
1919 timer = 1;
1920 }
1921 } else {
1922 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001924 &dummy52cmd,
1925 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 }
1927 }
1928 }
1929 }
1930
San Mehat9d2bd732009-09-22 16:44:22 -07001931 ret = 1;
1932 } while (status);
1933
1934 spin_unlock(&host->lock);
1935
San Mehat9d2bd732009-09-22 16:44:22 -07001936 return IRQ_RETVAL(ret);
1937}
1938
1939static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301940msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1941 bool is_first_request)
1942{
1943 struct msmsdcc_host *host = mmc_priv(mmc);
1944 struct mmc_data *data = mrq->data;
1945 int rc = 0;
1946
1947 if (unlikely(!data)) {
1948 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1949 __func__);
1950 return;
1951 }
1952 if (unlikely(data->host_cookie)) {
1953 /* Very wrong */
1954 data->host_cookie = 0;
1955 pr_err("%s: %s Request reposted for prepare\n",
1956 mmc_hostname(mmc), __func__);
1957 return;
1958 }
1959
1960 if (!msmsdcc_is_dma_possible(host, data))
1961 return;
1962
1963 rc = msmsdcc_prep_xfer(host, data);
1964 if (unlikely(rc < 0)) {
1965 data->host_cookie = 0;
1966 return;
1967 }
1968
1969 data->host_cookie = 1;
1970}
1971
1972static void
1973msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1974{
1975 struct msmsdcc_host *host = mmc_priv(mmc);
1976 unsigned int dir;
1977 struct mmc_data *data = mrq->data;
1978
1979 if (unlikely(!data)) {
1980 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1981 __func__);
1982 return;
1983 }
1984 if (data->flags & MMC_DATA_READ)
1985 dir = DMA_FROM_DEVICE;
1986 else
1987 dir = DMA_TO_DEVICE;
1988
1989 if (data->host_cookie)
1990 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1991 data->sg_len, dir);
1992
1993 data->host_cookie = 0;
1994}
1995
1996static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1998{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301999 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302001 if ((mrq->data->flags & MMC_DATA_READ) ||
2002 host->curr.use_wr_data_pend)
2003 msmsdcc_start_data(host, mrq->data,
2004 mrq->sbc ? mrq->sbc : mrq->cmd,
2005 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302006 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302007 msmsdcc_start_command(host,
2008 mrq->sbc ? mrq->sbc : mrq->cmd,
2009 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 } else {
2011 msmsdcc_start_command(host, mrq->cmd, 0);
2012 }
2013}
2014
2015static void
San Mehat9d2bd732009-09-22 16:44:22 -07002016msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2017{
2018 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302019 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07002020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 /*
2022 * Get the SDIO AL client out of LPM.
2023 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002024 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 if (host->plat->is_sdio_al_client)
2026 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002027
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302028 /* check if sps pipe reset is pending? */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302029 if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302030 msmsdcc_sps_pipes_reset_and_restore(host);
2031 host->sps.pipe_reset_pending = false;
2032 }
San Mehat9d2bd732009-09-22 16:44:22 -07002033
2034 spin_lock_irqsave(&host->lock, flags);
2035
San Mehat9d2bd732009-09-22 16:44:22 -07002036 if (host->eject) {
2037 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2038 mrq->cmd->error = 0;
2039 mrq->data->bytes_xfered = mrq->data->blksz *
2040 mrq->data->blocks;
2041 } else
2042 mrq->cmd->error = -ENOMEDIUM;
2043
2044 spin_unlock_irqrestore(&host->lock, flags);
2045 mmc_request_done(mmc, mrq);
2046 return;
2047 }
2048
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302049 /*
subhashjf181c292012-05-02 13:07:40 +05302050 * Don't start the request if SDCC is not in proper state to handle it
2051 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302052 if (!host->pwr || !atomic_read(&host->clks_on)
2053 || host->sdcc_irq_disabled) {
subhashjf181c292012-05-02 13:07:40 +05302054 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2055 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2056 __func__, mrq->cmd->opcode);
2057 msmsdcc_dump_sdcc_state(host);
2058 mrq->cmd->error = -EIO;
2059 if (mrq->data) {
2060 mrq->data->error = -EIO;
2061 mrq->data->bytes_xfered = 0;
2062 }
2063 spin_unlock_irqrestore(&host->lock, flags);
2064 mmc_request_done(mmc, mrq);
2065 return;
2066 }
2067
2068 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2069 " other request (CMD%d) is in progress\n",
2070 mmc_hostname(host->mmc), __func__,
2071 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2072
2073 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302074 * Set timeout value to 10 secs (or more in case of buggy cards)
2075 */
2076 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302077 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302078 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302079 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302080 /*
2081 * Kick the software request timeout timer here with the timeout
2082 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302083 */
2084 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302085 (jiffies +
2086 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002087
San Mehat9d2bd732009-09-22 16:44:22 -07002088 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302089 if (mrq->sbc) {
2090 mrq->sbc->mrq = mrq;
2091 mrq->sbc->data = mrq->data;
2092 }
2093
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302094 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302095 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302096 /*
2097 * Auto-prog done will be enabled for following cases:
2098 * mrq->sbc | mrq->stop
2099 * _____________|________________
2100 * True | Don't care
2101 * False | False (CMD24, ACMD25 use case)
2102 */
2103 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302104 host->curr.wait_for_auto_prog_done = true;
2105 } else {
2106 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2107 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 host->dummy_52_needed = 1;
2109 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302110
Subhash Jadavanif5277752011-10-12 16:47:52 +05302111 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2112 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2113 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002114 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302115
Subhash Jadavanif5277752011-10-12 16:47:52 +05302116 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302117
San Mehat9d2bd732009-09-22 16:44:22 -07002118 spin_unlock_irqrestore(&host->lock, flags);
2119}
2120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2122 int min_uV, int max_uV)
2123{
2124 int rc = 0;
2125
2126 if (vreg->set_voltage_sup) {
2127 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2128 if (rc) {
2129 pr_err("%s: regulator_set_voltage(%s) failed."
2130 " min_uV=%d, max_uV=%d, rc=%d\n",
2131 __func__, vreg->name, min_uV, max_uV, rc);
2132 }
2133 }
2134
2135 return rc;
2136}
2137
2138static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2139 int uA_load)
2140{
2141 int rc = 0;
2142
Krishna Kondafea60182011-11-01 16:01:34 -07002143 /* regulators that do not support regulator_set_voltage also
2144 do not support regulator_set_optimum_mode */
2145 if (vreg->set_voltage_sup) {
2146 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2147 if (rc < 0)
2148 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2149 "uA_load=%d) failed. rc=%d\n", __func__,
2150 vreg->name, uA_load, rc);
2151 else
2152 /* regulator_set_optimum_mode() can return non zero
2153 * value even for success case.
2154 */
2155 rc = 0;
2156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157
2158 return rc;
2159}
2160
2161static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2162 struct device *dev)
2163{
2164 int rc = 0;
2165
2166 /* check if regulator is already initialized? */
2167 if (vreg->reg)
2168 goto out;
2169
2170 /* Get the regulator handle */
2171 vreg->reg = regulator_get(dev, vreg->name);
2172 if (IS_ERR(vreg->reg)) {
2173 rc = PTR_ERR(vreg->reg);
2174 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2175 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002176 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002178
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302179 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002180 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302181 /* sanity check */
2182 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2183 pr_err("%s: %s invalid constraints specified\n",
2184 __func__, vreg->name);
2185 rc = -EINVAL;
2186 }
2187 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189out:
2190 return rc;
2191}
2192
2193static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2194{
2195 if (vreg->reg)
2196 regulator_put(vreg->reg);
2197}
2198
2199/* This init function should be called only once for each SDCC slot */
2200static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2201{
2202 int rc = 0;
2203 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302204 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205 struct device *dev = mmc_dev(host->mmc);
2206
2207 curr_slot = host->plat->vreg_data;
2208 if (!curr_slot)
2209 goto out;
2210
2211 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302212 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213
2214 if (is_init) {
2215 /*
2216 * Get the regulator handle from voltage regulator framework
2217 * and then try to set the voltage level for the regulator
2218 */
2219 if (curr_vdd_reg) {
2220 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2221 if (rc)
2222 goto out;
2223 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302224 if (curr_vdd_io_reg) {
2225 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 if (rc)
2227 goto vdd_reg_deinit;
2228 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002229 rc = msmsdcc_vreg_reset(host);
2230 if (rc)
2231 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2232 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 goto out;
2234 } else {
2235 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302236 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302238vdd_io_reg_deinit:
2239 if (curr_vdd_io_reg)
2240 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241vdd_reg_deinit:
2242 if (curr_vdd_reg)
2243 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2244out:
2245 return rc;
2246}
2247
2248static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2249{
2250 int rc = 0;
2251
Subhash Jadavanicc922692011-08-01 23:05:01 +05302252 /* Put regulator in HPM (high power mode) */
2253 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2254 if (rc < 0)
2255 goto out;
2256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 if (!vreg->is_enabled) {
2258 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302259 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2260 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 if (rc)
2262 goto out;
2263
2264 rc = regulator_enable(vreg->reg);
2265 if (rc) {
2266 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2267 __func__, vreg->name, rc);
2268 goto out;
2269 }
2270 vreg->is_enabled = true;
2271 }
2272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273out:
2274 return rc;
2275}
2276
Krishna Konda3c4142d2012-06-27 11:01:56 -07002277static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278{
2279 int rc = 0;
2280
2281 /* Never disable regulator marked as always_on */
2282 if (vreg->is_enabled && !vreg->always_on) {
2283 rc = regulator_disable(vreg->reg);
2284 if (rc) {
2285 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2286 __func__, vreg->name, rc);
2287 goto out;
2288 }
2289 vreg->is_enabled = false;
2290
2291 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2292 if (rc < 0)
2293 goto out;
2294
2295 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302296 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 if (rc)
2298 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002299 } else if (vreg->is_enabled && vreg->always_on) {
2300 if (!is_init && vreg->lpm_sup) {
2301 /* Put always_on regulator in LPM (low power mode) */
2302 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2303 if (rc < 0)
2304 goto out;
2305 } else if (is_init && vreg->reset_at_init) {
2306 /**
2307 * The regulator might not actually be disabled if it
2308 * is shared and in use by other drivers.
2309 */
2310 rc = regulator_disable(vreg->reg);
2311 if (rc) {
2312 pr_err("%s: regulator_disable(%s) failed at " \
2313 "bootup. rc=%d\n", __func__,
2314 vreg->name, rc);
2315 goto out;
2316 }
2317 vreg->is_enabled = false;
2318 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 }
2320out:
2321 return rc;
2322}
2323
Krishna Konda3c4142d2012-06-27 11:01:56 -07002324static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2325 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326{
2327 int rc = 0, i;
2328 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302329 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330
2331 curr_slot = host->plat->vreg_data;
2332 if (!curr_slot)
2333 goto out;
2334
Subhash Jadavani937c7502012-06-01 15:34:46 +05302335 vreg_table[0] = curr_slot->vdd_data;
2336 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337
2338 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2339 if (vreg_table[i]) {
2340 if (enable)
2341 rc = msmsdcc_vreg_enable(vreg_table[i]);
2342 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002343 rc = msmsdcc_vreg_disable(vreg_table[i],
2344 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345 if (rc)
2346 goto out;
2347 }
2348 }
2349out:
2350 return rc;
2351}
2352
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002353/*
2354 * Reset vreg by ensuring it is off during probe. A call
2355 * to enable vreg is needed to balance disable vreg
2356 */
2357static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2358{
2359 int rc;
2360
Krishna Konda3c4142d2012-06-27 11:01:56 -07002361 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002362 if (rc)
2363 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002364 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002365 return rc;
2366}
2367
Subhash Jadavani937c7502012-06-01 15:34:46 +05302368enum vdd_io_level {
2369 /* set vdd_io_data->low_vol_level */
2370 VDD_IO_LOW,
2371 /* set vdd_io_data->high_vol_level */
2372 VDD_IO_HIGH,
2373 /*
2374 * set whatever there in voltage_level (third argument) of
2375 * msmsdcc_set_vdd_io_vol() function.
2376 */
2377 VDD_IO_SET_LEVEL,
2378};
2379
2380static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2381 enum vdd_io_level level,
2382 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383{
2384 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302385 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386
2387 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302388 struct msm_mmc_reg_data *vdd_io_reg =
2389 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390
Subhash Jadavani937c7502012-06-01 15:34:46 +05302391 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2392 switch (level) {
2393 case VDD_IO_LOW:
2394 set_level = vdd_io_reg->low_vol_level;
2395 break;
2396 case VDD_IO_HIGH:
2397 set_level = vdd_io_reg->high_vol_level;
2398 break;
2399 case VDD_IO_SET_LEVEL:
2400 set_level = voltage_level;
2401 break;
2402 default:
2403 pr_err("%s: %s: invalid argument level = %d",
2404 mmc_hostname(host->mmc), __func__,
2405 level);
2406 rc = -EINVAL;
2407 goto out;
2408 }
2409 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2410 set_level, set_level);
2411 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 }
2413
Subhash Jadavani937c7502012-06-01 15:34:46 +05302414out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302415 return rc;
2416}
2417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2419{
2420 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2421 return 1;
2422 return 0;
2423}
2424
Asutosh Dasf5298c32012-04-03 14:51:47 +05302425/*
2426 * Any function calling msmsdcc_setup_clocks must
2427 * acquire clk_mutex. May sleep.
2428 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302429static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302431 int rc = 0;
2432
2433 if (enable && !atomic_read(&host->clks_on)) {
2434 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2435 rc = clk_prepare_enable(host->bus_clk);
2436 if (rc) {
2437 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2438 mmc_hostname(host->mmc), __func__, rc);
2439 goto out;
2440 }
2441 }
2442 if (!IS_ERR(host->pclk)) {
2443 rc = clk_prepare_enable(host->pclk);
2444 if (rc) {
2445 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2446 mmc_hostname(host->mmc), __func__, rc);
2447 goto disable_bus;
2448 }
2449 }
2450 rc = clk_prepare_enable(host->clk);
2451 if (rc) {
2452 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2453 mmc_hostname(host->mmc), __func__, rc);
2454 goto disable_pclk;
2455 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302456 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302457 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302458 atomic_set(&host->clks_on, 1);
2459 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302460 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302461 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302462 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302464 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302465 if (!IS_ERR_OR_NULL(host->bus_clk))
2466 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302467 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302469 goto out;
2470
2471disable_pclk:
2472 if (!IS_ERR_OR_NULL(host->pclk))
2473 clk_disable_unprepare(host->pclk);
2474disable_bus:
2475 if (!IS_ERR_OR_NULL(host->bus_clk))
2476 clk_disable_unprepare(host->bus_clk);
2477out:
2478 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479}
2480
2481static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2482 unsigned int req_clk)
2483{
2484 unsigned int sel_clk = -1;
2485
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302486 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2487 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2488 goto out;
2489 }
2490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2492 unsigned char cnt;
2493
2494 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2495 if (host->plat->sup_clk_table[cnt] > req_clk)
2496 break;
2497 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2498 sel_clk = host->plat->sup_clk_table[cnt];
2499 break;
2500 } else
2501 sel_clk = host->plat->sup_clk_table[cnt];
2502 }
2503 } else {
2504 if ((req_clk < host->plat->msmsdcc_fmax) &&
2505 (req_clk > host->plat->msmsdcc_fmid))
2506 sel_clk = host->plat->msmsdcc_fmid;
2507 else
2508 sel_clk = req_clk;
2509 }
2510
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302511out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 return sel_clk;
2513}
2514
2515static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2516 struct msmsdcc_host *host)
2517{
2518 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2519 return host->plat->sup_clk_table[0];
2520 else
2521 return host->plat->msmsdcc_fmin;
2522}
2523
2524static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2525 struct msmsdcc_host *host)
2526{
2527 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2528 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2529 else
2530 return host->plat->msmsdcc_fmax;
2531}
2532
2533static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302534{
2535 struct msm_mmc_gpio_data *curr;
2536 int i, rc = 0;
2537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302539 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302540 if (!gpio_is_valid(curr->gpio[i].no)) {
2541 rc = -EINVAL;
2542 pr_err("%s: Invalid gpio = %d\n",
2543 mmc_hostname(host->mmc), curr->gpio[i].no);
2544 goto free_gpios;
2545 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302546 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 if (curr->gpio[i].is_always_on &&
2548 curr->gpio[i].is_enabled)
2549 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302550 rc = gpio_request(curr->gpio[i].no,
2551 curr->gpio[i].name);
2552 if (rc) {
2553 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2554 mmc_hostname(host->mmc),
2555 curr->gpio[i].no,
2556 curr->gpio[i].name, rc);
2557 goto free_gpios;
2558 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002559 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302560 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561 if (curr->gpio[i].is_always_on)
2562 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302563 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302565 }
2566 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302568
2569free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302570 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302571 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572 curr->gpio[i].is_enabled = false;
2573 }
2574out:
2575 return rc;
2576}
2577
2578static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2579{
2580 struct msm_mmc_pad_data *curr;
2581 int i;
2582
2583 curr = host->plat->pin_data->pad_data;
2584 for (i = 0; i < curr->drv->size; i++) {
2585 if (enable)
2586 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2587 curr->drv->on[i].val);
2588 else
2589 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2590 curr->drv->off[i].val);
2591 }
2592
2593 for (i = 0; i < curr->pull->size; i++) {
2594 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002595 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 curr->pull->on[i].val);
2597 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002598 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 curr->pull->off[i].val);
2600 }
2601
2602 return 0;
2603}
2604
2605static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2606{
2607 int rc = 0;
2608
2609 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2610 return 0;
2611
2612 if (host->plat->pin_data->is_gpio)
2613 rc = msmsdcc_setup_gpio(host, enable);
2614 else
2615 rc = msmsdcc_setup_pad(host, enable);
2616
2617 if (!rc)
2618 host->plat->pin_data->cfg_sts = enable;
2619
2620 return rc;
2621}
2622
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302623static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2624 unsigned mode)
2625{
2626 int ret = 0;
2627 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2628
2629 if (!pin)
2630 return 0;
2631
2632 switch (mode) {
2633 case SDC_DAT1_DISABLE:
2634 ret = msm_mpm_enable_pin(pin, 0);
2635 break;
2636 case SDC_DAT1_ENABLE:
2637 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2638 ret = msm_mpm_enable_pin(pin, 1);
2639 break;
2640 case SDC_DAT1_ENWAKE:
2641 ret = msm_mpm_set_pin_wake(pin, 1);
2642 break;
2643 case SDC_DAT1_DISWAKE:
2644 ret = msm_mpm_set_pin_wake(pin, 0);
2645 break;
2646 default:
2647 ret = -EINVAL;
2648 break;
2649 }
2650
2651 return ret;
2652}
2653
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302654static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2655{
2656 u32 pwr = 0;
2657 int ret = 0;
2658 struct mmc_host *mmc = host->mmc;
2659
2660 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2661 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2662 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002663 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302664
2665 if (ret) {
2666 pr_err("%s: Failed to setup voltage regulators\n",
2667 mmc_hostname(host->mmc));
2668 goto out;
2669 }
2670
2671 switch (ios->power_mode) {
2672 case MMC_POWER_OFF:
2673 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302674 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302675 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302676 * If VDD IO rail is always on, set low voltage for VDD
2677 * IO rail when slot is not in use (like when card is not
2678 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302679 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302680 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302681 msmsdcc_setup_pins(host, false);
2682 break;
2683 case MMC_POWER_UP:
2684 /* writing PWR_UP bit is redundant */
2685 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302686 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302687
Subhash Jadavani937c7502012-06-01 15:34:46 +05302688 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302689 msmsdcc_setup_pins(host, true);
2690 break;
2691 case MMC_POWER_ON:
2692 pwr = MCI_PWR_ON;
2693 break;
2694 }
2695
2696out:
2697 return pwr;
2698}
2699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2701{
2702 unsigned int wakeup_irq;
2703
2704 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2705 host->plat->sdiowakeup_irq :
2706 host->core_irqres->start;
2707
2708 if (!host->irq_wake_enabled) {
2709 enable_irq_wake(wakeup_irq);
2710 host->irq_wake_enabled = true;
2711 }
2712}
2713
2714static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2715{
2716 unsigned int wakeup_irq;
2717
2718 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2719 host->plat->sdiowakeup_irq :
2720 host->core_irqres->start;
2721
2722 if (host->irq_wake_enabled) {
2723 disable_irq_wake(wakeup_irq);
2724 host->irq_wake_enabled = false;
2725 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302726}
2727
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302728/* Returns required bandwidth in Bytes per Sec */
2729static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2730 struct mmc_ios *ios)
2731{
2732 unsigned int bw;
2733
2734 bw = host->clk_rate;
2735 /*
2736 * For DDR mode, SDCC controller clock will be at
2737 * the double rate than the actual clock that goes to card.
2738 */
2739 if (ios->bus_width == MMC_BUS_WIDTH_4)
2740 bw /= 2;
2741 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2742 bw /= 8;
2743
2744 return bw;
2745}
2746
2747static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2748 unsigned int bw)
2749{
2750 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2751 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2752 int i;
2753
2754 if (host->msm_bus_vote.is_max_bw_needed && bw)
2755 return host->msm_bus_vote.max_bw_vote;
2756
2757 for (i = 0; i < size; i++) {
2758 if (bw <= table[i])
2759 break;
2760 }
2761
2762 if (i && (i == size))
2763 i--;
2764
2765 return i;
2766}
2767
2768static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2769{
2770 int rc = 0;
2771 struct msm_bus_scale_pdata *use_cases;
2772
2773 if (host->plat->msm_bus_voting_data &&
2774 host->plat->msm_bus_voting_data->use_cases &&
2775 host->plat->msm_bus_voting_data->bw_vecs &&
2776 host->plat->msm_bus_voting_data->bw_vecs_size) {
2777 use_cases = host->plat->msm_bus_voting_data->use_cases;
2778 host->msm_bus_vote.client_handle =
2779 msm_bus_scale_register_client(use_cases);
2780 } else {
2781 return 0;
2782 }
2783
2784 if (!host->msm_bus_vote.client_handle) {
2785 pr_err("%s: msm_bus_scale_register_client() failed\n",
2786 mmc_hostname(host->mmc));
2787 rc = -EFAULT;
2788 } else {
2789 /* cache the vote index for minimum and maximum bandwidth */
2790 host->msm_bus_vote.min_bw_vote =
2791 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2792 host->msm_bus_vote.max_bw_vote =
2793 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2794 }
2795
2796 return rc;
2797}
2798
2799static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2800{
2801 if (host->msm_bus_vote.client_handle)
2802 msm_bus_scale_unregister_client(
2803 host->msm_bus_vote.client_handle);
2804}
2805
2806/*
2807 * This function must be called with host lock acquired.
2808 * Caller of this function should also ensure that msm bus client
2809 * handle is not null.
2810 */
2811static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2812 int vote,
2813 unsigned long flags)
2814{
2815 int rc = 0;
2816
2817 if (vote != host->msm_bus_vote.curr_vote) {
2818 spin_unlock_irqrestore(&host->lock, flags);
2819 rc = msm_bus_scale_client_update_request(
2820 host->msm_bus_vote.client_handle, vote);
2821 if (rc)
2822 pr_err("%s: msm_bus_scale_client_update_request() failed."
2823 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2824 mmc_hostname(host->mmc),
2825 host->msm_bus_vote.client_handle, vote, rc);
2826 spin_lock_irqsave(&host->lock, flags);
2827 if (!rc)
2828 host->msm_bus_vote.curr_vote = vote;
2829 }
2830
2831 return rc;
2832}
2833
2834/*
2835 * Internal work. Work to set 0 bandwidth for msm bus.
2836 */
2837static void msmsdcc_msm_bus_work(struct work_struct *work)
2838{
2839 struct msmsdcc_host *host = container_of(work,
2840 struct msmsdcc_host,
2841 msm_bus_vote.vote_work.work);
2842 unsigned long flags;
2843
2844 if (!host->msm_bus_vote.client_handle)
2845 return;
2846
2847 spin_lock_irqsave(&host->lock, flags);
2848 /* don't vote for 0 bandwidth if any request is in progress */
2849 if (!host->curr.mrq)
2850 msmsdcc_msm_bus_set_vote(host,
2851 host->msm_bus_vote.min_bw_vote, flags);
2852 else
2853 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2854 " bus voting to 0 bandwidth\n",
2855 mmc_hostname(host->mmc), __func__);
2856 spin_unlock_irqrestore(&host->lock, flags);
2857}
2858
2859/*
2860 * This function cancels any scheduled delayed work
2861 * and sets the bus vote based on ios argument.
2862 * If "ios" argument is NULL, bandwidth required is 0 else
2863 * calculate the bandwidth based on ios parameters.
2864 */
2865static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2866 struct msmsdcc_host *host,
2867 struct mmc_ios *ios)
2868{
2869 unsigned long flags;
2870 unsigned int bw;
2871 int vote;
2872
2873 if (!host->msm_bus_vote.client_handle)
2874 return;
2875
2876 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2877
2878 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2879 spin_lock_irqsave(&host->lock, flags);
2880 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2881 msmsdcc_msm_bus_set_vote(host, vote, flags);
2882 spin_unlock_irqrestore(&host->lock, flags);
2883}
2884
2885/* This function queues a work which will set the bandwidth requiement to 0 */
2886static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2887{
2888 unsigned long flags;
2889
2890 if (!host->msm_bus_vote.client_handle)
2891 return;
2892
2893 spin_lock_irqsave(&host->lock, flags);
2894 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2895 queue_delayed_work(system_nrt_wq,
2896 &host->msm_bus_vote.vote_work,
2897 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2898 spin_unlock_irqrestore(&host->lock, flags);
2899}
2900
San Mehat9d2bd732009-09-22 16:44:22 -07002901static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302902msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2903{
2904 struct mmc_host *mmc = host->mmc;
2905
2906 /*
2907 * SDIO_AL clients has different mechanism of handling LPM through
2908 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2909 * part of that. Here, we are interested only in clients like WLAN.
2910 */
2911 if (!(mmc->card && mmc_card_sdio(mmc->card))
2912 || host->plat->is_sdio_al_client)
2913 goto out;
2914
2915 if (!host->sdcc_suspended) {
2916 /*
2917 * When MSM is not in power collapse and we
2918 * are disabling clocks, enable bit 22 in MASK0
2919 * to handle asynchronous SDIO interrupts.
2920 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302921 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302922 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302923 mb();
2924 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302925 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302926 msmsdcc_sync_reg_wr(host);
2927 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302928 goto out;
2929 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2930 /*
2931 * Wakeup MSM only if SDIO function drivers set
2932 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2933 */
2934 goto out;
2935 }
2936
2937 if (enable_wakeup_irq) {
2938 if (!host->plat->sdiowakeup_irq) {
2939 /*
2940 * When there is no gpio line that can be configured
2941 * as wakeup interrupt handle it by configuring
2942 * asynchronous sdio interrupts and DAT1 line.
2943 */
2944 writel_relaxed(MCI_SDIOINTMASK,
2945 host->base + MMCIMASK0);
2946 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302947 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302948 /* configure sdcc core interrupt as wakeup interrupt */
2949 msmsdcc_enable_irq_wake(host);
2950 } else {
2951 /* Let gpio line handle wakeup interrupt */
2952 writel_relaxed(0, host->base + MMCIMASK0);
2953 mb();
2954 if (host->sdio_wakeupirq_disabled) {
2955 host->sdio_wakeupirq_disabled = 0;
2956 /* configure gpio line as wakeup interrupt */
2957 msmsdcc_enable_irq_wake(host);
2958 enable_irq(host->plat->sdiowakeup_irq);
2959 }
2960 }
2961 } else {
2962 if (!host->plat->sdiowakeup_irq) {
2963 /*
2964 * We may not have cleared bit 22 in the interrupt
2965 * handler as the clocks might be off at that time.
2966 */
2967 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302968 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302969 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302970 msmsdcc_disable_irq_wake(host);
2971 } else if (!host->sdio_wakeupirq_disabled) {
2972 disable_irq_nosync(host->plat->sdiowakeup_irq);
2973 msmsdcc_disable_irq_wake(host);
2974 host->sdio_wakeupirq_disabled = 1;
2975 }
2976 }
2977out:
2978 return;
San Mehat9d2bd732009-09-22 16:44:22 -07002979}
2980
2981static void
2982msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2983{
2984 struct msmsdcc_host *host = mmc_priv(mmc);
2985 u32 clk = 0, pwr = 0;
2986 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002987 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002989
Sahitya Tummala7a892482011-01-18 11:22:49 +05302990
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302991 /*
2992 * Disable SDCC core interrupt until set_ios is completed.
2993 * This avoids any race conditions with interrupt raised
2994 * when turning on/off the clocks. One possible
2995 * scenario is SDIO operational interrupt while the clock
2996 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302997 * host->lock is being released intermittently below.
2998 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302999 */
3000
Asutosh Dasf5298c32012-04-03 14:51:47 +05303001 mutex_lock(&host->clk_mutex);
3002 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003003 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303004 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303005 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303006 host->sdcc_irq_disabled = 1;
3007 }
San Mehatd0719e52009-12-03 10:58:54 -08003008 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003009
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303010 /* Make sure sdcc core irq is synchronized */
3011 synchronize_irq(host->core_irqres->start);
3012
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303013 pwr = msmsdcc_setup_pwr(host, ios);
3014
3015 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003016 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303017 spin_unlock_irqrestore(&host->lock, flags);
3018 rc = msmsdcc_setup_clocks(host, true);
3019 if (rc)
3020 goto out;
3021 spin_lock_irqsave(&host->lock, flags);
3022 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3023 mb();
3024 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 /*
3028 * For DDR50 mode, controller needs clock rate to be
3029 * double than what is required on the SD card CLK pin.
3030 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303031 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032 /*
3033 * Make sure that we don't double the clock if
3034 * doubled clock rate is already set
3035 */
3036 if (!host->ddr_doubled_clk_rate ||
3037 (host->ddr_doubled_clk_rate &&
3038 (host->ddr_doubled_clk_rate != ios->clock))) {
3039 host->ddr_doubled_clk_rate =
3040 msmsdcc_get_sup_clk_rate(
3041 host, (ios->clock * 2));
3042 clock = host->ddr_doubled_clk_rate;
3043 }
3044 } else {
3045 host->ddr_doubled_clk_rate = 0;
3046 }
3047
3048 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303049 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003050 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303051 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303053 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 mmc_hostname(mmc), clock);
3055 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303056 host->reg_write_delay =
3057 (1 + ((3 * USEC_PER_SEC) /
3058 (host->clk_rate ? host->clk_rate :
3059 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060 }
3061 /*
3062 * give atleast 2 MCLK cycles delay for clocks
3063 * and SDCC core to stabilize
3064 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303065 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003067 clk |= MCI_CLK_ENABLE;
3068 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 if (ios->bus_width == MMC_BUS_WIDTH_8)
3070 clk |= MCI_CLK_WIDEBUS_8;
3071 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3072 clk |= MCI_CLK_WIDEBUS_4;
3073 else
3074 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 if (msmsdcc_is_pwrsave(host))
3077 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081 host->tuning_needed = 0;
3082 /*
3083 * Select the controller timing mode according
3084 * to current bus speed mode
3085 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303086 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
3087 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 clk |= (4 << 14);
3089 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303090 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 clk |= (3 << 14);
3092 } else {
3093 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003094 }
3095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3097 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003098
Subhash Jadavani00083572012-02-15 16:18:01 +05303099 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3100 if (!ios->vdd)
3101 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07003102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003103 if (host->io_pad_pwr_switch)
3104 clk |= IO_PAD_PWR_SWITCH;
3105
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303106 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303107 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303108 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3109 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303110 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303112 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3113 host->pwr = pwr;
3114 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303115 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 }
San Mehat9d2bd732009-09-22 16:44:22 -07003117 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303119 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303120 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303121 spin_unlock_irqrestore(&host->lock, flags);
3122 /*
3123 * May get a wake-up interrupt the instant we disable the
3124 * clocks. This would disable the wake-up interrupt.
3125 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303127 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303129
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303130 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303131 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303132 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303133
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303134 /* Let interrupts be disabled if the host is powered off */
3135 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3136 enable_irq(host->core_irqres->start);
3137 host->sdcc_irq_disabled = 0;
3138 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003139 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303140out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303141 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003142}
3143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3145{
3146 struct msmsdcc_host *host = mmc_priv(mmc);
3147 u32 clk;
3148
3149 clk = readl_relaxed(host->base + MMCICLOCK);
3150 pr_debug("Changing to pwr_save=%d", pwrsave);
3151 if (pwrsave && msmsdcc_is_pwrsave(host))
3152 clk |= MCI_CLK_PWRSAVE;
3153 else
3154 clk &= ~MCI_CLK_PWRSAVE;
3155 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303156 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157
3158 return 0;
3159}
3160
3161static int msmsdcc_get_ro(struct mmc_host *mmc)
3162{
3163 int status = -ENOSYS;
3164 struct msmsdcc_host *host = mmc_priv(mmc);
3165
3166 if (host->plat->wpswitch) {
3167 status = host->plat->wpswitch(mmc_dev(mmc));
3168 } else if (host->plat->wpswitch_gpio) {
3169 status = gpio_request(host->plat->wpswitch_gpio,
3170 "SD_WP_Switch");
3171 if (status) {
3172 pr_err("%s: %s: Failed to request GPIO %d\n",
3173 mmc_hostname(mmc), __func__,
3174 host->plat->wpswitch_gpio);
3175 } else {
3176 status = gpio_direction_input(
3177 host->plat->wpswitch_gpio);
3178 if (!status) {
3179 /*
3180 * Wait for atleast 300ms as debounce
3181 * time for GPIO input to stabilize.
3182 */
3183 msleep(300);
3184 status = gpio_get_value_cansleep(
3185 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303186 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187 }
3188 gpio_free(host->plat->wpswitch_gpio);
3189 }
3190 }
3191
3192 if (status < 0)
3193 status = -ENOSYS;
3194 pr_debug("%s: Card read-only status %d\n", __func__, status);
3195
3196 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003197}
3198
3199static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3200{
3201 struct msmsdcc_host *host = mmc_priv(mmc);
3202 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303204 /*
3205 * We may come here with clocks turned off in that case don't
3206 * attempt to write into MASK0 register. While turning on the
3207 * clocks mci_irqenable will be written to MASK0 register.
3208 */
San Mehat9d2bd732009-09-22 16:44:22 -07003209
3210 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003212 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303213 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303214 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303216 mb();
3217 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 } else {
3219 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303220 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303221 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303223 mb();
3224 }
San Mehat9d2bd732009-09-22 16:44:22 -07003225 }
3226 spin_unlock_irqrestore(&host->lock, flags);
3227}
3228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303230static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003231{
subhashj245831e2012-04-30 18:46:17 +05303232 struct device *dev = mmc_dev(host->mmc);
3233
3234 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3235 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3236 " request_pending=%d, request=%d\n",
3237 mmc_hostname(host->mmc), dev->power.runtime_status,
3238 atomic_read(&dev->power.usage_count),
3239 dev->power.is_suspended, dev->power.disable_depth,
3240 dev->power.runtime_error, dev->power.request_pending,
3241 dev->power.request);
3242}
3243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244static int msmsdcc_enable(struct mmc_host *mmc)
3245{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003246 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003247 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003248 struct msmsdcc_host *host = mmc_priv(mmc);
3249
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303250 msmsdcc_pm_qos_update_latency(host, 1);
3251
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003252 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303253 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003254
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003255 if (host->sdcc_suspended && host->pending_resume &&
3256 !pm_runtime_suspended(dev)) {
3257 host->pending_resume = false;
3258 pm_runtime_get_noresume(dev);
3259 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303260 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003261 }
3262
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303263 if (dev->power.runtime_status == RPM_SUSPENDING) {
3264 if (mmc->suspend_task == current) {
3265 pm_runtime_get_noresume(dev);
3266 goto out;
3267 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303268 } else if (dev->power.runtime_status == RPM_RESUMING) {
3269 pm_runtime_get_noresume(dev);
3270 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303271 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303273 rc = pm_runtime_get_sync(dev);
3274
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303275skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303276 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3278 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303279 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303280 return rc;
3281 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303282out:
3283 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303284 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285}
3286
Steve Mucklef132c6c2012-06-06 18:30:57 -07003287static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003288{
3289 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303290 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303292 msmsdcc_pm_qos_update_latency(host, 0);
3293
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303294 if (mmc->card && mmc_card_sdio(mmc->card)) {
3295 rc = 0;
3296 goto out;
3297 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303298
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303299 if (host->plat->disable_runtime_pm)
3300 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301
3302 rc = pm_runtime_put_sync(mmc->parent);
3303
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003304 /*
3305 * Ignore -EAGAIN as that is not fatal, it means that
3306 * either runtime usage count is non-zero or the runtime
3307 * pm itself is disabled or not in proper state to process
3308 * idle notification.
3309 */
3310 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3312 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303313 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003314 return rc;
3315 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303316
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303317out:
3318 msmsdcc_msm_bus_queue_work(host);
3319 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320}
3321#else
subhashj245831e2012-04-30 18:46:17 +05303322static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3323
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303324static int msmsdcc_enable(struct mmc_host *mmc)
3325{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003326 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303327 struct msmsdcc_host *host = mmc_priv(mmc);
3328 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303329 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303330
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303331 msmsdcc_pm_qos_update_latency(host, 1);
3332
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303333 if (mmc->card && mmc_card_sdio(mmc->card)) {
3334 rc = 0;
3335 goto out;
3336 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003337
3338 if (host->sdcc_suspended && host->pending_resume) {
3339 host->pending_resume = false;
3340 rc = msmsdcc_runtime_resume(dev);
3341 goto out;
3342 }
3343
Asutosh Dasf5298c32012-04-03 14:51:47 +05303344 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303345 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303346 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303347
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003348out:
3349 if (rc < 0) {
3350 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3351 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303352 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003353 return rc;
3354 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303355 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303356 return 0;
3357}
3358
Steve Mucklef132c6c2012-06-06 18:30:57 -07003359static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303360{
3361 struct msmsdcc_host *host = mmc_priv(mmc);
3362 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303363 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303364
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303365 msmsdcc_pm_qos_update_latency(host, 0);
3366
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303367 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303368 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303369
Asutosh Dasf5298c32012-04-03 14:51:47 +05303370 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303371 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303372 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303373
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303374 if (rc) {
3375 msmsdcc_pm_qos_update_latency(host, 1);
3376 return rc;
3377 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303378out:
3379 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303380 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303381}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382#endif
3383
Subhash Jadavani937c7502012-06-01 15:34:46 +05303384static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3385 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386{
3387 struct msmsdcc_host *host = mmc_priv(mmc);
3388 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303389 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390
Subhash Jadavani00083572012-02-15 16:18:01 +05303391 spin_lock_irqsave(&host->lock, flags);
3392 host->io_pad_pwr_switch = 0;
3393 spin_unlock_irqrestore(&host->lock, flags);
3394
Subhash Jadavani937c7502012-06-01 15:34:46 +05303395 switch (ios->signal_voltage) {
3396 case MMC_SIGNAL_VOLTAGE_330:
3397 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3398 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303399 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303400 case MMC_SIGNAL_VOLTAGE_180:
3401 break;
3402 case MMC_SIGNAL_VOLTAGE_120:
3403 /*
3404 * For eMMC cards, VDD_IO voltage range must be changed
3405 * only if it operates in HS200 SDR 1.2V mode or in
3406 * DDR 1.2V mode.
3407 */
3408 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303410 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303412 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003413 goto out;
3414 }
San Mehat9d2bd732009-09-22 16:44:22 -07003415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003416 /*
3417 * If we are here means voltage switch from high voltage to
3418 * low voltage is required
3419 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303420 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003421
3422 /*
3423 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3424 * register until they become all zeros.
3425 */
3426 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303427 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3429 mmc_hostname(mmc), __func__);
3430 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003432
3433 /* Stop SD CLK output. */
3434 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3435 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303436 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003437 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438
3439 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303440 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3441 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303443 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303444 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446
3447 spin_lock_irqsave(&host->lock, flags);
3448 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3449 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303450 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451 host->io_pad_pwr_switch = 1;
3452 spin_unlock_irqrestore(&host->lock, flags);
3453
3454 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3455 usleep_range(5000, 5500);
3456
3457 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303458 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003459 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3460 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303461 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 spin_unlock_irqrestore(&host->lock, flags);
3463
3464 /*
3465 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3466 * don't become all ones within 1 ms then a Voltage Switch
3467 * sequence has failed and a power cycle to the card is required.
3468 * Otherwise Voltage Switch sequence is completed successfully.
3469 */
3470 usleep_range(1000, 1500);
3471
3472 spin_lock_irqsave(&host->lock, flags);
3473 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3474 != (0xF << 1)) {
3475 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3476 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303477 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 goto out_unlock;
3479 }
3480
3481out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303482 /* Enable PWRSAVE */
3483 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3484 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303485 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 spin_unlock_irqrestore(&host->lock, flags);
3487out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303488 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489}
3490
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303491static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494
3495 /* Program the MCLK value to MCLK_FREQ bit field */
3496 if (host->clk_rate <= 112000000)
3497 mclk_freq = 0;
3498 else if (host->clk_rate <= 125000000)
3499 mclk_freq = 1;
3500 else if (host->clk_rate <= 137000000)
3501 mclk_freq = 2;
3502 else if (host->clk_rate <= 150000000)
3503 mclk_freq = 3;
3504 else if (host->clk_rate <= 162000000)
3505 mclk_freq = 4;
3506 else if (host->clk_rate <= 175000000)
3507 mclk_freq = 5;
3508 else if (host->clk_rate <= 187000000)
3509 mclk_freq = 6;
3510 else if (host->clk_rate <= 200000000)
3511 mclk_freq = 7;
3512
3513 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3514 & ~(7 << 24)) | (mclk_freq << 24)),
3515 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516}
3517
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303518/* Initialize the DLL (Programmable Delay Line ) */
3519static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003521 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303522 unsigned long flags;
3523 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003524
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303525 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 /*
3527 * Make sure that clock is always enabled when DLL
3528 * tuning is in progress. Keeping PWRSAVE ON may
3529 * turn off the clock. So let's disable the PWRSAVE
3530 * here and re-enable it once tuning is completed.
3531 */
3532 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3533 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303534 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303535
3536 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3537 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3538 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3539
3540 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3541 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3542 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3543
3544 msmsdcc_cm_sdc4_dll_set_freq(host);
3545
3546 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3547 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3548 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3549
3550 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3551 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3552 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3553
3554 /* Set DLL_EN bit to 1. */
3555 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3556 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3557
3558 /* Set CK_OUT_EN bit to 1. */
3559 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3560 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3561
3562 wait_cnt = 50;
3563 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3564 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3565 /* max. wait for 50us sec for LOCK bit to be set */
3566 if (--wait_cnt == 0) {
3567 pr_err("%s: %s: DLL failed to LOCK\n",
3568 mmc_hostname(host->mmc), __func__);
3569 rc = -ETIMEDOUT;
3570 goto out;
3571 }
3572 /* wait for 1us before polling again */
3573 udelay(1);
3574 }
3575
3576out:
3577 /* re-enable PWRSAVE */
3578 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3579 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303580 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303581 spin_unlock_irqrestore(&host->lock, flags);
3582
3583 return rc;
3584}
3585
3586static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3587 u8 poll)
3588{
3589 int rc = 0;
3590 u32 wait_cnt = 50;
3591 u8 ck_out_en = 0;
3592
3593 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3594 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3595 MCI_CK_OUT_EN);
3596
3597 while (ck_out_en != poll) {
3598 if (--wait_cnt == 0) {
3599 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3600 mmc_hostname(host->mmc), __func__, poll);
3601 rc = -ETIMEDOUT;
3602 goto out;
3603 }
3604 udelay(1);
3605
3606 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3607 MCI_CK_OUT_EN);
3608 }
3609out:
3610 return rc;
3611}
3612
3613/*
3614 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3615 * calibration sequence. This function should be called before
3616 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3617 * commands (CMD17/CMD18).
3618 *
3619 * This function gets called when host spinlock acquired.
3620 */
3621static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3622{
3623 int rc = 0;
3624 u32 config;
3625
3626 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3627 config |= MCI_CDR_EN;
3628 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3629 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3630
3631 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3632 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3633 if (rc)
3634 goto err_out;
3635
3636 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3637 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3638 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3639
3640 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3641 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3642 if (rc)
3643 goto err_out;
3644
3645 goto out;
3646
3647err_out:
3648 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3649out:
3650 return rc;
3651}
3652
3653static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3654 u8 phase)
3655{
3656 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303657 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3658 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3659 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303660 unsigned long flags;
3661 u32 config;
3662
3663 spin_lock_irqsave(&host->lock, flags);
3664
3665 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3666 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3667 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3668 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3669
3670 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3671 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3672 if (rc)
3673 goto err_out;
3674
3675 /*
3676 * Write the selected DLL clock output phase (0 ... 15)
3677 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3678 */
3679 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3680 & ~(0xF << 20))
3681 | (grey_coded_phase_table[phase] << 20)),
3682 host->base + MCI_DLL_CONFIG);
3683
3684 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3685 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3686 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3687
3688 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3689 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3690 if (rc)
3691 goto err_out;
3692
3693 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3694 config |= MCI_CDR_EN;
3695 config &= ~MCI_CDR_EXT_EN;
3696 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3697 goto out;
3698
3699err_out:
3700 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3701 mmc_hostname(host->mmc), __func__, phase);
3702out:
3703 spin_unlock_irqrestore(&host->lock, flags);
3704 return rc;
3705}
3706
3707/*
3708 * Find out the greatest range of consecuitive selected
3709 * DLL clock output phases that can be used as sampling
3710 * setting for SD3.0 UHS-I card read operation (in SDR104
3711 * timing mode) or for eMMC4.5 card read operation (in HS200
3712 * timing mode).
3713 * Select the 3/4 of the range and configure the DLL with the
3714 * selected DLL clock output phase.
3715*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303716static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303717 u8 *phase_table, u8 total_phases)
3718{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303719 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303720 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303721 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3722 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303723 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303724 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3725 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303726
Subhash Jadavani6159c622012-03-15 19:05:55 +05303727 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303728 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3729 mmc_hostname(host->mmc), __func__, total_phases);
3730 return -EINVAL;
3731 }
3732
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303733 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303734 ranges[row_index][col_index] = phase_table[cnt];
3735 phases_per_row[row_index] += 1;
3736 col_index++;
3737
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303738 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303739 continue;
3740 /* check if next phase in phase_table is consecutive or not */
3741 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3742 row_index++;
3743 col_index = 0;
3744 }
3745 }
3746
Subhash Jadavani6159c622012-03-15 19:05:55 +05303747 if (row_index >= MAX_PHASES)
3748 return -EINVAL;
3749
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303750 /* Check if phase-0 is present in first valid window? */
3751 if (!ranges[0][0]) {
3752 phase_0_found = true;
3753 phase_0_raw_index = 0;
3754 /* Check if cycle exist between 2 valid windows */
3755 for (cnt = 1; cnt <= row_index; cnt++) {
3756 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303757 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303758 if (ranges[cnt][i] == 15) {
3759 phase_15_found = true;
3760 phase_15_raw_index = cnt;
3761 break;
3762 }
3763 }
3764 }
3765 }
3766 }
3767
3768 /* If 2 valid windows form cycle then merge them as single window */
3769 if (phase_0_found && phase_15_found) {
3770 /* number of phases in raw where phase 0 is present */
3771 u8 phases_0 = phases_per_row[phase_0_raw_index];
3772 /* number of phases in raw where phase 15 is present */
3773 u8 phases_15 = phases_per_row[phase_15_raw_index];
3774
Subhash Jadavani6159c622012-03-15 19:05:55 +05303775 if (phases_0 + phases_15 >= MAX_PHASES)
3776 /*
3777 * If there are more than 1 phase windows then total
3778 * number of phases in both the windows should not be
3779 * more than or equal to MAX_PHASES.
3780 */
3781 return -EINVAL;
3782
3783 /* Merge 2 cyclic windows */
3784 i = phases_15;
3785 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303786 ranges[phase_15_raw_index][i] =
3787 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303788 if (++i >= MAX_PHASES)
3789 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303790 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303791
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303792 phases_per_row[phase_0_raw_index] = 0;
3793 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3794 }
3795
3796 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303797 if (phases_per_row[cnt] > curr_max) {
3798 curr_max = phases_per_row[cnt];
3799 selected_row_index = cnt;
3800 }
3801 }
3802
Subhash Jadavani6159c622012-03-15 19:05:55 +05303803 i = ((curr_max * 3) / 4);
3804 if (i)
3805 i--;
3806
Subhash Jadavani34187042012-03-02 10:59:49 +05303807 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303808
Subhash Jadavani6159c622012-03-15 19:05:55 +05303809 if (ret >= MAX_PHASES) {
3810 ret = -EINVAL;
3811 pr_err("%s: %s: invalid phase selected=%d\n",
3812 mmc_hostname(host->mmc), __func__, ret);
3813 }
3814
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303815 return ret;
3816}
3817
Girish K Sa3f41692012-02-29 12:00:09 +05303818static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303819{
3820 int rc = 0;
3821 struct msmsdcc_host *host = mmc_priv(mmc);
3822 unsigned long flags;
3823 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303824 const u32 *tuning_block_pattern = tuning_block_64;
3825 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303826
3827 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3828
3829 /* Tuning is only required for SDR104 modes */
3830 if (!host->tuning_needed) {
3831 rc = 0;
3832 goto exit;
3833 }
3834
3835 spin_lock_irqsave(&host->lock, flags);
3836 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303837 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303838 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3839
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303840 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303841 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3842 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3843 tuning_block_pattern = tuning_block_128;
3844 size = sizeof(tuning_block_128);
3845 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303846 spin_unlock_irqrestore(&host->lock, flags);
3847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848 /* first of all reset the tuning block */
3849 rc = msmsdcc_init_cm_sdc4_dll(host);
3850 if (rc)
3851 goto out;
3852
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303853 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854 if (!data_buf) {
3855 rc = -ENOMEM;
3856 goto out;
3857 }
3858
3859 phase = 0;
3860 do {
3861 struct mmc_command cmd = {0};
3862 struct mmc_data data = {0};
3863 struct mmc_request mrq = {
3864 .cmd = &cmd,
3865 .data = &data
3866 };
3867 struct scatterlist sg;
3868
3869 /* set the phase in delay line hw block */
3870 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3871 if (rc)
3872 goto kfree;
3873
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303874 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003875 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3876
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303877 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878 data.blocks = 1;
3879 data.flags = MMC_DATA_READ;
3880 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3881
3882 data.sg = &sg;
3883 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303884 sg_init_one(&sg, data_buf, size);
3885 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003886 mmc_wait_for_req(mmc, &mrq);
3887
3888 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303889 !memcmp(data_buf, tuning_block_pattern, size)) {
3890 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303892 pr_debug("%s: %s: found good phase = %d\n",
3893 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003894 }
3895 } while (++phase < 16);
3896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003897 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303898 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303899 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303900 if (rc < 0)
3901 goto kfree;
3902 else
3903 phase = (u8)rc;
3904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003905 /*
3906 * Finally set the selected phase in delay
3907 * line hw block.
3908 */
3909 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3910 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303911 goto kfree;
3912 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3913 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914 } else {
3915 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303916 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303918 msmsdcc_dump_sdcc_state(host);
3919 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921
3922kfree:
3923 kfree(data_buf);
3924out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303925 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303926 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303927 spin_unlock_irqrestore(&host->lock, flags);
3928exit:
3929 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003930 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003931}
3932
San Mehat9d2bd732009-09-22 16:44:22 -07003933static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934 .enable = msmsdcc_enable,
3935 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303936 .pre_req = msmsdcc_pre_req,
3937 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003938 .request = msmsdcc_request,
3939 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003941 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303942 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003943 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003944};
3945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003946static unsigned int
3947msmsdcc_slot_status(struct msmsdcc_host *host)
3948{
3949 int status;
3950 unsigned int gpio_no = host->plat->status_gpio;
3951
3952 status = gpio_request(gpio_no, "SD_HW_Detect");
3953 if (status) {
3954 pr_err("%s: %s: Failed to request GPIO %d\n",
3955 mmc_hostname(host->mmc), __func__, gpio_no);
3956 } else {
3957 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003958 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003959 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003960 if (host->plat->is_status_gpio_active_low)
3961 status = !status;
3962 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963 gpio_free(gpio_no);
3964 }
3965 return status;
3966}
3967
San Mehat9d2bd732009-09-22 16:44:22 -07003968static void
3969msmsdcc_check_status(unsigned long data)
3970{
3971 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3972 unsigned int status;
3973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003974 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003975 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003977 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003978 status = msmsdcc_slot_status(host);
3979
Krishna Konda941604a2012-01-10 17:46:34 -08003980 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003983 if (host->plat->status)
3984 pr_info("%s: Slot status change detected "
3985 "(%d -> %d)\n",
3986 mmc_hostname(host->mmc),
3987 host->oldstat, status);
3988 else if (host->plat->is_status_gpio_active_low)
3989 pr_info("%s: Slot status change detected "
3990 "(%d -> %d) and the card detect GPIO"
3991 " is ACTIVE_LOW\n",
3992 mmc_hostname(host->mmc),
3993 host->oldstat, status);
3994 else
3995 pr_info("%s: Slot status change detected "
3996 "(%d -> %d) and the card detect GPIO"
3997 " is ACTIVE_HIGH\n",
3998 mmc_hostname(host->mmc),
3999 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004000 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004001 }
4002 host->oldstat = status;
4003 } else {
4004 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004005 }
San Mehat9d2bd732009-09-22 16:44:22 -07004006}
4007
4008static irqreturn_t
4009msmsdcc_platform_status_irq(int irq, void *dev_id)
4010{
4011 struct msmsdcc_host *host = dev_id;
4012
Girish K Sa3c76eb2011-10-11 11:44:09 +05304013 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004014 msmsdcc_check_status((unsigned long) host);
4015 return IRQ_HANDLED;
4016}
4017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018static irqreturn_t
4019msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4020{
4021 struct msmsdcc_host *host = dev_id;
4022
4023 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4024 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304025 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304027 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028 wake_lock(&host->sdio_wlock);
4029 msmsdcc_disable_irq_wake(host);
4030 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304031 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032 }
4033 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004034 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304035 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304036 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304037 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 }
4039 spin_unlock(&host->lock);
4040
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304041out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042 return IRQ_HANDLED;
4043}
4044
San Mehat9d2bd732009-09-22 16:44:22 -07004045static void
4046msmsdcc_status_notify_cb(int card_present, void *dev_id)
4047{
4048 struct msmsdcc_host *host = dev_id;
4049
Girish K Sa3c76eb2011-10-11 11:44:09 +05304050 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004051 card_present);
4052 msmsdcc_check_status((unsigned long) host);
4053}
4054
San Mehat9d2bd732009-09-22 16:44:22 -07004055static int
4056msmsdcc_init_dma(struct msmsdcc_host *host)
4057{
4058 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4059 host->dma.host = host;
4060 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004061 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004062
4063 if (!host->dmares)
4064 return -ENODEV;
4065
4066 host->dma.nc = dma_alloc_coherent(NULL,
4067 sizeof(struct msmsdcc_nc_dmadata),
4068 &host->dma.nc_busaddr,
4069 GFP_KERNEL);
4070 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004071 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004072 return -ENOMEM;
4073 }
4074 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4075 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4076 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4077 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4078 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004079 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004080
4081 return 0;
4082}
4083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4085/**
4086 * Allocate and Connect a SDCC peripheral's SPS endpoint
4087 *
4088 * This function allocates endpoint context and
4089 * connect it with memory endpoint by calling
4090 * appropriate SPS driver APIs.
4091 *
4092 * Also registers a SPS callback function with
4093 * SPS driver
4094 *
4095 * This function should only be called once typically
4096 * during driver probe.
4097 *
4098 * @host - Pointer to sdcc host structure
4099 * @ep - Pointer to sps endpoint data structure
4100 * @is_produce - 1 means Producer endpoint
4101 * 0 means Consumer endpoint
4102 *
4103 * @return - 0 if successful else negative value.
4104 *
4105 */
4106static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4107 struct msmsdcc_sps_ep_conn_data *ep,
4108 bool is_producer)
4109{
4110 int rc = 0;
4111 struct sps_pipe *sps_pipe_handle;
4112 struct sps_connect *sps_config = &ep->config;
4113 struct sps_register_event *sps_event = &ep->event;
4114
4115 /* Allocate endpoint context */
4116 sps_pipe_handle = sps_alloc_endpoint();
4117 if (!sps_pipe_handle) {
4118 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4119 mmc_hostname(host->mmc), is_producer);
4120 rc = -ENOMEM;
4121 goto out;
4122 }
4123
4124 /* Get default connection configuration for an endpoint */
4125 rc = sps_get_config(sps_pipe_handle, sps_config);
4126 if (rc) {
4127 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4128 " rc=%d", mmc_hostname(host->mmc),
4129 (u32)sps_pipe_handle, rc);
4130 goto get_config_err;
4131 }
4132
4133 /* Modify the default connection configuration */
4134 if (is_producer) {
4135 /*
4136 * For SDCC producer transfer, source should be
4137 * SDCC peripheral where as destination should
4138 * be system memory.
4139 */
4140 sps_config->source = host->sps.bam_handle;
4141 sps_config->destination = SPS_DEV_HANDLE_MEM;
4142 /* Producer pipe will handle this connection */
4143 sps_config->mode = SPS_MODE_SRC;
4144 sps_config->options =
4145 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4146 } else {
4147 /*
4148 * For SDCC consumer transfer, source should be
4149 * system memory where as destination should
4150 * SDCC peripheral
4151 */
4152 sps_config->source = SPS_DEV_HANDLE_MEM;
4153 sps_config->destination = host->sps.bam_handle;
4154 sps_config->mode = SPS_MODE_DEST;
4155 sps_config->options =
4156 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4157 }
4158
4159 /* Producer pipe index */
4160 sps_config->src_pipe_index = host->sps.src_pipe_index;
4161 /* Consumer pipe index */
4162 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4163 /*
4164 * This event thresold value is only significant for BAM-to-BAM
4165 * transfer. It's ignored for BAM-to-System mode transfer.
4166 */
4167 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304168
4169 /* Allocate maximum descriptor fifo size */
4170 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4171 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4173 sps_config->desc.size,
4174 &sps_config->desc.phys_base,
4175 GFP_KERNEL);
4176
Pratibhasagar V00b94332011-10-18 14:57:27 +05304177 if (!sps_config->desc.base) {
4178 rc = -ENOMEM;
4179 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4180 , mmc_hostname(host->mmc));
4181 goto get_config_err;
4182 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004183 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4184
4185 /* Establish connection between peripheral and memory endpoint */
4186 rc = sps_connect(sps_pipe_handle, sps_config);
4187 if (rc) {
4188 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4189 " rc=%d", mmc_hostname(host->mmc),
4190 (u32)sps_pipe_handle, rc);
4191 goto sps_connect_err;
4192 }
4193
4194 sps_event->mode = SPS_TRIGGER_CALLBACK;
4195 sps_event->options = SPS_O_EOT;
4196 sps_event->callback = msmsdcc_sps_complete_cb;
4197 sps_event->xfer_done = NULL;
4198 sps_event->user = (void *)host;
4199
4200 /* Register callback event for EOT (End of transfer) event. */
4201 rc = sps_register_event(sps_pipe_handle, sps_event);
4202 if (rc) {
4203 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4204 " rc=%d", mmc_hostname(host->mmc),
4205 (u32)sps_pipe_handle, rc);
4206 goto reg_event_err;
4207 }
4208 /* Now save the sps pipe handle */
4209 ep->pipe_handle = sps_pipe_handle;
4210 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4211 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4212 __func__, is_producer ? "READ" : "WRITE",
4213 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4214 goto out;
4215
4216reg_event_err:
4217 sps_disconnect(sps_pipe_handle);
4218sps_connect_err:
4219 dma_free_coherent(mmc_dev(host->mmc),
4220 sps_config->desc.size,
4221 sps_config->desc.base,
4222 sps_config->desc.phys_base);
4223get_config_err:
4224 sps_free_endpoint(sps_pipe_handle);
4225out:
4226 return rc;
4227}
4228
4229/**
4230 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4231 *
4232 * This function disconnect endpoint and deallocates
4233 * endpoint context.
4234 *
4235 * This function should only be called once typically
4236 * during driver remove.
4237 *
4238 * @host - Pointer to sdcc host structure
4239 * @ep - Pointer to sps endpoint data structure
4240 *
4241 */
4242static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4243 struct msmsdcc_sps_ep_conn_data *ep)
4244{
4245 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4246 struct sps_connect *sps_config = &ep->config;
4247 struct sps_register_event *sps_event = &ep->event;
4248
4249 sps_event->xfer_done = NULL;
4250 sps_event->callback = NULL;
4251 sps_register_event(sps_pipe_handle, sps_event);
4252 sps_disconnect(sps_pipe_handle);
4253 dma_free_coherent(mmc_dev(host->mmc),
4254 sps_config->desc.size,
4255 sps_config->desc.base,
4256 sps_config->desc.phys_base);
4257 sps_free_endpoint(sps_pipe_handle);
4258}
4259
4260/**
4261 * Reset SDCC peripheral's SPS endpoint
4262 *
4263 * This function disconnects an endpoint.
4264 *
4265 * This function should be called for reseting
4266 * SPS endpoint when data transfer error is
4267 * encountered during data transfer. This
4268 * can be considered as soft reset to endpoint.
4269 *
4270 * This function should only be called if
4271 * msmsdcc_sps_init() is already called.
4272 *
4273 * @host - Pointer to sdcc host structure
4274 * @ep - Pointer to sps endpoint data structure
4275 *
4276 * @return - 0 if successful else negative value.
4277 */
4278static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4279 struct msmsdcc_sps_ep_conn_data *ep)
4280{
4281 int rc = 0;
4282 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4283
4284 rc = sps_disconnect(sps_pipe_handle);
4285 if (rc) {
4286 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4287 " rc=%d", mmc_hostname(host->mmc), __func__,
4288 (u32)sps_pipe_handle, rc);
4289 goto out;
4290 }
4291 out:
4292 return rc;
4293}
4294
4295/**
4296 * Restore SDCC peripheral's SPS endpoint
4297 *
4298 * This function connects an endpoint.
4299 *
4300 * This function should be called for restoring
4301 * SPS endpoint after data transfer error is
4302 * encountered during data transfer. This
4303 * can be considered as soft reset to endpoint.
4304 *
4305 * This function should only be called if
4306 * msmsdcc_sps_reset_ep() is called before.
4307 *
4308 * @host - Pointer to sdcc host structure
4309 * @ep - Pointer to sps endpoint data structure
4310 *
4311 * @return - 0 if successful else negative value.
4312 */
4313static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4314 struct msmsdcc_sps_ep_conn_data *ep)
4315{
4316 int rc = 0;
4317 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4318 struct sps_connect *sps_config = &ep->config;
4319 struct sps_register_event *sps_event = &ep->event;
4320
4321 /* Establish connection between peripheral and memory endpoint */
4322 rc = sps_connect(sps_pipe_handle, sps_config);
4323 if (rc) {
4324 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4325 " rc=%d", mmc_hostname(host->mmc), __func__,
4326 (u32)sps_pipe_handle, rc);
4327 goto out;
4328 }
4329
4330 /* Register callback event for EOT (End of transfer) event. */
4331 rc = sps_register_event(sps_pipe_handle, sps_event);
4332 if (rc) {
4333 pr_err("%s: %s: sps_register_event() failed!!!"
4334 " pipe_handle=0x%x, rc=%d",
4335 mmc_hostname(host->mmc), __func__,
4336 (u32)sps_pipe_handle, rc);
4337 goto reg_event_err;
4338 }
4339 goto out;
4340
4341reg_event_err:
4342 sps_disconnect(sps_pipe_handle);
4343out:
4344 return rc;
4345}
4346
4347/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004348 * Handle BAM device's global error condition
4349 *
4350 * This is an error handler for the SDCC bam device
4351 *
4352 * This function is registered as a callback with SPS-BAM
4353 * driver and will called in case there are an errors for
4354 * the SDCC BAM deivce. Any error conditions in the BAM
4355 * device are global and will be result in this function
4356 * being called once per device.
4357 *
4358 * This function will be called from the sps driver's
4359 * interrupt context.
4360 *
4361 * @sps_cb_case - indicates what error it is
4362 * @user - Pointer to sdcc host structure
4363 */
4364static void
4365msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4366{
4367 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4368 struct mmc_request *mrq;
4369 unsigned long flags;
4370 int32_t error = 0;
4371
4372 BUG_ON(!host);
4373 BUG_ON(!is_sps_mode(host));
4374
4375 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
4376 /**
4377 * Reset the all endpoints along with reseting the sps device.
4378 */
4379 host->sps.pipe_reset_pending = true;
4380 host->sps.reset_device = true;
4381
4382 pr_err("%s: BAM Global ERROR IRQ happened\n",
4383 mmc_hostname(host->mmc));
4384 error = EAGAIN;
4385 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4386 /**
4387 * This means that there was an AHB access error and
4388 * the address we are trying to read/write is something
4389 * we dont have priviliges to do so.
4390 */
4391 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4392 mmc_hostname(host->mmc));
4393 error = EACCES;
4394 } else {
4395 /**
4396 * This should not have happened ideally. If this happens
4397 * there is some seriously wrong.
4398 */
4399 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4400 mmc_hostname(host->mmc), (u32) sps_cb_case);
4401 error = EIO;
4402 }
4403
4404 spin_lock_irqsave(&host->lock, flags);
4405
4406 mrq = host->curr.mrq;
4407
4408 if (mrq && mrq->cmd) {
4409 msmsdcc_dump_sdcc_state(host);
4410
4411 if (!mrq->cmd->error)
4412 mrq->cmd->error = -error;
4413 if (host->curr.data) {
4414 if (mrq->data && !mrq->data->error)
4415 mrq->data->error = -error;
4416 host->curr.data_xfered = 0;
4417 if (host->sps.sg && is_sps_mode(host)) {
4418 /* Stop current SPS transfer */
4419 msmsdcc_sps_exit_curr_xfer(host);
4420 } else {
4421 /* this condition should not have happened */
4422 pr_err("%s: something is seriously wrong. "\
4423 "Funtion: %s, line: %d\n",
4424 mmc_hostname(host->mmc),
4425 __func__, __LINE__);
4426 }
4427 } else {
4428 /* this condition should not have happened */
4429 pr_err("%s: something is seriously wrong. Funtion: "\
4430 "%s, line: %d\n", mmc_hostname(host->mmc),
4431 __func__, __LINE__);
4432 }
4433 }
4434 spin_unlock_irqrestore(&host->lock, flags);
4435}
4436
4437/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004438 * Initialize SPS HW connected with SDCC core
4439 *
4440 * This function register BAM HW resources with
4441 * SPS driver and then initialize 2 SPS endpoints
4442 *
4443 * This function should only be called once typically
4444 * during driver probe.
4445 *
4446 * @host - Pointer to sdcc host structure
4447 *
4448 * @return - 0 if successful else negative value.
4449 *
4450 */
4451static int msmsdcc_sps_init(struct msmsdcc_host *host)
4452{
4453 int rc = 0;
4454 struct sps_bam_props bam = {0};
4455
4456 host->bam_base = ioremap(host->bam_memres->start,
4457 resource_size(host->bam_memres));
4458 if (!host->bam_base) {
4459 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4460 " size=0x%x", mmc_hostname(host->mmc),
4461 host->bam_memres->start,
4462 (host->bam_memres->end -
4463 host->bam_memres->start));
4464 rc = -ENOMEM;
4465 goto out;
4466 }
4467
4468 bam.phys_addr = host->bam_memres->start;
4469 bam.virt_addr = host->bam_base;
4470 /*
4471 * This event thresold value is only significant for BAM-to-BAM
4472 * transfer. It's ignored for BAM-to-System mode transfer.
4473 */
4474 bam.event_threshold = 0x10; /* Pipe event threshold */
4475 /*
4476 * This threshold controls when the BAM publish
4477 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304478 * SPS HW will be used for data transfer size even
4479 * less than SDCC FIFO size. So let's set BAM summing
4480 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004481 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304482 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483 /* SPS driver wll handle the SDCC BAM IRQ */
4484 bam.irq = (u32)host->bam_irqres->start;
4485 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004486 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4487 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004488
4489 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4490 (u32)bam.phys_addr);
4491 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4492 (u32)bam.virt_addr);
4493
4494 /* Register SDCC Peripheral BAM device to SPS driver */
4495 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4496 if (rc) {
4497 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4498 mmc_hostname(host->mmc), rc);
4499 goto reg_bam_err;
4500 }
4501 pr_info("%s: BAM device registered. bam_handle=0x%x",
4502 mmc_hostname(host->mmc), host->sps.bam_handle);
4503
4504 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4505 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4506
4507 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4508 SPS_PROD_PERIPHERAL);
4509 if (rc)
4510 goto sps_reset_err;
4511 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4512 SPS_CONS_PERIPHERAL);
4513 if (rc)
4514 goto cons_conn_err;
4515
4516 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4517 mmc_hostname(host->mmc),
4518 (unsigned long long)host->bam_memres->start,
4519 (unsigned int)host->bam_irqres->start);
4520 goto out;
4521
4522cons_conn_err:
4523 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4524sps_reset_err:
4525 sps_deregister_bam_device(host->sps.bam_handle);
4526reg_bam_err:
4527 iounmap(host->bam_base);
4528out:
4529 return rc;
4530}
4531
4532/**
4533 * De-initialize SPS HW connected with SDCC core
4534 *
4535 * This function deinitialize SPS endpoints and then
4536 * deregisters BAM resources from SPS driver.
4537 *
4538 * This function should only be called once typically
4539 * during driver remove.
4540 *
4541 * @host - Pointer to sdcc host structure
4542 *
4543 */
4544static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4545{
4546 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4547 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4548 sps_deregister_bam_device(host->sps.bam_handle);
4549 iounmap(host->bam_base);
4550}
4551#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4552
4553static ssize_t
4554show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4555{
4556 struct mmc_host *mmc = dev_get_drvdata(dev);
4557 struct msmsdcc_host *host = mmc_priv(mmc);
4558 int poll;
4559 unsigned long flags;
4560
4561 spin_lock_irqsave(&host->lock, flags);
4562 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4563 spin_unlock_irqrestore(&host->lock, flags);
4564
4565 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4566}
4567
4568static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304569store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004570 const char *buf, size_t count)
4571{
4572 struct mmc_host *mmc = dev_get_drvdata(dev);
4573 struct msmsdcc_host *host = mmc_priv(mmc);
4574 int value;
4575 unsigned long flags;
4576
4577 sscanf(buf, "%d", &value);
4578
4579 spin_lock_irqsave(&host->lock, flags);
4580 if (value) {
4581 mmc->caps |= MMC_CAP_NEEDS_POLL;
4582 mmc_detect_change(host->mmc, 0);
4583 } else {
4584 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4585 }
4586#ifdef CONFIG_HAS_EARLYSUSPEND
4587 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4588#endif
4589 spin_unlock_irqrestore(&host->lock, flags);
4590 return count;
4591}
4592
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304593static ssize_t
4594show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4595 char *buf)
4596{
4597 struct mmc_host *mmc = dev_get_drvdata(dev);
4598 struct msmsdcc_host *host = mmc_priv(mmc);
4599
4600 return snprintf(buf, PAGE_SIZE, "%u\n",
4601 host->msm_bus_vote.is_max_bw_needed);
4602}
4603
4604static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304605store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304606 const char *buf, size_t count)
4607{
4608 struct mmc_host *mmc = dev_get_drvdata(dev);
4609 struct msmsdcc_host *host = mmc_priv(mmc);
4610 uint32_t value;
4611 unsigned long flags;
4612
4613 if (!kstrtou32(buf, 0, &value)) {
4614 spin_lock_irqsave(&host->lock, flags);
4615 host->msm_bus_vote.is_max_bw_needed = !!value;
4616 spin_unlock_irqrestore(&host->lock, flags);
4617 }
4618
4619 return count;
4620}
4621
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304622static ssize_t
4623show_idle_timeout(struct device *dev, struct device_attribute *attr,
4624 char *buf)
4625{
4626 struct mmc_host *mmc = dev_get_drvdata(dev);
4627 struct msmsdcc_host *host = mmc_priv(mmc);
4628
4629 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4630 host->idle_tout_ms / 1000);
4631}
4632
4633static ssize_t
4634store_idle_timeout(struct device *dev, struct device_attribute *attr,
4635 const char *buf, size_t count)
4636{
4637 struct mmc_host *mmc = dev_get_drvdata(dev);
4638 struct msmsdcc_host *host = mmc_priv(mmc);
4639 unsigned int long flags;
4640 int timeout; /* in secs */
4641
4642 if (!kstrtou32(buf, 0, &timeout)
4643 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4644 spin_lock_irqsave(&host->lock, flags);
4645 host->idle_tout_ms = timeout * 1000;
4646 spin_unlock_irqrestore(&host->lock, flags);
4647 }
4648 return count;
4649}
4650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004651#ifdef CONFIG_HAS_EARLYSUSPEND
4652static void msmsdcc_early_suspend(struct early_suspend *h)
4653{
4654 struct msmsdcc_host *host =
4655 container_of(h, struct msmsdcc_host, early_suspend);
4656 unsigned long flags;
4657
4658 spin_lock_irqsave(&host->lock, flags);
4659 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4660 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4661 spin_unlock_irqrestore(&host->lock, flags);
4662};
4663static void msmsdcc_late_resume(struct early_suspend *h)
4664{
4665 struct msmsdcc_host *host =
4666 container_of(h, struct msmsdcc_host, early_suspend);
4667 unsigned long flags;
4668
4669 if (host->polling_enabled) {
4670 spin_lock_irqsave(&host->lock, flags);
4671 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4672 mmc_detect_change(host->mmc, 0);
4673 spin_unlock_irqrestore(&host->lock, flags);
4674 }
4675};
4676#endif
4677
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304678static void msmsdcc_print_regs(const char *name, void __iomem *base,
4679 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304680{
4681 unsigned int i;
4682
4683 if (!base)
4684 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304685
4686 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4687 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304688 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304689 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4690 (u32)readl_relaxed(base + i*4),
4691 (u32)readl_relaxed(base + ((i+1)*4)),
4692 (u32)readl_relaxed(base + ((i+2)*4)),
4693 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304694 }
4695}
4696
4697static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4698{
4699 /* Dump current state of SDCC clocks, power and irq */
4700 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304701 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304702 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304703 mmc_hostname(host->mmc),
4704 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304705 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304706 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4707 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4708
4709 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304710 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304711 msmsdcc_print_regs("SDCC-CORE", host->base,
4712 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304713
4714 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304715 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304716 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304717 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304718 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4719 mmc_hostname(host->mmc), host->dma.busy,
4720 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304721 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304722 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304723 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4724 host->dml_memres->start,
4725 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304726 pr_info("%s: SPS mode: busy=%d\n",
4727 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304728 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304729
4730 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4731 mmc_hostname(host->mmc), host->curr.xfer_size,
4732 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304733 }
4734
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304735 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304736 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4737 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4738 host->curr.got_dataend, host->prog_enable,
4739 host->curr.wait_for_auto_prog_done,
4740 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304741 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304742}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004744static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4745{
4746 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4747 struct mmc_request *mrq;
4748 unsigned long flags;
4749
4750 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004751 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004752 pr_info("%s: %s: dummy CMD52 timeout\n",
4753 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004754 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004755 }
4756
4757 mrq = host->curr.mrq;
4758
4759 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304760 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4761 mrq->cmd->opcode);
4762 msmsdcc_dump_sdcc_state(host);
4763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764 if (!mrq->cmd->error)
4765 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304766 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004768 if (mrq->data && !mrq->data->error)
4769 mrq->data->error = -ETIMEDOUT;
4770 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304771 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004772 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304773 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 /* Stop current SPS transfer */
4775 msmsdcc_sps_exit_curr_xfer(host);
4776 } else {
4777 msmsdcc_reset_and_restore(host);
4778 msmsdcc_stop_data(host);
4779 if (mrq->data && mrq->data->stop)
4780 msmsdcc_start_command(host,
4781 mrq->data->stop, 0);
4782 else
4783 msmsdcc_request_end(host, mrq);
4784 }
4785 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304786 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304787 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788 msmsdcc_reset_and_restore(host);
4789 msmsdcc_request_end(host, mrq);
4790 }
4791 }
4792 spin_unlock_irqrestore(&host->lock, flags);
4793}
4794
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05304795/*
4796 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
4797 *
4798 * @dev: device node from which the property value is to be read.
4799 * @prop_name: name of the property to be searched.
4800 * @out_array: filled array returned to caller
4801 * @len: filled array size returned to caller
4802 * @size: expected size of the array
4803 *
4804 * If expected "size" doesn't match with "len" an error is returned. If
4805 * expected size is zero, the length of actual array is returned provided
4806 * return value is zero.
4807 *
4808 * RETURNS:
4809 * zero on success, negative error if failed.
4810 */
4811static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
4812 u32 **out_array, int *len, int size)
4813{
4814 int ret = 0;
4815 u32 *array = NULL;
4816 struct device_node *np = dev->of_node;
4817
4818 if (of_get_property(np, prop_name, len)) {
4819 size_t sz;
4820 sz = *len = *len / sizeof(*array);
4821
4822 if (sz > 0 && !(size > 0 && (sz != size))) {
4823 array = devm_kzalloc(dev, sz * sizeof(*array),
4824 GFP_KERNEL);
4825 if (!array) {
4826 dev_err(dev, "%s: no memory\n", prop_name);
4827 ret = -ENOMEM;
4828 goto out;
4829 }
4830
4831 ret = of_property_read_u32_array(np, prop_name,
4832 array, sz);
4833 if (ret < 0) {
4834 dev_err(dev, "%s: error reading array %d\n",
4835 prop_name, ret);
4836 goto out;
4837 }
4838 } else {
4839 dev_err(dev, "%s invalid size\n", prop_name);
4840 ret = -EINVAL;
4841 goto out;
4842 }
4843 } else {
4844 dev_err(dev, "%s not specified\n", prop_name);
4845 ret = -EINVAL;
4846 goto out;
4847 }
4848 *out_array = array;
4849out:
4850 if (ret)
4851 *len = 0;
4852 return ret;
4853}
4854
4855static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
4856 struct msm_mmc_pad_pull_data **pad_pull_data)
4857{
4858 int ret = 0, base = 0, len, i;
4859 u32 *tmp;
4860 struct msm_mmc_pad_pull_data *pull_data;
4861 struct msm_mmc_pad_pull *pull;
4862
4863 switch (id) {
4864 case 1:
4865 base = TLMM_PULL_SDC1_CLK;
4866 break;
4867 case 2:
4868 base = TLMM_PULL_SDC2_CLK;
4869 break;
4870 case 3:
4871 base = TLMM_PULL_SDC3_CLK;
4872 break;
4873 case 4:
4874 base = TLMM_PULL_SDC4_CLK;
4875 break;
4876 default:
4877 dev_err(dev, "%s: Invalid slot id\n", __func__);
4878 ret = -EINVAL;
4879 goto err;
4880 }
4881
4882 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
4883 GFP_KERNEL);
4884 if (!pull_data) {
4885 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
4886 ret = -ENOMEM;
4887 goto err;
4888 }
4889 pull_data->size = 3; /* array size for clk, cmd, data */
4890
4891 /* Allocate on, off configs for clk, cmd, data */
4892 pull = devm_kzalloc(dev, 2 * pull_data->size *\
4893 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
4894 if (!pull) {
4895 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
4896 ret = -ENOMEM;
4897 goto err;
4898 }
4899 pull_data->on = pull;
4900 pull_data->off = pull + pull_data->size;
4901
4902 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
4903 &tmp, &len, pull_data->size);
4904 if (!ret) {
4905 for (i = 0; i < len; i++) {
4906 pull_data->on[i].no = base + i;
4907 pull_data->on[i].val = tmp[i];
4908 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4909 i, pull_data->on[i].val);
4910 }
4911 } else {
4912 goto err;
4913 }
4914
4915 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
4916 &tmp, &len, pull_data->size);
4917 if (!ret) {
4918 for (i = 0; i < len; i++) {
4919 pull_data->off[i].no = base + i;
4920 pull_data->off[i].val = tmp[i];
4921 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4922 i, pull_data->off[i].val);
4923 }
4924 } else {
4925 goto err;
4926 }
4927
4928 *pad_pull_data = pull_data;
4929err:
4930 return ret;
4931}
4932
4933static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
4934 struct msm_mmc_pad_drv_data **pad_drv_data)
4935{
4936 int ret = 0, base = 0, len, i;
4937 u32 *tmp;
4938 struct msm_mmc_pad_drv_data *drv_data;
4939 struct msm_mmc_pad_drv *drv;
4940
4941 switch (id) {
4942 case 1:
4943 base = TLMM_HDRV_SDC1_CLK;
4944 break;
4945 case 2:
4946 base = TLMM_HDRV_SDC2_CLK;
4947 break;
4948 case 3:
4949 base = TLMM_HDRV_SDC3_CLK;
4950 break;
4951 case 4:
4952 base = TLMM_HDRV_SDC4_CLK;
4953 break;
4954 default:
4955 dev_err(dev, "%s: Invalid slot id\n", __func__);
4956 ret = -EINVAL;
4957 goto err;
4958 }
4959
4960 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
4961 GFP_KERNEL);
4962 if (!drv_data) {
4963 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
4964 ret = -ENOMEM;
4965 goto err;
4966 }
4967 drv_data->size = 3; /* array size for clk, cmd, data */
4968
4969 /* Allocate on, off configs for clk, cmd, data */
4970 drv = devm_kzalloc(dev, 2 * drv_data->size *\
4971 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
4972 if (!drv) {
4973 dev_err(dev, "No memory msm_mmc_pad_drv\n");
4974 ret = -ENOMEM;
4975 goto err;
4976 }
4977 drv_data->on = drv;
4978 drv_data->off = drv + drv_data->size;
4979
4980 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
4981 &tmp, &len, drv_data->size);
4982 if (!ret) {
4983 for (i = 0; i < len; i++) {
4984 drv_data->on[i].no = base + i;
4985 drv_data->on[i].val = tmp[i];
4986 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
4987 i, drv_data->on[i].val);
4988 }
4989 } else {
4990 goto err;
4991 }
4992
4993 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
4994 &tmp, &len, drv_data->size);
4995 if (!ret) {
4996 for (i = 0; i < len; i++) {
4997 drv_data->off[i].no = base + i;
4998 drv_data->off[i].val = tmp[i];
4999 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5000 i, drv_data->off[i].val);
5001 }
5002 } else {
5003 goto err;
5004 }
5005
5006 *pad_drv_data = drv_data;
5007err:
5008 return ret;
5009}
5010
5011static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5012 struct mmc_platform_data *pdata)
5013{
5014 int ret = 0, id = 0, cnt, i;
5015 struct msm_mmc_pin_data *pin_data;
5016 struct device_node *np = dev->of_node;
5017
5018 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5019 if (!pin_data) {
5020 dev_err(dev, "No memory for pin_data\n");
5021 ret = -ENOMEM;
5022 goto err;
5023 }
5024
5025 cnt = of_gpio_count(np);
5026 if (cnt > 0) {
5027 pin_data->is_gpio = true;
5028
5029 pin_data->gpio_data = devm_kzalloc(dev,
5030 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5031 if (!pin_data->gpio_data) {
5032 dev_err(dev, "No memory for gpio_data\n");
5033 ret = -ENOMEM;
5034 goto err;
5035 }
5036 pin_data->gpio_data->size = cnt;
5037 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5038 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5039 if (!pin_data->gpio_data->gpio) {
5040 dev_err(dev, "No memory for gpio\n");
5041 ret = -ENOMEM;
5042 goto err;
5043 }
5044
5045 for (i = 0; i < cnt; i++) {
5046 const char *name = NULL;
5047 char result[32];
5048 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5049 of_property_read_string_index(np,
5050 "qcom,sdcc-gpio-names", i, &name);
5051
5052 snprintf(result, 32, "%s-%s",
5053 dev_name(dev), name ? name : "?");
5054 pin_data->gpio_data->gpio[i].name = result;
5055 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5056 pin_data->gpio_data->gpio[i].name,
5057 pin_data->gpio_data->gpio[i].no);
5058 }
5059 } else {
5060 pin_data->pad_data = devm_kzalloc(dev,
5061 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5062 if (!pin_data->pad_data) {
5063 dev_err(dev, "No memory for pin_data->pad_data\n");
5064 ret = -ENOMEM;
5065 goto err;
5066 }
5067
5068 of_property_read_u32(np, "cell-index", &id);
5069
5070 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5071 &pin_data->pad_data->pull);
5072 if (ret)
5073 goto err;
5074 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5075 &pin_data->pad_data->drv);
5076 if (ret)
5077 goto err;
5078 }
5079
5080 pdata->pin_data = pin_data;
5081err:
5082 if (ret)
5083 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5084 return ret;
5085}
5086
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305087#define MAX_PROP_SIZE 32
5088static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5089 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5090{
5091 int len, ret = 0;
5092 const __be32 *prop;
5093 char prop_name[MAX_PROP_SIZE];
5094 struct msm_mmc_reg_data *vreg;
5095 struct device_node *np = dev->of_node;
5096
5097 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5098 if (of_parse_phandle(np, prop_name, 0)) {
5099 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5100 if (!vreg) {
5101 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5102 ret = -ENOMEM;
5103 goto err;
5104 }
5105
5106 vreg->name = vreg_name;
5107
5108 snprintf(prop_name, MAX_PROP_SIZE,
5109 "qcom,sdcc-%s-always_on", vreg_name);
5110 if (of_get_property(np, prop_name, NULL))
5111 vreg->always_on = true;
5112
5113 snprintf(prop_name, MAX_PROP_SIZE,
5114 "qcom,sdcc-%s-lpm_sup", vreg_name);
5115 if (of_get_property(np, prop_name, NULL))
5116 vreg->lpm_sup = true;
5117
5118 snprintf(prop_name, MAX_PROP_SIZE,
5119 "qcom,sdcc-%s-voltage_level", vreg_name);
5120 prop = of_get_property(np, prop_name, &len);
5121 if (!prop || (len != (2 * sizeof(__be32)))) {
5122 dev_warn(dev, "%s %s property\n",
5123 prop ? "invalid format" : "no", prop_name);
5124 } else {
5125 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5126 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5127 }
5128
5129 snprintf(prop_name, MAX_PROP_SIZE,
5130 "qcom,sdcc-%s-current_level", vreg_name);
5131 prop = of_get_property(np, prop_name, &len);
5132 if (!prop || (len != (2 * sizeof(__be32)))) {
5133 dev_warn(dev, "%s %s property\n",
5134 prop ? "invalid format" : "no", prop_name);
5135 } else {
5136 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5137 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5138 }
5139
5140 *vreg_data = vreg;
5141 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5142 vreg->name, vreg->always_on ? "always_on," : "",
5143 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5144 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5145 }
5146
5147err:
5148 return ret;
5149}
5150
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305151static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5152{
5153 int i, ret;
5154 struct mmc_platform_data *pdata;
5155 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305156 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305157 u32 *clk_table, *sup_voltages;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305158 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305159
5160 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5161 if (!pdata) {
5162 dev_err(dev, "could not allocate memory for platform data\n");
5163 goto err;
5164 }
5165
5166 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5167 if (bus_width == 8) {
5168 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5169 } else if (bus_width == 4) {
5170 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5171 } else {
5172 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5173 pdata->mmc_bus_width = 0;
5174 }
5175
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305176 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5177 &sup_voltages, &sup_volt_len, 0);
5178 if (!ret) {
5179 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305180 u32 mask;
5181
5182 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5183 sup_voltages[i + 1]);
5184 if (!mask)
5185 dev_err(dev, "Invalide voltage range %d\n", i);
5186 pdata->ocr_mask |= mask;
5187 }
5188 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305189 }
5190
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305191 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5192 &clk_table, &clk_table_len, 0);
5193 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305194 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305195 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305196 }
5197
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305198 pdata->vreg_data = devm_kzalloc(dev,
5199 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5200 if (!pdata->vreg_data) {
5201 dev_err(dev, "could not allocate memory for vreg_data\n");
5202 goto err;
5203 }
5204
5205 if (msmsdcc_dt_parse_vreg_info(dev,
5206 &pdata->vreg_data->vdd_data, "vdd"))
5207 goto err;
5208
5209 if (msmsdcc_dt_parse_vreg_info(dev,
5210 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5211 goto err;
5212
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305213 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5214 goto err;
5215
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305216 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5217
5218 for (i = 0; i < len; i++) {
5219 const char *name = NULL;
5220
5221 of_property_read_string_index(np,
5222 "qcom,sdcc-bus-speed-mode", i, &name);
5223 if (!name)
5224 continue;
5225
5226 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5227 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5228 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5229 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5230 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5231 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5232 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5233 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5234 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5235 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5236 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5237 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5238 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5239 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5240 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5241 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5242 | MMC_CAP_UHS_DDR50;
5243 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5244 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5245 | MMC_CAP_UHS_DDR50;
5246 }
5247
5248 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5249 if (current_limit == 800)
5250 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5251 else if (current_limit == 600)
5252 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5253 else if (current_limit == 400)
5254 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5255 else if (current_limit == 200)
5256 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5257
5258 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5259 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305260 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5261 pdata->nonremovable = true;
5262 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5263 pdata->disable_cmd23 = true;
5264
5265 return pdata;
5266err:
5267 return NULL;
5268}
5269
San Mehat9d2bd732009-09-22 16:44:22 -07005270static int
5271msmsdcc_probe(struct platform_device *pdev)
5272{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305273 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005274 struct msmsdcc_host *host;
5275 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005276 unsigned long flags;
5277 struct resource *core_irqres = NULL;
5278 struct resource *bam_irqres = NULL;
5279 struct resource *core_memres = NULL;
5280 struct resource *dml_memres = NULL;
5281 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005282 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005283 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305284 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005285 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07005286
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305287 if (pdev->dev.of_node) {
5288 plat = msmsdcc_populate_pdata(&pdev->dev);
5289 of_property_read_u32((&pdev->dev)->of_node,
5290 "cell-index", &pdev->id);
5291 } else {
5292 plat = pdev->dev.platform_data;
5293 }
San Mehat9d2bd732009-09-22 16:44:22 -07005294
5295 /* must have platform data */
5296 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005297 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005298 ret = -EINVAL;
5299 goto out;
5300 }
5301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005302 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005303 return -EINVAL;
5304
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305305 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5306 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5307 return -EINVAL;
5308 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005309
San Mehat9d2bd732009-09-22 16:44:22 -07005310 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005311 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005312 return -ENXIO;
5313 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305314 if (pdev->dev.of_node) {
5315 /*
5316 * Device tree iomem resources are only accessible by index.
5317 * index = 0 -> SDCC register interface
5318 * index = 1 -> DML register interface
5319 * index = 2 -> BAM register interface
5320 * IRQ resources:
5321 * index = 0 -> SDCC IRQ
5322 * index = 1 -> BAM IRQ
5323 */
5324 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5325 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
5326 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
5327 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
5328 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
5329 } else {
5330 for (i = 0; i < pdev->num_resources; i++) {
5331 if (pdev->resource[i].flags & IORESOURCE_MEM) {
5332 if (!strncmp(pdev->resource[i].name,
5333 "sdcc_dml_addr",
5334 sizeof("sdcc_dml_addr")))
5335 dml_memres = &pdev->resource[i];
5336 else if (!strncmp(pdev->resource[i].name,
5337 "sdcc_bam_addr",
5338 sizeof("sdcc_bam_addr")))
5339 bam_memres = &pdev->resource[i];
5340 else
5341 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07005342
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305343 }
5344 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
5345 if (!strncmp(pdev->resource[i].name,
5346 "sdcc_bam_irq",
5347 sizeof("sdcc_bam_irq")))
5348 bam_irqres = &pdev->resource[i];
5349 else
5350 core_irqres = &pdev->resource[i];
5351 }
5352 if (pdev->resource[i].flags & IORESOURCE_DMA) {
5353 if (!strncmp(pdev->resource[i].name,
5354 "sdcc_dma_chnl",
5355 sizeof("sdcc_dma_chnl")))
5356 dmares = &pdev->resource[i];
5357 else if (!strncmp(pdev->resource[i].name,
5358 "sdcc_dma_crci",
5359 sizeof("sdcc_dma_crci")))
5360 dma_crci_res = &pdev->resource[i];
5361 }
Krishna Konda25786ec2011-07-25 16:21:36 -07005362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005363 }
San Mehat9d2bd732009-09-22 16:44:22 -07005364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005365 if (!core_irqres || !core_memres) {
5366 pr_err("%s: Invalid sdcc core resource\n", __func__);
5367 return -ENXIO;
5368 }
5369
5370 /*
5371 * Both BAM and DML memory resource should be preset.
5372 * BAM IRQ resource should also be present.
5373 */
5374 if ((bam_memres && !dml_memres) ||
5375 (!bam_memres && dml_memres) ||
5376 ((bam_memres && dml_memres) && !bam_irqres)) {
5377 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005378 return -ENXIO;
5379 }
5380
5381 /*
5382 * Setup our host structure
5383 */
San Mehat9d2bd732009-09-22 16:44:22 -07005384 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5385 if (!mmc) {
5386 ret = -ENOMEM;
5387 goto out;
5388 }
5389
5390 host = mmc_priv(mmc);
5391 host->pdev_id = pdev->id;
5392 host->plat = plat;
5393 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005394 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305395
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305396 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305397 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005398 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305399 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005401 host->base = ioremap(core_memres->start,
5402 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005403 if (!host->base) {
5404 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305405 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005406 }
5407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005408 host->core_irqres = core_irqres;
5409 host->bam_irqres = bam_irqres;
5410 host->core_memres = core_memres;
5411 host->dml_memres = dml_memres;
5412 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005413 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005414 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005415 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305416 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005418#ifdef CONFIG_MMC_EMBEDDED_SDIO
5419 if (plat->embedded_sdio)
5420 mmc_set_embedded_sdio_data(mmc,
5421 &plat->embedded_sdio->cis,
5422 &plat->embedded_sdio->cccr,
5423 plat->embedded_sdio->funcs,
5424 plat->embedded_sdio->num_funcs);
5425#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005426
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305427 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5428 (unsigned long)host);
5429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005430 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5431 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305432 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005433 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305434 ret = msmsdcc_init_dma(host);
5435 if (ret)
5436 goto ioremap_free;
5437 } else {
5438 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005439 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305440 }
San Mehat9d2bd732009-09-22 16:44:22 -07005441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005442 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305443 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005444 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305445 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5446 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5447 /* Vote for max. clk rate for max. performance */
5448 ret = clk_set_rate(host->bus_clk, INT_MAX);
5449 if (ret)
5450 goto bus_clk_put;
5451 ret = clk_prepare_enable(host->bus_clk);
5452 if (ret)
5453 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005454 }
5455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005456 /*
5457 * Setup main peripheral bus clock
5458 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005459 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005460 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305461 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005462 if (ret)
5463 goto pclk_put;
5464
5465 host->pclk_rate = clk_get_rate(host->pclk);
5466 }
5467
5468 /*
5469 * Setup SDC MMC clock
5470 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005471 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005472 if (IS_ERR(host->clk)) {
5473 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005474 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005475 }
5476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005477 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305478 if (ret) {
5479 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5480 goto clk_put;
5481 }
5482
Asutosh Dasf5298c32012-04-03 14:51:47 +05305483 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005484 if (ret)
5485 goto clk_put;
5486
San Mehat9d2bd732009-09-22 16:44:22 -07005487 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305488 if (!host->clk_rate)
5489 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305490
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305491 set_default_hw_caps(host);
5492
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305493 /*
5494 * Set the register write delay according to min. clock frequency
5495 * supported and update later when the host->clk_rate changes.
5496 */
5497 host->reg_write_delay =
5498 (1 + ((3 * USEC_PER_SEC) /
5499 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005500
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305501 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305502 /* Apply Hard reset to SDCC to put it in power on default state */
5503 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005504
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005505#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305506 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005507 if (host->plat->cpu_dma_latency)
5508 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5509 else
5510 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5511 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305512 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5513
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305514 ret = msmsdcc_msm_bus_register(host);
5515 if (ret)
5516 goto pm_qos_remove;
5517
5518 if (host->msm_bus_vote.client_handle)
5519 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5520 msmsdcc_msm_bus_work);
5521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005522 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005523 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005524 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005525 goto clk_disable;
5526 }
5527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005528
5529 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305530 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005531 /* Initialize SPS */
5532 ret = msmsdcc_sps_init(host);
5533 if (ret)
5534 goto vreg_deinit;
5535 /* Initialize DML */
5536 ret = msmsdcc_dml_init(host);
5537 if (ret)
5538 goto sps_exit;
5539 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305540 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005541
San Mehat9d2bd732009-09-22 16:44:22 -07005542 /*
5543 * Setup MMC host structure
5544 */
5545 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005546 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5547 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005548 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305549 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005551 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5552 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005553 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305554 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07005555
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305556 /*
5557 * If we send the CMD23 before multi block write/read command
5558 * then we need not to send CMD12 at the end of the transfer.
5559 * If we don't send the CMD12 then only way to detect the PROG_DONE
5560 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5561 * controller. So let's enable the CMD23 for SDCC4 only.
5562 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305563 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305564 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005566 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305567 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005568 /*
5569 * XPC controls the maximum current in the default speed mode of SDXC
5570 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5571 * XPC=1 means 150mA (max.) and speed class is supported.
5572 */
5573 if (plat->xpc_cap)
5574 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5575 MMC_CAP_SET_XPC_180);
5576
Maya Erez25e22612012-05-20 08:45:01 +03005577 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03005578 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305579 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005580 mmc->caps2 |= MMC_CAP2_SANITIZE;
5581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005582 if (plat->nonremovable)
5583 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005584 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005585
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005586 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005588 if (plat->is_sdio_al_client)
5589 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005590
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305591 mmc->max_segs = msmsdcc_get_nr_sg(host);
5592 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5593 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005594
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305595 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005596 mmc->max_seg_size = mmc->max_req_size;
5597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005598 writel_relaxed(0, host->base + MMCIMASK0);
5599 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305600 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005602 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5603 mb();
5604 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005606 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5607 DRIVER_NAME " (cmd)", host);
5608 if (ret)
5609 goto dml_exit;
5610
5611 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5612 DRIVER_NAME " (pio)", host);
5613 if (ret)
5614 goto irq_free;
5615
5616 /*
5617 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5618 * IRQ is un-necessarily being monitored by MPM (Modem power
5619 * management block) during idle-power collapse. The MPM will be
5620 * configured to monitor the DATA1 GPIO line with level-low trigger
5621 * and thus depending on the GPIO status, it prevents TCXO shutdown
5622 * during idle-power collapse.
5623 */
5624 disable_irq(core_irqres->start);
5625 host->sdcc_irq_disabled = 1;
5626
5627 if (plat->sdiowakeup_irq) {
5628 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5629 mmc_hostname(mmc));
5630 ret = request_irq(plat->sdiowakeup_irq,
5631 msmsdcc_platform_sdiowakeup_irq,
5632 IRQF_SHARED | IRQF_TRIGGER_LOW,
5633 DRIVER_NAME "sdiowakeup", host);
5634 if (ret) {
5635 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5636 plat->sdiowakeup_irq, ret);
5637 goto pio_irq_free;
5638 } else {
5639 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305640 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005641 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305642 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005643 }
5644 spin_unlock_irqrestore(&host->lock, flags);
5645 }
5646 }
5647
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305648 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005649 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5650 mmc_hostname(mmc));
5651 }
5652
5653 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5654 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005655 /*
5656 * Setup card detect change
5657 */
5658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005659 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005660 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005661 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005662 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005663 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005664
Krishna Konda941604a2012-01-10 17:46:34 -08005665 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005666 }
San Mehat9d2bd732009-09-22 16:44:22 -07005667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005668 if (plat->status_irq) {
5669 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005670 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005671 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005672 DRIVER_NAME " (slot)",
5673 host);
5674 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005675 pr_err("Unable to get slot IRQ %d (%d)\n",
5676 plat->status_irq, ret);
5677 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005678 }
5679 } else if (plat->register_status_notify) {
5680 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5681 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005682 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005683 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005684
5685 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005686
5687 ret = pm_runtime_set_active(&(pdev)->dev);
5688 if (ret < 0)
5689 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5690 __func__, ret);
5691 /*
5692 * There is no notion of suspend/resume for SD/MMC/SDIO
5693 * cards. So host can be suspended/resumed with out
5694 * worrying about its children.
5695 */
5696 pm_suspend_ignore_children(&(pdev)->dev, true);
5697
5698 /*
5699 * MMC/SD/SDIO bus suspend/resume operations are defined
5700 * only for the slots that will be used for non-removable
5701 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5702 * defined. Otherwise, they simply become card removal and
5703 * insertion events during suspend and resume respectively.
5704 * Hence, enable run-time PM only for slots for which bus
5705 * suspend/resume operations are defined.
5706 */
5707#ifdef CONFIG_MMC_UNSAFE_RESUME
5708 /*
5709 * If this capability is set, MMC core will enable/disable host
5710 * for every claim/release operation on a host. We use this
5711 * notification to increment/decrement runtime pm usage count.
5712 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005713 pm_runtime_enable(&(pdev)->dev);
5714#else
5715 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005716 pm_runtime_enable(&(pdev)->dev);
5717 }
5718#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305719 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005720 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5721 (unsigned long)host);
5722
San Mehat9d2bd732009-09-22 16:44:22 -07005723 mmc_add_host(mmc);
5724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005725#ifdef CONFIG_HAS_EARLYSUSPEND
5726 host->early_suspend.suspend = msmsdcc_early_suspend;
5727 host->early_suspend.resume = msmsdcc_late_resume;
5728 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5729 register_early_suspend(&host->early_suspend);
5730#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005731
Krishna Konda25786ec2011-07-25 16:21:36 -07005732 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5733 " dmacrcri %d\n", mmc_hostname(mmc),
5734 (unsigned long long)core_memres->start,
5735 (unsigned int) core_irqres->start,
5736 (unsigned int) plat->status_irq, host->dma.channel,
5737 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005738
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305739 pr_info("%s: Controller capabilities: 0x%.8x\n",
5740 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005741 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5742 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5743 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5744 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5745 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5746 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5747 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5748 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5749 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5750 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5751 host->eject);
5752 pr_info("%s: Power save feature enable = %d\n",
5753 mmc_hostname(mmc), msmsdcc_pwrsave);
5754
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305755 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07005756 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005757 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005758 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005759 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005760 mmc_hostname(mmc), host->dma.cmd_busaddr,
5761 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305762 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005763 pr_info("%s: SPS-BAM data transfer mode available\n",
5764 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005765 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005766 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005767
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005768#if defined(CONFIG_DEBUG_FS)
5769 msmsdcc_dbg_createhost(host);
5770#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305771
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305772 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5773 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5774 sysfs_attr_init(&host->max_bus_bw.attr);
5775 host->max_bus_bw.attr.name = "max_bus_bw";
5776 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5777 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305778 if (ret)
5779 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305780
5781 if (!plat->status_irq) {
5782 host->polling.show = show_polling;
5783 host->polling.store = store_polling;
5784 sysfs_attr_init(&host->polling.attr);
5785 host->polling.attr.name = "polling";
5786 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5787 ret = device_create_file(&pdev->dev, &host->polling);
5788 if (ret)
5789 goto remove_max_bus_bw_file;
5790 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305791 host->idle_timeout.show = show_idle_timeout;
5792 host->idle_timeout.store = store_idle_timeout;
5793 sysfs_attr_init(&host->idle_timeout.attr);
5794 host->idle_timeout.attr.name = "idle_timeout";
5795 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
5796 ret = device_create_file(&pdev->dev, &host->idle_timeout);
5797 if (ret)
5798 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07005799 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005800
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305801 remove_polling_file:
5802 if (!plat->status_irq)
5803 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305804 remove_max_bus_bw_file:
5805 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005806 platform_irq_free:
5807 del_timer_sync(&host->req_tout_timer);
5808 pm_runtime_disable(&(pdev)->dev);
5809 pm_runtime_set_suspended(&(pdev)->dev);
5810
5811 if (plat->status_irq)
5812 free_irq(plat->status_irq, host);
5813 sdiowakeup_irq_free:
5814 wake_lock_destroy(&host->sdio_suspend_wlock);
5815 if (plat->sdiowakeup_irq)
5816 free_irq(plat->sdiowakeup_irq, host);
5817 pio_irq_free:
5818 if (plat->sdiowakeup_irq)
5819 wake_lock_destroy(&host->sdio_wlock);
5820 free_irq(core_irqres->start, host);
5821 irq_free:
5822 free_irq(core_irqres->start, host);
5823 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305824 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005825 msmsdcc_dml_exit(host);
5826 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305827 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005828 msmsdcc_sps_exit(host);
5829 vreg_deinit:
5830 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005831 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005832 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305833 msmsdcc_msm_bus_unregister(host);
5834 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005835 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305836 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005837 clk_put:
5838 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005839 pclk_disable:
5840 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305841 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005842 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005843 if (!IS_ERR(host->pclk))
5844 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305845 if (!IS_ERR_OR_NULL(host->bus_clk))
5846 clk_disable_unprepare(host->bus_clk);
5847 bus_clk_put:
5848 if (!IS_ERR_OR_NULL(host->bus_clk))
5849 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305850 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005851 if (host->dmares)
5852 dma_free_coherent(NULL,
5853 sizeof(struct msmsdcc_nc_dmadata),
5854 host->dma.nc, host->dma.nc_busaddr);
5855 }
5856 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305857 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005858 host_free:
5859 mmc_free_host(mmc);
5860 out:
5861 return ret;
5862}
5863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005864static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005865{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005866 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5867 struct mmc_platform_data *plat;
5868 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005870 if (!mmc)
5871 return -ENXIO;
5872
5873 if (pm_runtime_suspended(&(pdev)->dev))
5874 pm_runtime_resume(&(pdev)->dev);
5875
5876 host = mmc_priv(mmc);
5877
5878 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5879 plat = host->plat;
5880
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305881 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005882 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305883 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305884 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005885
5886 del_timer_sync(&host->req_tout_timer);
5887 tasklet_kill(&host->dma_tlet);
5888 tasklet_kill(&host->sps.tlet);
5889 mmc_remove_host(mmc);
5890
5891 if (plat->status_irq)
5892 free_irq(plat->status_irq, host);
5893
5894 wake_lock_destroy(&host->sdio_suspend_wlock);
5895 if (plat->sdiowakeup_irq) {
5896 wake_lock_destroy(&host->sdio_wlock);
5897 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5898 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005899 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005900
5901 free_irq(host->core_irqres->start, host);
5902 free_irq(host->core_irqres->start, host);
5903
5904 clk_put(host->clk);
5905 if (!IS_ERR(host->pclk))
5906 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305907 if (!IS_ERR_OR_NULL(host->bus_clk))
5908 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005909
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005910 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305911 pm_qos_remove_request(&host->pm_qos_req_dma);
5912
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305913 if (host->msm_bus_vote.client_handle) {
5914 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5915 msmsdcc_msm_bus_unregister(host);
5916 }
5917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005918 msmsdcc_vreg_init(host, false);
5919
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305920 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005921 if (host->dmares)
5922 dma_free_coherent(NULL,
5923 sizeof(struct msmsdcc_nc_dmadata),
5924 host->dma.nc, host->dma.nc_busaddr);
5925 }
5926
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305927 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005928 msmsdcc_dml_exit(host);
5929 msmsdcc_sps_exit(host);
5930 }
5931
5932 iounmap(host->base);
5933 mmc_free_host(mmc);
5934
5935#ifdef CONFIG_HAS_EARLYSUSPEND
5936 unregister_early_suspend(&host->early_suspend);
5937#endif
5938 pm_runtime_disable(&(pdev)->dev);
5939 pm_runtime_set_suspended(&(pdev)->dev);
5940
5941 return 0;
5942}
5943
5944#ifdef CONFIG_MSM_SDIO_AL
5945int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5946{
5947 struct msmsdcc_host *host = mmc_priv(mmc);
5948 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305949 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005950
Asutosh Dasf5298c32012-04-03 14:51:47 +05305951 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005952 spin_lock_irqsave(&host->lock, flags);
5953 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5954 enable ? "En" : "Dis");
5955
5956 if (enable) {
5957 if (!host->sdcc_irq_disabled) {
5958 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305959 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005960 host->sdcc_irq_disabled = 1;
5961 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305962 rc = msmsdcc_setup_clocks(host, false);
5963 if (rc)
5964 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005965
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305966 if (host->plat->sdio_lpm_gpio_setup &&
5967 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005968 spin_unlock_irqrestore(&host->lock, flags);
5969 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5970 spin_lock_irqsave(&host->lock, flags);
5971 host->sdio_gpio_lpm = 1;
5972 }
5973
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305974 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005975 msmsdcc_enable_irq_wake(host);
5976 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305977 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 }
5979 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305980 rc = msmsdcc_setup_clocks(host, true);
5981 if (rc)
5982 goto out;
5983
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305984 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005985 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305986 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005987 msmsdcc_disable_irq_wake(host);
5988 }
5989
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305990 if (host->plat->sdio_lpm_gpio_setup &&
5991 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005992 spin_unlock_irqrestore(&host->lock, flags);
5993 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5994 spin_lock_irqsave(&host->lock, flags);
5995 host->sdio_gpio_lpm = 0;
5996 }
5997
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305998 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005999 writel_relaxed(host->mci_irqenable,
6000 host->base + MMCIMASK0);
6001 mb();
6002 enable_irq(host->core_irqres->start);
6003 host->sdcc_irq_disabled = 0;
6004 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006005 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306006out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006007 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306008 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306009 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006010}
6011#else
6012int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6013{
6014 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006015}
6016#endif
6017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006018#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306019#ifdef CONFIG_MMC_CLKGATE
6020static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6021{
6022 struct mmc_host *mmc = host->mmc;
6023 unsigned long flags;
6024
6025 mmc_host_clk_hold(mmc);
6026 spin_lock_irqsave(&mmc->clk_lock, flags);
6027 mmc->clk_old = mmc->ios.clock;
6028 mmc->ios.clock = 0;
6029 mmc->clk_gated = true;
6030 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6031 mmc_set_ios(mmc);
6032 mmc_host_clk_release(mmc);
6033}
6034
6035static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6036{
6037 struct mmc_host *mmc = host->mmc;
6038
6039 mmc_host_clk_hold(mmc);
6040 mmc->ios.clock = host->clk_rate;
6041 mmc_set_ios(mmc);
6042 mmc_host_clk_release(mmc);
6043}
6044#else
6045static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6046{
6047 struct mmc_host *mmc = host->mmc;
6048
6049 mmc->ios.clock = 0;
6050 mmc_set_ios(mmc);
6051}
6052
6053static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6054{
6055 struct mmc_host *mmc = host->mmc;
6056
6057 mmc->ios.clock = host->clk_rate;
6058 mmc_set_ios(mmc);
6059}
6060#endif
6061
San Mehat9d2bd732009-09-22 16:44:22 -07006062static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006063msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006064{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006065 struct mmc_host *mmc = dev_get_drvdata(dev);
6066 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006067 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306068 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006069
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306070 if (host->plat->is_sdio_al_client) {
6071 rc = 0;
6072 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006073 }
San Mehat9d2bd732009-09-22 16:44:22 -07006074
Sahitya Tummala7661a452011-07-18 13:28:35 +05306075 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006076 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006077 host->sdcc_suspending = 1;
6078 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006080 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006081 * MMC core thinks that host is disabled by now since
6082 * runtime suspend is scheduled after msmsdcc_disable()
6083 * is called. Thus, MMC core will try to enable the host
6084 * while suspending it. This results in a synchronous
6085 * runtime resume request while in runtime suspending
6086 * context and hence inorder to complete this resume
6087 * requet, it will wait for suspend to be complete,
6088 * but runtime suspend also can not proceed further
6089 * until the host is resumed. Thus, it leads to a hang.
6090 * Hence, increase the pm usage count before suspending
6091 * the host so that any resume requests after this will
6092 * simple become pm usage counter increment operations.
6093 */
6094 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306095 /* If there is pending detect work abort runtime suspend */
6096 if (unlikely(work_busy(&mmc->detect.work)))
6097 rc = -EAGAIN;
6098 else
6099 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006100 pm_runtime_put_noidle(dev);
6101
6102 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306103 spin_lock_irqsave(&host->lock, flags);
6104 host->sdcc_suspended = true;
6105 spin_unlock_irqrestore(&host->lock, flags);
6106 if (mmc->card && mmc_card_sdio(mmc->card) &&
6107 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006108 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306109 * If SDIO function driver doesn't want
6110 * to power off the card, atleast turn off
6111 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006112 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306113 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006114 }
6115 }
6116 host->sdcc_suspending = 0;
6117 mmc->suspend_task = NULL;
6118 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6119 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006120 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306121 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306122out:
6123 /* set bus bandwidth to 0 immediately */
6124 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006125 return rc;
6126}
6127
6128static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006129msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006130{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006131 struct mmc_host *mmc = dev_get_drvdata(dev);
6132 struct msmsdcc_host *host = mmc_priv(mmc);
6133 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006135 if (host->plat->is_sdio_al_client)
6136 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006137
Sahitya Tummala7661a452011-07-18 13:28:35 +05306138 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006139 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306140 if (mmc->card && mmc_card_sdio(mmc->card) &&
6141 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306142 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306143 }
San Mehat9d2bd732009-09-22 16:44:22 -07006144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006145 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006147 /*
6148 * FIXME: Clearing of flags must be handled in clients
6149 * resume handler.
6150 */
6151 spin_lock_irqsave(&host->lock, flags);
6152 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306153 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006154 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006156 /*
6157 * After resuming the host wait for sometime so that
6158 * the SDIO work will be processed.
6159 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306160 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306161 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006162 host->plat->sdiowakeup_irq) &&
6163 wake_lock_active(&host->sdio_wlock))
6164 wake_lock_timeout(&host->sdio_wlock, 1);
6165 }
6166
6167 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006168 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05306169 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006170 return 0;
6171}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006172
6173static int msmsdcc_runtime_idle(struct device *dev)
6174{
6175 struct mmc_host *mmc = dev_get_drvdata(dev);
6176 struct msmsdcc_host *host = mmc_priv(mmc);
6177
6178 if (host->plat->is_sdio_al_client)
6179 return 0;
6180
6181 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306182 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006183
6184 return -EAGAIN;
6185}
6186
6187static int msmsdcc_pm_suspend(struct device *dev)
6188{
6189 struct mmc_host *mmc = dev_get_drvdata(dev);
6190 struct msmsdcc_host *host = mmc_priv(mmc);
6191 int rc = 0;
6192
6193 if (host->plat->is_sdio_al_client)
6194 return 0;
6195
6196
6197 if (host->plat->status_irq)
6198 disable_irq(host->plat->status_irq);
6199
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006200 if (!pm_runtime_suspended(dev))
6201 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006202
6203 return rc;
6204}
6205
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306206static int msmsdcc_suspend_noirq(struct device *dev)
6207{
6208 struct mmc_host *mmc = dev_get_drvdata(dev);
6209 struct msmsdcc_host *host = mmc_priv(mmc);
6210 int rc = 0;
6211
6212 /*
6213 * After platform suspend there may be active request
6214 * which might have enabled clocks. For example, in SDIO
6215 * case, ksdioirq thread might have scheduled after sdcc
6216 * suspend but before system freeze. In that case abort
6217 * suspend and retry instead of keeping the clocks on
6218 * during suspend and not allowing TCXO.
6219 */
6220
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306221 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306222 pr_warn("%s: clocks are on after suspend, aborting system "
6223 "suspend\n", mmc_hostname(mmc));
6224 rc = -EAGAIN;
6225 }
6226
6227 return rc;
6228}
6229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006230static int msmsdcc_pm_resume(struct device *dev)
6231{
6232 struct mmc_host *mmc = dev_get_drvdata(dev);
6233 struct msmsdcc_host *host = mmc_priv(mmc);
6234 int rc = 0;
6235
6236 if (host->plat->is_sdio_al_client)
6237 return 0;
6238
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006239 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306240 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006241 else
6242 host->pending_resume = true;
6243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006244 if (host->plat->status_irq) {
6245 msmsdcc_check_status((unsigned long)host);
6246 enable_irq(host->plat->status_irq);
6247 }
6248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006249 return rc;
6250}
6251
Daniel Walker08ecfde2010-06-23 12:32:20 -07006252#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006253static int msmsdcc_runtime_suspend(struct device *dev)
6254{
6255 return 0;
6256}
6257static int msmsdcc_runtime_idle(struct device *dev)
6258{
6259 return 0;
6260}
6261static int msmsdcc_pm_suspend(struct device *dev)
6262{
6263 return 0;
6264}
6265static int msmsdcc_pm_resume(struct device *dev)
6266{
6267 return 0;
6268}
6269static int msmsdcc_suspend_noirq(struct device *dev)
6270{
6271 return 0;
6272}
6273static int msmsdcc_runtime_resume(struct device *dev)
6274{
6275 return 0;
6276}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006277#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006279static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6280 .runtime_suspend = msmsdcc_runtime_suspend,
6281 .runtime_resume = msmsdcc_runtime_resume,
6282 .runtime_idle = msmsdcc_runtime_idle,
6283 .suspend = msmsdcc_pm_suspend,
6284 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306285 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006286};
6287
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306288static const struct of_device_id msmsdcc_dt_match[] = {
6289 {.compatible = "qcom,msm-sdcc"},
6290
6291};
6292MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6293
San Mehat9d2bd732009-09-22 16:44:22 -07006294static struct platform_driver msmsdcc_driver = {
6295 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006296 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006297 .driver = {
6298 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006299 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306300 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006301 },
6302};
6303
6304static int __init msmsdcc_init(void)
6305{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006306#if defined(CONFIG_DEBUG_FS)
6307 int ret = 0;
6308 ret = msmsdcc_dbg_init();
6309 if (ret) {
6310 pr_err("Failed to create debug fs dir \n");
6311 return ret;
6312 }
6313#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006314 return platform_driver_register(&msmsdcc_driver);
6315}
San Mehat9d2bd732009-09-22 16:44:22 -07006316
San Mehat9d2bd732009-09-22 16:44:22 -07006317static void __exit msmsdcc_exit(void)
6318{
6319 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006320
6321#if defined(CONFIG_DEBUG_FS)
6322 debugfs_remove(debugfs_file);
6323 debugfs_remove(debugfs_dir);
6324#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006325}
6326
6327module_init(msmsdcc_init);
6328module_exit(msmsdcc_exit);
6329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006330MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006331MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006332
6333#if defined(CONFIG_DEBUG_FS)
6334
6335static int
6336msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6337{
6338 file->private_data = inode->i_private;
6339 return 0;
6340}
6341
6342static ssize_t
6343msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6344 size_t count, loff_t *ppos)
6345{
6346 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006347 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006348 int max, i;
6349
6350 i = 0;
6351 max = sizeof(buf) - 1;
6352
6353 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6354 host->curr.cmd, host->curr.data);
6355 if (host->curr.cmd) {
6356 struct mmc_command *cmd = host->curr.cmd;
6357
6358 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6359 cmd->opcode, cmd->arg, cmd->flags);
6360 }
6361 if (host->curr.data) {
6362 struct mmc_data *data = host->curr.data;
6363 i += scnprintf(buf + i, max - i,
6364 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6365 data->timeout_ns, data->timeout_clks,
6366 data->blksz, data->blocks, data->error,
6367 data->flags);
6368 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6369 host->curr.xfer_size, host->curr.xfer_remain,
6370 host->curr.data_xfered, host->dma.sg);
6371 }
6372
6373 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6374}
6375
6376static const struct file_operations msmsdcc_dbg_state_ops = {
6377 .read = msmsdcc_dbg_state_read,
6378 .open = msmsdcc_dbg_state_open,
6379};
6380
6381static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6382{
6383 if (debugfs_dir) {
6384 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6385 0644, debugfs_dir, host,
6386 &msmsdcc_dbg_state_ops);
6387 }
6388}
6389
6390static int __init msmsdcc_dbg_init(void)
6391{
6392 int err;
6393
6394 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6395 if (IS_ERR(debugfs_dir)) {
6396 err = PTR_ERR(debugfs_dir);
6397 debugfs_dir = NULL;
6398 return err;
6399 }
6400
6401 return 0;
6402}
6403#endif