blob: c69e7645617ee954d3038374e5f750599a02ce5c [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);
Maya Erez00d7be62013-02-05 13:19:52 +0200161static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
162 struct mmc_request *mrq);
163static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
164 struct mmc_request *mrq);
San Mehat9d2bd732009-09-22 16:44:22 -0700165
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530166static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530167{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530168 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530169
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530170 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530171 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530172 } else { /* DMA or PIO mode */
173 if (NR_SG > MAX_NR_SG_DMA_PIO)
174 ret = MAX_NR_SG_DMA_PIO;
175 }
176
177 return ret;
178}
179
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530180/* Prevent idle power collapse(pc) while operating in peripheral mode */
181static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
182{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700183 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530184 return;
185
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530186 if (vote)
187 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700188 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530189 else
190 pm_qos_update_request(&host->pm_qos_req_dma,
191 PM_QOS_DEFAULT_VALUE);
192}
193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
195static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep);
197static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
198 struct msmsdcc_sps_ep_conn_data *ep);
199#else
200static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
201 struct msmsdcc_sps_ep_conn_data *ep,
202 bool is_producer) { return 0; }
203static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
204 struct msmsdcc_sps_ep_conn_data *ep) { }
205static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530207{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 return 0;
209}
210static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
211 struct msmsdcc_sps_ep_conn_data *ep)
212{
213 return 0;
214}
215static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
216static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
217#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219/**
Maya Erezb7a086f2012-11-29 00:37:36 +0200220 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530221 *
Maya Erezb7a086f2012-11-29 00:37:36 +0200222 * This function resets SPS BAM and DML cores.
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530223 *
224 * This function should be called to recover from error
225 * conditions encountered during CMD/DATA tranfsers with card.
226 *
227 * @host - Pointer to driver's host structure
228 *
229 */
Maya Erezb7a086f2012-11-29 00:37:36 +0200230static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530231{
232 int rc;
233
234 /* Reset all SDCC BAM pipes */
235 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
Maya Erezb7a086f2012-11-29 00:37:36 +0200236 if (rc) {
237 pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530238 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200239 goto out;
240 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530241
Maya Erezb7a086f2012-11-29 00:37:36 +0200242 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
243 if (rc) {
244 pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
Krishna Konda5af8f972012-05-14 16:15:24 -0700245 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200246 goto out;
247 }
248
249 /* Reset BAM */
250 rc = sps_device_reset(host->sps.bam_handle);
251 if (rc) {
252 pr_err("%s: sps_device_reset error=%d\n",
253 mmc_hostname(host->mmc), rc);
254 goto out;
Krishna Konda5af8f972012-05-14 16:15:24 -0700255 }
256
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530257 /* Restore all BAM pipes connections */
258 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Maya Erezb7a086f2012-11-29 00:37:36 +0200259 if (rc) {
260 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530261 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200262 goto out;
263 }
264
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530265 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
Sujit Reddy Thumma8ce39122012-12-27 17:24:45 +0530266 if (rc) {
Maya Erezb7a086f2012-11-29 00:37:36 +0200267 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530268 mmc_hostname(host->mmc), rc);
Sujit Reddy Thumma8ce39122012-12-27 17:24:45 +0530269 goto out;
270 }
271
272 /* Reset and init DML */
273 rc = msmsdcc_dml_init(host);
274 if (rc)
275 pr_err("%s: msmsdcc_dml_init error=%d\n",
276 mmc_hostname(host->mmc), rc);
Maya Erezb7a086f2012-11-29 00:37:36 +0200277
278out:
Sujit Reddy Thumma8ce39122012-12-27 17:24:45 +0530279 if (!rc)
280 host->sps.reset_bam = false;
Maya Erezb7a086f2012-11-29 00:37:36 +0200281 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530282}
283
284/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 * Apply soft reset
286 *
Maya Erezb7a086f2012-11-29 00:37:36 +0200287 * This function applies soft reset to SDCC core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 *
289 * This function should be called to recover from error
290 * conditions encountered with CMD/DATA tranfsers with card.
291 *
292 * Soft reset should only be used with SDCC controller v4.
293 *
294 * @host - Pointer to driver's host structure
295 *
296 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530297static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530300 * Reset controller state machines without resetting
301 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530303 if (is_sw_reset_save_config(host)) {
304 ktime_t start;
305
306 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
307 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
308 msmsdcc_sync_reg_wr(host);
309
310 start = ktime_get();
311 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
312 /*
313 * SW reset can take upto 10HCLK + 15MCLK cycles.
314 * Calculating based on min clk rates (hclk = 27MHz,
315 * mclk = 400KHz) it comes to ~40us. Let's poll for
316 * max. 1ms for reset completion.
317 */
318 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
319 pr_err("%s: %s failed\n",
320 mmc_hostname(host->mmc), __func__);
321 BUG();
322 }
323 }
324 } else {
325 writel_relaxed(0, host->base + MMCICOMMAND);
326 msmsdcc_sync_reg_wr(host);
327 writel_relaxed(0, host->base + MMCIDATACTRL);
328 msmsdcc_sync_reg_wr(host);
329 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530330}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530331
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530332static void msmsdcc_hard_reset(struct msmsdcc_host *host)
333{
334 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530335
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530336 /*
337 * Reset SDCC controller to power on default state.
338 * Don't issue a reset request to clock control block if
339 * SDCC controller itself can support hard reset.
340 */
341 if (is_sw_hard_reset(host)) {
342 ktime_t start;
343
344 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
345 | MCI_SW_RST, host->base + MMCIPOWER);
346 msmsdcc_sync_reg_wr(host);
347
348 start = ktime_get();
349 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST) {
350 /*
351 * See comment in msmsdcc_soft_reset() on choosing 1ms
352 * poll timeout.
353 */
354 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
355 pr_err("%s: %s failed\n",
356 mmc_hostname(host->mmc), __func__);
357 BUG();
358 }
359 }
360 } else {
361 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
362 if (ret)
363 pr_err("%s: Clock assert failed at %u Hz" \
364 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530365 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530366
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530367 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
368 if (ret)
369 pr_err("%s: Clock deassert failed at %u Hz" \
370 " with err %d\n", mmc_hostname(host->mmc),
371 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530372
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530373 mb();
374 /* Give some delay for clock reset to propogate to controller */
375 msmsdcc_delay(host);
376 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530377}
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
380{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530381 if (is_soft_reset(host)) {
Maya Erezb7a086f2012-11-29 00:37:36 +0200382 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530383 /*
Maya Erezb7a086f2012-11-29 00:37:36 +0200384 * delay the SPS BAM reset in thread context as
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530385 * sps_connect/sps_disconnect APIs can be called
386 * only from non-atomic context.
387 */
Maya Erezb7a086f2012-11-29 00:37:36 +0200388 host->sps.reset_bam = true;
389
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530390 msmsdcc_soft_reset(host);
391
392 pr_debug("%s: Applied soft reset to Controller\n",
393 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 } else {
Maya Erezb7a086f2012-11-29 00:37:36 +0200395 /*
396 * When there is a requirement to use this hard reset,
397 * BAM needs to be reconfigured as well by calling
398 * msmsdcc_sps_exit and msmsdcc_sps_init.
399 */
400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 /* Give Clock reset (hard reset) to controller */
402 u32 mci_clk = 0;
403 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404
405 /* Save the controller state */
406 mci_clk = readl_relaxed(host->base + MMCICLOCK);
407 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530408 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530411 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 pr_debug("%s: Controller has been reinitialized\n",
413 mmc_hostname(host->mmc));
414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 /* Restore the contoller state */
416 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530417 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530419 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530421 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530423
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700424 if (host->dummy_52_needed)
425 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426}
427
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530428static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
429{
430 struct mmc_request *mrq = host->curr.mrq;
431
Maya Erez00d7be62013-02-05 13:19:52 +0200432 if (!mrq || !mrq->cmd || !mrq->data)
433 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530434
435 /*
Maya Erez00d7be62013-02-05 13:19:52 +0200436 * If we have not waited for the prog done for write transfer then
437 * perform the DPSM reset without polling for TXACTIVE.
438 * Otherwise, we poll here unnecessarily as TXACTIVE will not be
439 * deasserted until DAT0 (Busy line) goes high.
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530440 */
Maya Erez00d7be62013-02-05 13:19:52 +0200441 if (mrq->data->flags & MMC_DATA_WRITE) {
442 if (!msmsdcc_is_wait_for_prog_done(host, mrq)) {
443 if (is_wait_for_tx_rx_active(host) &&
444 !is_auto_prog_done(host))
445 pr_warning("%s: %s: AUTO_PROG_DONE capability is must\n",
446 mmc_hostname(host->mmc), __func__);
447 goto no_polling;
448 }
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530449 }
450
451 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
452 if (is_wait_for_tx_rx_active(host)) {
453 ktime_t start = ktime_get();
454
455 while (readl_relaxed(host->base + MMCISTATUS) &
456 (MCI_TXACTIVE | MCI_RXACTIVE)) {
457 /*
458 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
459 * cycles (~11us) after data transfer due to clock mux
460 * switching delays. Let's poll for 1ms and panic if
461 * still active.
462 */
463 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
464 pr_err("%s: %s still active\n",
465 mmc_hostname(host->mmc),
466 readl_relaxed(host->base + MMCISTATUS)
467 & MCI_TXACTIVE ? "TX" : "RX");
468 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma565c4312012-11-17 13:03:27 +0530469 msmsdcc_reset_and_restore(host);
Sujit Reddy Thumma565c4312012-11-17 13:03:27 +0530470 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530471 }
472 }
473 }
474
Maya Erez00d7be62013-02-05 13:19:52 +0200475no_polling:
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530476 writel_relaxed(0, host->base + MMCIDATACTRL);
477 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530478out:
479 return;
480}
481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482static int
San Mehat9d2bd732009-09-22 16:44:22 -0700483msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
484{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 int retval = 0;
486
San Mehat9d2bd732009-09-22 16:44:22 -0700487 BUG_ON(host->curr.data);
488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700490
491 if (mrq->data)
492 mrq->data->bytes_xfered = host->curr.data_xfered;
493 if (mrq->cmd->error == -ETIMEDOUT)
494 mdelay(5);
495
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530496 msmsdcc_reset_dpsm(host);
497
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530498 /* Clear current request information as current request has ended */
499 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
500
San Mehat9d2bd732009-09-22 16:44:22 -0700501 /*
502 * Need to drop the host lock here; mmc_request_done may call
503 * back into the driver...
504 */
505 spin_unlock(&host->lock);
506 mmc_request_done(host->mmc, mrq);
507 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
509 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700510}
511
512static void
513msmsdcc_stop_data(struct msmsdcc_host *host)
514{
San Mehat9d2bd732009-09-22 16:44:22 -0700515 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530516 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530517 host->curr.wait_for_auto_prog_done = false;
518 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700519}
520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700522{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523 return host->core_memres->start + MMCIFIFO;
524}
525
526static inline unsigned int msmsdcc_get_min_sup_clk_rate(
527 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530528
Subhash Jadavanidd432952012-03-28 11:25:56 +0530529static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530{
531 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530532 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530533 udelay(host->reg_write_delay);
534 else if (readl_relaxed(host->base + MCI_STATUS2) &
535 MCI_MCLK_REG_WR_ACTIVE) {
536 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530537
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530538 start = ktime_get();
539 while (readl_relaxed(host->base + MCI_STATUS2) &
540 MCI_MCLK_REG_WR_ACTIVE) {
541 diff = ktime_sub(ktime_get(), start);
542 /* poll for max. 1 ms */
543 if (ktime_to_us(diff) > 1000) {
544 pr_warning("%s: previous reg. write is"
545 " still active\n",
546 mmc_hostname(host->mmc));
547 break;
548 }
549 }
550 }
San Mehat9d2bd732009-09-22 16:44:22 -0700551}
552
Subhash Jadavanidd432952012-03-28 11:25:56 +0530553static inline void msmsdcc_delay(struct msmsdcc_host *host)
554{
555 udelay(host->reg_write_delay);
556
San Mehat9d2bd732009-09-22 16:44:22 -0700557}
558
San Mehat56a8b5b2009-11-21 12:29:46 -0800559static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
561{
562 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530564 /*
565 * As after sending the command, we don't write any of the
566 * controller registers and just wait for the
567 * CMD_RESPOND_END/CMD_SENT/Command failure notication
568 * from Controller.
569 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800571}
572
573static void
574msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
575{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
579 writel_relaxed((unsigned int)host->curr.xfer_size,
580 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530582 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800583
San Mehat6ac9ea62009-12-02 17:24:58 -0800584 if (host->cmd_cmd) {
585 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800587 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800588}
589
San Mehat9d2bd732009-09-22 16:44:22 -0700590static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530591msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700592{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530593 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700594 unsigned long flags;
595 struct mmc_request *mrq;
596
597 spin_lock_irqsave(&host->lock, flags);
598 mrq = host->curr.mrq;
599 BUG_ON(!mrq);
600
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530601 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700602 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700603 goto out;
604 }
605
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530606 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700607 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700609 } else {
610 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530611 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700612 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530613 mmc_hostname(host->mmc), host->dma.result);
614 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700615 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530616 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530617 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 host->dma.err.flush[0], host->dma.err.flush[1],
619 host->dma.err.flush[2], host->dma.err.flush[3],
620 host->dma.err.flush[4],
621 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530622 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700623 if (!mrq->data->error)
624 mrq->data->error = -EIO;
625 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530626 if (!mrq->data->host_cookie)
627 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
628 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 if (host->curr.user_pages) {
631 struct scatterlist *sg = host->dma.sg;
632 int i;
633
634 for (i = 0; i < host->dma.num_ents; i++, sg++)
635 flush_dcache_page(sg_page(sg));
636 }
San Mehat9d2bd732009-09-22 16:44:22 -0700637
San Mehat9d2bd732009-09-22 16:44:22 -0700638 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800639 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700640
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530641 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
642 (host->curr.wait_for_auto_prog_done &&
643 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700644 /*
645 * If we've already gotten our DATAEND / DATABLKEND
646 * for this request, then complete it through here.
647 */
San Mehat9d2bd732009-09-22 16:44:22 -0700648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700650 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 host->curr.xfer_remain -= host->curr.xfer_size;
652 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700653 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700654 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700655 host->dummy_52_sent = 1;
656 msmsdcc_start_command(host, &dummy52cmd,
657 MCI_CPSM_PROGENA);
658 goto out;
659 }
660 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530661 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530662 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700663 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530664 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530666 /*
667 * Clear current request information as current
668 * request has ended
669 */
670 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700671 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672
San Mehat9d2bd732009-09-22 16:44:22 -0700673 mmc_request_done(host->mmc, mrq);
674 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530675 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
676 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700677 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530678 }
San Mehat9d2bd732009-09-22 16:44:22 -0700679 }
680
681out:
682 spin_unlock_irqrestore(&host->lock, flags);
683 return;
684}
685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
687/**
688 * Callback notification from SPS driver
689 *
690 * This callback function gets triggered called from
691 * SPS driver when requested SPS data transfer is
692 * completed.
693 *
694 * SPS driver invokes this callback in BAM irq context so
695 * SDCC driver schedule a tasklet for further processing
696 * this callback notification at later point of time in
697 * tasklet context and immediately returns control back
698 * to SPS driver.
699 *
700 * @nofity - Pointer to sps event notify sturcture
701 *
702 */
703static void
704msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
705{
706 struct msmsdcc_host *host =
707 (struct msmsdcc_host *)
708 ((struct sps_event_notify *)notify)->user;
709
710 host->sps.notify = *notify;
711 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
712 mmc_hostname(host->mmc), __func__, notify->event_id,
713 notify->data.transfer.iovec.addr,
714 notify->data.transfer.iovec.size,
715 notify->data.transfer.iovec.flags);
716 /* Schedule a tasklet for completing data transfer */
717 tasklet_schedule(&host->sps.tlet);
718}
719
720/**
721 * Tasklet handler for processing SPS callback event
722 *
723 * This function processing SPS event notification and
724 * checks if the SPS transfer is completed or not and
725 * then accordingly notifies status to MMC core layer.
726 *
727 * This function is called in tasklet context.
728 *
729 * @data - Pointer to sdcc driver data
730 *
731 */
732static void msmsdcc_sps_complete_tlet(unsigned long data)
733{
734 unsigned long flags;
735 int i, rc;
736 u32 data_xfered = 0;
737 struct mmc_request *mrq;
738 struct sps_iovec iovec;
739 struct sps_pipe *sps_pipe_handle;
740 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
741 struct sps_event_notify *notify = &host->sps.notify;
742
743 spin_lock_irqsave(&host->lock, flags);
744 if (host->sps.dir == DMA_FROM_DEVICE)
745 sps_pipe_handle = host->sps.prod.pipe_handle;
746 else
747 sps_pipe_handle = host->sps.cons.pipe_handle;
748 mrq = host->curr.mrq;
749
750 if (!mrq) {
751 spin_unlock_irqrestore(&host->lock, flags);
752 return;
753 }
754
755 pr_debug("%s: %s: sps event_id=%d\n",
756 mmc_hostname(host->mmc), __func__,
757 notify->event_id);
758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700759 /*
760 * Got End of transfer event!!! Check if all of the data
761 * has been transferred?
762 */
763 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
764 rc = sps_get_iovec(sps_pipe_handle, &iovec);
765 if (rc) {
766 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
767 mmc_hostname(host->mmc), __func__, rc, i);
768 break;
769 }
770 data_xfered += iovec.size;
771 }
772
773 if (data_xfered == host->curr.xfer_size) {
774 host->curr.data_xfered = host->curr.xfer_size;
775 host->curr.xfer_remain -= host->curr.xfer_size;
776 pr_debug("%s: Data xfer success. data_xfered=0x%x",
777 mmc_hostname(host->mmc),
778 host->curr.xfer_size);
779 } else {
780 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
781 " xfer_size=%d", mmc_hostname(host->mmc),
782 data_xfered, host->curr.xfer_size);
783 msmsdcc_reset_and_restore(host);
784 if (!mrq->data->error)
785 mrq->data->error = -EIO;
786 }
787
788 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530789 if (!mrq->data->host_cookie)
790 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
791 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 host->sps.sg = NULL;
793 host->sps.busy = 0;
794
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530795 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
796 (host->curr.wait_for_auto_prog_done &&
797 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798 /*
799 * If we've already gotten our DATAEND / DATABLKEND
800 * for this request, then complete it through here.
801 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802
803 if (!mrq->data->error) {
804 host->curr.data_xfered = host->curr.xfer_size;
805 host->curr.xfer_remain -= host->curr.xfer_size;
806 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700807 if (host->dummy_52_needed) {
808 mrq->data->bytes_xfered = host->curr.data_xfered;
809 host->dummy_52_sent = 1;
810 msmsdcc_start_command(host, &dummy52cmd,
811 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700812 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700813 return;
814 }
815 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530816 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530817 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530819 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530821 /*
822 * Clear current request information as current
823 * request has ended
824 */
825 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 spin_unlock_irqrestore(&host->lock, flags);
827
828 mmc_request_done(host->mmc, mrq);
829 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530830 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
831 || !mrq->sbc)) {
832 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833 }
834 }
835 spin_unlock_irqrestore(&host->lock, flags);
836}
837
838/**
839 * Exit from current SPS data transfer
840 *
841 * This function exits from current SPS data transfer.
842 *
843 * This function should be called when error condition
844 * is encountered during data transfer.
845 *
846 * @host - Pointer to sdcc host structure
847 *
848 */
849static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
850{
851 struct mmc_request *mrq;
852
853 mrq = host->curr.mrq;
854 BUG_ON(!mrq);
855
856 msmsdcc_reset_and_restore(host);
857 if (!mrq->data->error)
858 mrq->data->error = -EIO;
859
860 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530861 if (!mrq->data->host_cookie)
862 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
863 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864
865 host->sps.sg = NULL;
866 host->sps.busy = 0;
867 if (host->curr.data)
868 msmsdcc_stop_data(host);
869
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530870 if (!mrq->data->stop || mrq->cmd->error ||
871 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530873 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
874 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875 msmsdcc_start_command(host, mrq->data->stop, 0);
876
877}
878#else
879static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
880static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
881static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
882#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
883
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530884static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530886static void
887msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
888 unsigned int result,
889 struct msm_dmov_errdata *err)
890{
891 struct msmsdcc_dma_data *dma_data =
892 container_of(cmd, struct msmsdcc_dma_data, hdr);
893 struct msmsdcc_host *host = dma_data->host;
894
895 dma_data->result = result;
896 if (err)
897 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
898
899 tasklet_schedule(&host->dma_tlet);
900}
901
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530902static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
903 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700904{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530905 bool ret = true;
906 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700907
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530908 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530909 /*
910 * BAM Mode: Fall back on PIO if size is less
911 * than or equal to SPS_MIN_XFER_SIZE bytes.
912 */
913 if (xfer_size <= SPS_MIN_XFER_SIZE)
914 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530915 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530916 /*
917 * ADM Mode: Fall back on PIO if size is less than FIFO size
918 * or not integer multiple of FIFO size
919 */
920 if (xfer_size % MCI_FIFOSIZE)
921 ret = false;
922 } else {
923 /* PIO Mode */
924 ret = false;
925 }
926
927 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700928}
929
930static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
931{
932 struct msmsdcc_nc_dmadata *nc;
933 dmov_box *box;
934 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700935 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530936 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700937 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530938 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700939
Krishna Konda25786ec2011-07-25 16:21:36 -0700940 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700942
Krishna Konda25786ec2011-07-25 16:21:36 -0700943 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700944
945 host->dma.sg = data->sg;
946 host->dma.num_ents = data->sg_len;
947
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530948 /* Prevent memory corruption */
949 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800950
San Mehat9d2bd732009-09-22 16:44:22 -0700951 nc = host->dma.nc;
952
San Mehat9d2bd732009-09-22 16:44:22 -0700953 if (data->flags & MMC_DATA_READ)
954 host->dma.dir = DMA_FROM_DEVICE;
955 else
956 host->dma.dir = DMA_TO_DEVICE;
957
Asutosh Dasaccacd42012-03-08 14:33:17 +0530958 if (!data->host_cookie) {
959 n = msmsdcc_prep_xfer(host, data);
960 if (unlikely(n < 0)) {
961 host->dma.sg = NULL;
962 host->dma.num_ents = 0;
963 return -ENOMEM;
964 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800965 }
San Mehat9d2bd732009-09-22 16:44:22 -0700966
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530967 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
968 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700969 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530970 for (i = 0; i < host->dma.num_ents; i++) {
971 len = sg_dma_len(sg);
972 offset = 0;
973
974 do {
975 /* Check if we can do DMA */
976 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
977 err = -ENOTSUPP;
978 goto unmap;
979 }
980
981 box->cmd = CMD_MODE_BOX;
982
983 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
984 len = MMC_MAX_DMA_BOX_LENGTH;
985 len -= len % data->blksz;
986 }
987 rows = (len % MCI_FIFOSIZE) ?
988 (len / MCI_FIFOSIZE) + 1 :
989 (len / MCI_FIFOSIZE);
990
991 if (data->flags & MMC_DATA_READ) {
992 box->src_row_addr = msmsdcc_fifo_addr(host);
993 box->dst_row_addr = sg_dma_address(sg) + offset;
994 box->src_dst_len = (MCI_FIFOSIZE << 16) |
995 (MCI_FIFOSIZE);
996 box->row_offset = MCI_FIFOSIZE;
997 box->num_rows = rows * ((1 << 16) + 1);
998 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
999 } else {
1000 box->src_row_addr = sg_dma_address(sg) + offset;
1001 box->dst_row_addr = msmsdcc_fifo_addr(host);
1002 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1003 (MCI_FIFOSIZE);
1004 box->row_offset = (MCI_FIFOSIZE << 16);
1005 box->num_rows = rows * ((1 << 16) + 1);
1006 box->cmd |= CMD_DST_CRCI(host->dma.crci);
1007 }
1008
1009 offset += len;
1010 len = sg_dma_len(sg) - offset;
1011 box++;
1012 box_cmd_cnt++;
1013 } while (len);
1014 sg++;
1015 }
1016 /* Mark last command */
1017 box--;
1018 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001019
1020 /* location of command block must be 64 bit aligned */
1021 BUG_ON(host->dma.cmd_busaddr & 0x07);
1022
1023 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1024 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1025 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1026 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1027
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301028 /* Flush all data to memory before starting dma */
1029 mb();
1030
1031unmap:
1032 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301033 if (!data->host_cookie)
1034 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1035 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301036 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1037 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001038 }
1039
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301040 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001041}
1042
Asutosh Dasaccacd42012-03-08 14:33:17 +05301043static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1044 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001045{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301046 int rc = 0;
1047 unsigned int dir;
1048
1049 /* Prevent memory corruption */
1050 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1051
1052 if (data->flags & MMC_DATA_READ)
1053 dir = DMA_FROM_DEVICE;
1054 else
1055 dir = DMA_TO_DEVICE;
1056
1057 /* Make sg buffers DMA ready */
1058 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1059 dir);
1060
1061 if (unlikely(rc != data->sg_len)) {
1062 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1063 mmc_hostname(host->mmc), rc);
1064 rc = -ENOMEM;
1065 goto dma_map_err;
1066 }
1067
1068 pr_debug("%s: %s: %s: sg_len=%d\n",
1069 mmc_hostname(host->mmc), __func__,
1070 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1071 data->sg_len);
1072
1073 goto out;
1074
1075dma_map_err:
1076 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1077 data->flags);
1078out:
1079 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001080}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1082/**
1083 * Submits data transfer request to SPS driver
1084 *
1085 * This function make sg (scatter gather) data buffers
1086 * DMA ready and then submits them to SPS driver for
1087 * transfer.
1088 *
1089 * @host - Pointer to sdcc host structure
1090 * @data - Pointer to mmc_data structure
1091 *
1092 * @return 0 if success else negative value
1093 */
1094static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301095 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001096{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 int rc = 0;
1098 u32 flags;
1099 int i;
1100 u32 addr, len, data_cnt;
1101 struct scatterlist *sg = data->sg;
1102 struct sps_pipe *sps_pipe_handle;
1103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104 host->sps.sg = data->sg;
1105 host->sps.num_ents = data->sg_len;
1106 host->sps.xfer_req_cnt = 0;
1107 if (data->flags & MMC_DATA_READ) {
1108 host->sps.dir = DMA_FROM_DEVICE;
1109 sps_pipe_handle = host->sps.prod.pipe_handle;
1110 } else {
1111 host->sps.dir = DMA_TO_DEVICE;
1112 sps_pipe_handle = host->sps.cons.pipe_handle;
1113 }
1114
Asutosh Dasaccacd42012-03-08 14:33:17 +05301115 if (!data->host_cookie) {
1116 rc = msmsdcc_prep_xfer(host, data);
1117 if (unlikely(rc < 0)) {
1118 host->dma.sg = NULL;
1119 host->dma.num_ents = 0;
1120 goto out;
1121 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 }
1123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 for (i = 0; i < data->sg_len; i++) {
1125 /*
1126 * Check if this is the last buffer to transfer?
1127 * If yes then set the INT and EOT flags.
1128 */
1129 len = sg_dma_len(sg);
1130 addr = sg_dma_address(sg);
1131 flags = 0;
1132 while (len > 0) {
1133 if (len > SPS_MAX_DESC_SIZE) {
1134 data_cnt = SPS_MAX_DESC_SIZE;
1135 } else {
1136 data_cnt = len;
1137 if (i == data->sg_len - 1)
1138 flags = SPS_IOVEC_FLAG_INT |
1139 SPS_IOVEC_FLAG_EOT;
1140 }
1141 rc = sps_transfer_one(sps_pipe_handle, addr,
1142 data_cnt, host, flags);
1143 if (rc) {
1144 pr_err("%s: sps_transfer_one() error! rc=%d,"
1145 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1146 mmc_hostname(host->mmc), rc,
1147 (u32)sps_pipe_handle, (u32)sg, i);
1148 goto dma_map_err;
1149 }
1150 addr += data_cnt;
1151 len -= data_cnt;
1152 host->sps.xfer_req_cnt++;
1153 }
1154 sg++;
1155 }
1156 goto out;
1157
1158dma_map_err:
1159 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301160 if (!data->host_cookie)
1161 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1162 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163out:
1164 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001165}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166#else
1167static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1168 struct mmc_data *data) { return 0; }
1169#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001170
1171static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001172msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1173 struct mmc_command *cmd, u32 *c)
1174{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301175 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 cmd->opcode, cmd->arg, cmd->flags);
1177
San Mehat56a8b5b2009-11-21 12:29:46 -08001178 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1179
1180 if (cmd->flags & MMC_RSP_PRESENT) {
1181 if (cmd->flags & MMC_RSP_136)
1182 *c |= MCI_CPSM_LONGRSP;
1183 *c |= MCI_CPSM_RESPONSE;
1184 }
1185
1186 if (/*interrupt*/0)
1187 *c |= MCI_CPSM_INTERRUPT;
1188
Asutosh Das05049132012-05-09 12:38:15 +05301189 /* DAT_CMD bit should be set for all ADTC */
1190 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001191 *c |= MCI_CSPM_DATCMD;
1192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301194 if (host->tuning_needed &&
1195 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1196
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301197 /*
1198 * For open ended block read operation (without CMD23),
1199 * AUTO_CMD19 bit should be set while sending the READ command.
1200 * For close ended block read operation (with CMD23),
1201 * AUTO_CMD19 bit should be set while sending CMD23.
1202 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301203 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1204 host->curr.mrq->cmd->opcode ==
1205 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301206 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301207 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1208 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301209 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1210 *c |= MCI_CSPM_AUTO_CMD19;
1211 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 }
1213
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301214 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1215 writel_relaxed((readl_relaxed(host->base +
1216 MCI_DLL_CONFIG) | MCI_CDR_EN),
1217 host->base + MCI_DLL_CONFIG);
1218 else
1219 /* Clear CDR_EN bit for non read operations */
1220 writel_relaxed((readl_relaxed(host->base +
1221 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1222 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301223
Subhash Jadavani824c4ad2012-12-19 19:05:02 +05301224 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301225 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301227 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001228 if (cmd == cmd->mrq->stop)
1229 *c |= MCI_CSPM_MCIABORT;
1230
San Mehat56a8b5b2009-11-21 12:29:46 -08001231 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301232 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001234 }
1235 host->curr.cmd = cmd;
1236}
1237
1238static void
1239msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1240 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001241{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301242 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001243 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001245 unsigned int pio_irqmask = 0;
1246
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301247 BUG_ON(!data->sg);
1248 BUG_ON(!data->sg_len);
1249
San Mehat9d2bd732009-09-22 16:44:22 -07001250 host->curr.data = data;
1251 host->curr.xfer_size = data->blksz * data->blocks;
1252 host->curr.xfer_remain = host->curr.xfer_size;
1253 host->curr.data_xfered = 0;
1254 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301255 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001256
San Mehat9d2bd732009-09-22 16:44:22 -07001257 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1258
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301259 if (host->curr.wait_for_auto_prog_done)
1260 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001261
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301262 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301263 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301265 } else if (is_sps_mode(host)) {
Krishna Kondad337ddd2012-08-19 11:16:39 -07001266 if (!msmsdcc_sps_start_xfer(host, data)) {
1267 /* Now kick start DML transfer */
1268 mb();
1269 msmsdcc_dml_start_xfer(host, data);
1270 datactrl |= MCI_DPSM_DMAENABLE;
1271 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 }
1273 }
1274 }
1275
1276 /* Is data transfer in PIO mode required? */
1277 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001278 if (data->flags & MMC_DATA_READ) {
1279 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1280 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1281 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1282 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1284 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001285
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001286 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001287 }
1288
1289 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301290 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301291 else if (host->curr.use_wr_data_pend)
1292 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001293
San Mehat56a8b5b2009-11-21 12:29:46 -08001294 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001296 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301297 WARN(!timeout,
1298 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1299 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001300
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301301 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 /* Use ADM (Application Data Mover) HW for Data transfer */
1303 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001304 host->cmd_timeout = timeout;
1305 host->cmd_pio_irqmask = pio_irqmask;
1306 host->cmd_datactrl = datactrl;
1307 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1310 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001311 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001312
1313 if (cmd) {
1314 msmsdcc_start_command_deferred(host, cmd, &c);
1315 host->cmd_c = c;
1316 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1318 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1319 host->base + MMCIMASK0);
1320 mb();
1321 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001322 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1329 (~(MCI_IRQ_PIO))) | pio_irqmask,
1330 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001332
1333 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301334 /* Delay between data/command */
1335 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001336 /* Daisy-chain the command if requested */
1337 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301338 } else {
1339 /*
1340 * We don't need delay after writing to DATA_CTRL
1341 * register if we are not writing to CMD register
1342 * immediately after this. As we already have delay
1343 * before sending the command, we just need mb() here.
1344 */
1345 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001346 }
San Mehat9d2bd732009-09-22 16:44:22 -07001347 }
1348}
1349
1350static void
1351msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1352{
San Mehat56a8b5b2009-11-21 12:29:46 -08001353 msmsdcc_start_command_deferred(host, cmd, &c);
1354 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001355}
1356
1357static void
1358msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1359 unsigned int status)
1360{
1361 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301363 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1364 || data->mrq->cmd->opcode ==
1365 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 pr_err("%s: Data CRC error\n",
1367 mmc_hostname(host->mmc));
1368 pr_err("%s: opcode 0x%.8x\n", __func__,
1369 data->mrq->cmd->opcode);
1370 pr_err("%s: blksz %d, blocks %d\n", __func__,
1371 data->blksz, data->blocks);
1372 data->error = -EILSEQ;
1373 }
San Mehat9d2bd732009-09-22 16:44:22 -07001374 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 /* CRC is optional for the bus test commands, not all
1376 * cards respond back with CRC. However controller
1377 * waits for the CRC and times out. Hence ignore the
1378 * data timeouts during the Bustest.
1379 */
1380 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1381 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301382 pr_err("%s: CMD%d: Data timeout\n",
1383 mmc_hostname(host->mmc),
1384 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301386 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 }
San Mehat9d2bd732009-09-22 16:44:22 -07001388 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001389 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001390 data->error = -EIO;
1391 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001392 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001393 data->error = -EIO;
1394 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001395 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001397 data->error = -EIO;
1398 }
San Mehat9d2bd732009-09-22 16:44:22 -07001399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001401 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 host->dummy_52_needed = 0;
1403}
San Mehat9d2bd732009-09-22 16:44:22 -07001404
1405static int
1406msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1407{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001409 uint32_t *ptr = (uint32_t *) buffer;
1410 int count = 0;
1411
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301412 if (remain % 4)
1413 remain = ((remain >> 2) + 1) << 2;
1414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1416
1417 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001418 ptr++;
1419 count += sizeof(uint32_t);
1420
1421 remain -= sizeof(uint32_t);
1422 if (remain == 0)
1423 break;
1424 }
1425 return count;
1426}
1427
1428static int
1429msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001431{
1432 void __iomem *base = host->base;
1433 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 while (readl_relaxed(base + MMCISTATUS) &
1437 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1438 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001439
San Mehat9d2bd732009-09-22 16:44:22 -07001440 count = min(remain, maxcnt);
1441
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301442 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1443 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001444 ptr += count;
1445 remain -= count;
1446
1447 if (remain == 0)
1448 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 }
1450 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001451
1452 return ptr - buffer;
1453}
1454
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001455/*
1456 * Copy up to a word (4 bytes) between a scatterlist
1457 * and a temporary bounce buffer when the word lies across
1458 * two pages. The temporary buffer can then be read to/
1459 * written from the FIFO once.
1460 */
1461static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001462{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001463 struct msmsdcc_pio_data *pio = &host->pio;
1464 unsigned int bytes_avail;
1465
1466 if (host->curr.data->flags & MMC_DATA_READ)
1467 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1468 pio->bounce_buf_len);
1469 else
1470 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1471 pio->bounce_buf_len);
1472
1473 while (pio->bounce_buf_len != 4) {
1474 if (!sg_miter_next(&pio->sg_miter))
1475 break;
1476 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1477 4 - pio->bounce_buf_len);
1478 if (host->curr.data->flags & MMC_DATA_READ)
1479 memcpy(pio->sg_miter.addr,
1480 &pio->bounce_buf[pio->bounce_buf_len],
1481 bytes_avail);
1482 else
1483 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1484 pio->sg_miter.addr, bytes_avail);
1485
1486 pio->sg_miter.consumed = bytes_avail;
1487 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001488 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001489}
1490
1491/*
1492 * Use sg_miter_next to return as many 4-byte aligned
1493 * chunks as possible, using a temporary 4 byte buffer
1494 * for alignment if necessary
1495 */
1496static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1497{
1498 struct msmsdcc_pio_data *pio = &host->pio;
1499 unsigned int length, rlength;
1500 char *buffer;
1501
1502 if (!sg_miter_next(&pio->sg_miter))
1503 return 0;
1504
1505 buffer = pio->sg_miter.addr;
1506 length = pio->sg_miter.length;
1507
1508 if (length < host->curr.xfer_remain) {
1509 rlength = round_down(length, 4);
1510 if (rlength) {
1511 /*
1512 * We have a 4-byte aligned chunk.
1513 * The rounding will be reflected by
1514 * a call to msmsdcc_sg_consumed
1515 */
1516 length = rlength;
1517 goto sg_next_end;
1518 }
1519 /*
1520 * We have a length less than 4 bytes. Check to
1521 * see if more buffer is available, and combine
1522 * to make 4 bytes if possible.
1523 */
1524 pio->bounce_buf_len = length;
1525 memset(pio->bounce_buf, 0, 4);
1526
1527 /*
1528 * On a read, get 4 bytes from FIFO, and distribute
1529 * (4-bouce_buf_len) bytes into consecutive
1530 * sgl buffers when msmsdcc_sg_consumed is called
1531 */
1532 if (host->curr.data->flags & MMC_DATA_READ) {
1533 buffer = pio->bounce_buf;
1534 length = 4;
1535 goto sg_next_end;
1536 } else {
1537 _msmsdcc_sg_consume_word(host);
1538 buffer = pio->bounce_buf;
1539 length = pio->bounce_buf_len;
1540 }
1541 }
1542
1543sg_next_end:
1544 *buf = buffer;
1545 *len = length;
1546 return 1;
1547}
1548
1549/*
1550 * Update sg_miter.consumed based on how many bytes were
1551 * consumed. If the bounce buffer was used to read from FIFO,
1552 * redistribute into sgls.
1553 */
1554static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1555 unsigned int length)
1556{
1557 struct msmsdcc_pio_data *pio = &host->pio;
1558
1559 if (host->curr.data->flags & MMC_DATA_READ) {
1560 if (length > pio->sg_miter.consumed)
1561 /*
1562 * consumed 4 bytes, but sgl
1563 * describes < 4 bytes
1564 */
1565 _msmsdcc_sg_consume_word(host);
1566 else
1567 pio->sg_miter.consumed = length;
1568 } else
1569 if (length < pio->sg_miter.consumed)
1570 pio->sg_miter.consumed = length;
1571}
1572
1573static void msmsdcc_sg_start(struct msmsdcc_host *host)
1574{
1575 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1576
1577 host->pio.bounce_buf_len = 0;
1578
1579 if (host->curr.data->flags & MMC_DATA_READ)
1580 sg_miter_flags |= SG_MITER_TO_SG;
1581 else
1582 sg_miter_flags |= SG_MITER_FROM_SG;
1583
1584 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1585 host->curr.data->sg_len, sg_miter_flags);
1586}
1587
1588static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1589{
1590 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001591}
1592
San Mehat1cd22962010-02-03 12:59:29 -08001593static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001594msmsdcc_pio_irq(int irq, void *dev_id)
1595{
1596 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001598 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001599 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001600 unsigned int remain;
1601 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001602
Murali Palnati36448a42011-09-02 15:06:18 +05301603 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301608 (MCI_IRQ_PIO)) == 0) {
1609 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301610 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301611 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001612#if IRQ_DEBUG
1613 msmsdcc_print_status(host, "irq1-r", status);
1614#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001615 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001616
1617 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001618 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1621 | MCI_RXDATAAVLBL)))
1622 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001623
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001624 if (!msmsdcc_sg_next(host, &buffer, &remain))
1625 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001626
San Mehat9d2bd732009-09-22 16:44:22 -07001627 len = 0;
1628 if (status & MCI_RXACTIVE)
1629 len = msmsdcc_pio_read(host, buffer, remain);
1630 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001632
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301633 /* len might have aligned to 32bits above */
1634 if (len > remain)
1635 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001636
San Mehat9d2bd732009-09-22 16:44:22 -07001637 host->curr.xfer_remain -= len;
1638 host->curr.data_xfered += len;
1639 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001640 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 if (remain) /* Done with this page? */
1643 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001646 } while (1);
1647
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001648 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001649 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1652 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1653 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1654 host->base + MMCIMASK0);
1655 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301656 /*
1657 * back to back write to MASK0 register don't need
1658 * synchronization delay.
1659 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1661 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1662 }
1663 mb();
1664 } else if (!host->curr.xfer_remain) {
1665 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1666 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1667 mb();
1668 }
San Mehat9d2bd732009-09-22 16:44:22 -07001669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001671
1672 return IRQ_HANDLED;
1673}
1674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675static void
1676msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1677
1678static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1679 struct mmc_data *data)
1680{
1681 u32 loop_cnt = 0;
1682
1683 /*
1684 * For read commands with data less than fifo size, it is possible to
1685 * get DATAEND first and RXDATA_AVAIL might be set later because of
1686 * synchronization delay through the asynchronous RX FIFO. Thus, for
1687 * such cases, even after DATAEND interrupt is received software
1688 * should poll for RXDATA_AVAIL until the requested data is read out
1689 * of FIFO. This change is needed to get around this abnormal but
1690 * sometimes expected behavior of SDCC3 controller.
1691 *
1692 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1693 * after the data is loaded into RX FIFO. This would amount to less
1694 * than a microsecond and thus looping for 1000 times is good enough
1695 * for that delay.
1696 */
1697 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1698 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1699 spin_unlock(&host->lock);
1700 msmsdcc_pio_irq(1, host);
1701 spin_lock(&host->lock);
1702 }
1703 }
1704 if (loop_cnt == 1000) {
1705 pr_info("%s: Timed out while polling for Rx Data\n",
1706 mmc_hostname(host->mmc));
1707 data->error = -ETIMEDOUT;
1708 msmsdcc_reset_and_restore(host);
1709 }
1710}
1711
San Mehat9d2bd732009-09-22 16:44:22 -07001712static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1713{
1714 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001715
1716 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301717 if (mmc_resp_type(cmd))
1718 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1719 /*
1720 * Read rest of the response registers only if
1721 * long response is expected for this command
1722 */
1723 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1724 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1725 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1726 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1727 }
San Mehat9d2bd732009-09-22 16:44:22 -07001728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301730 pr_debug("%s: CMD%d: Command timeout\n",
1731 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001732 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301734 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301735 pr_err("%s: CMD%d: Command CRC error\n",
1736 mmc_hostname(host->mmc), cmd->opcode);
1737 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001738 cmd->error = -EILSEQ;
1739 }
1740
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301741 if (!cmd->error) {
1742 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1743 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1744 mod_timer(&host->req_tout_timer, (jiffies +
1745 msecs_to_jiffies(host->curr.req_tout_ms)));
1746 }
1747 }
1748
San Mehat9d2bd732009-09-22 16:44:22 -07001749 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301751 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001752 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301754 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 /* Stop current SPS transfer */
1756 msmsdcc_sps_exit_curr_xfer(host);
1757 }
San Mehat9d2bd732009-09-22 16:44:22 -07001758 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301759 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001760 msmsdcc_stop_data(host);
1761 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301762 } else { /* host->data == NULL */
1763 if (!cmd->error && host->prog_enable) {
1764 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301766 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301768 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301769 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301770 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301771 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001772 if (host->dummy_52_needed)
1773 host->dummy_52_needed = 0;
1774 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301776 msmsdcc_request_end(host, cmd->mrq);
1777 }
1778 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301779 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301780 if (cmd == host->curr.mrq->sbc)
1781 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1782 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1783 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301784 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001785 }
1786}
1787
San Mehat9d2bd732009-09-22 16:44:22 -07001788static irqreturn_t
1789msmsdcc_irq(int irq, void *dev_id)
1790{
1791 struct msmsdcc_host *host = dev_id;
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301792 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001793 u32 status;
1794 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001796
1797 spin_lock(&host->lock);
1798
1799 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 struct mmc_command *cmd;
1801 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 if (timer) {
1804 timer = 0;
1805 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001806 }
San Mehat9d2bd732009-09-22 16:44:22 -07001807
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301808 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 pr_debug("%s: %s: SDIO async irq received\n",
1810 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301811
1812 /*
1813 * Only async interrupt can come when clocks are off,
1814 * disable further interrupts and enable them when
1815 * clocks are on.
1816 */
1817 if (!host->sdcc_irq_disabled) {
1818 disable_irq_nosync(irq);
1819 host->sdcc_irq_disabled = 1;
1820 }
1821
1822 /*
1823 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1824 * will take care of signaling sdio irq during
1825 * mmc_sdio_resume().
1826 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301827 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301828 /*
1829 * This is a wakeup interrupt so hold wakelock
1830 * until SDCC resume is handled.
1831 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301833 } else {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301834 if (!mmc->card || !mmc_card_sdio(mmc->card)) {
1835 WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1836 mmc_hostname(mmc));
1837 ret = 1;
1838 break;
1839 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301840 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301841 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301842 spin_lock(&host->lock);
1843 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301844 ret = 1;
1845 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 }
1847
1848 status = readl_relaxed(host->base + MMCISTATUS);
1849
1850 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1851 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001852 break;
1853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854#if IRQ_DEBUG
1855 msmsdcc_print_status(host, "irq0-r", status);
1856#endif
1857 status &= readl_relaxed(host->base + MMCIMASK0);
1858 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301859 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301860 if (host->clk_rate <=
1861 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301862 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863#if IRQ_DEBUG
1864 msmsdcc_print_status(host, "irq0-p", status);
1865#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 if (status & MCI_SDIOINTROPE) {
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05301868 if (!mmc->card || mmc_card_sdio(mmc->card)) {
1869 WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
1870 mmc_hostname(mmc));
1871 ret = 1;
1872 break;
1873 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874 if (host->sdcc_suspending)
1875 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301876 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301878 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001879 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001880 data = host->curr.data;
1881
1882 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1884 MCI_CMDTIMEOUT)) {
1885 if (status & MCI_CMDTIMEOUT)
1886 pr_debug("%s: dummy CMD52 timeout\n",
1887 mmc_hostname(host->mmc));
1888 if (status & MCI_CMDCRCFAIL)
1889 pr_debug("%s: dummy CMD52 CRC failed\n",
1890 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001891 host->dummy_52_sent = 0;
1892 host->dummy_52_needed = 0;
1893 if (data) {
1894 msmsdcc_stop_data(host);
1895 msmsdcc_request_end(host, data->mrq);
1896 }
1897 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 spin_unlock(&host->lock);
1899 return IRQ_HANDLED;
1900 }
1901 break;
1902 }
1903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904 /*
1905 * Check for proper command response
1906 */
1907 cmd = host->curr.cmd;
1908 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1909 MCI_CMDTIMEOUT | MCI_PROGDONE |
1910 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1911 msmsdcc_do_cmdirq(host, status);
1912 }
1913
Sathish Ambley081d7842011-11-29 11:19:41 -08001914 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 /* Check for data errors */
1916 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1917 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1918 msmsdcc_data_err(host, data, status);
1919 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301920 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001921 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301922 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923 /* Stop current SPS transfer */
1924 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301925 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 msmsdcc_reset_and_restore(host);
1927 if (host->curr.data)
1928 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301929 if (!data->stop || (host->curr.mrq->sbc
1930 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 timer |=
1932 msmsdcc_request_end(host,
1933 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301934 else if ((host->curr.mrq->sbc
1935 && data->error) ||
1936 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937 msmsdcc_start_command(host,
1938 data->stop,
1939 0);
1940 timer = 1;
1941 }
1942 }
1943 }
1944
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301945 /* Check for prog done */
1946 if (host->curr.wait_for_auto_prog_done &&
1947 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301948 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 /* Check for data done */
1951 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1952 host->curr.got_dataend = 1;
1953
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301954 if (host->curr.got_dataend &&
1955 (!host->curr.wait_for_auto_prog_done ||
1956 (host->curr.wait_for_auto_prog_done &&
1957 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 /*
1959 * If DMA is still in progress, we complete
1960 * via the completion handler
1961 */
1962 if (!host->dma.busy && !host->sps.busy) {
1963 /*
1964 * There appears to be an issue in the
1965 * controller where if you request a
1966 * small block transfer (< fifo size),
1967 * you may get your DATAEND/DATABLKEND
1968 * irq without the PIO data irq.
1969 *
1970 * Check to see if theres still data
1971 * to be read, and simulate a PIO irq.
1972 */
1973 if (data->flags & MMC_DATA_READ)
1974 msmsdcc_wait_for_rxdata(host,
1975 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976 if (!data->error) {
1977 host->curr.data_xfered =
1978 host->curr.xfer_size;
1979 host->curr.xfer_remain -=
1980 host->curr.xfer_size;
1981 }
1982
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001983 if (!host->dummy_52_needed) {
1984 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301985 if (!data->stop ||
1986 (host->curr.mrq->sbc
1987 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001988 msmsdcc_request_end(
1989 host,
1990 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301991 else if ((host->curr.mrq->sbc
1992 && data->error) ||
1993 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001994 msmsdcc_start_command(
1995 host,
1996 data->stop, 0);
1997 timer = 1;
1998 }
1999 } else {
2000 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002002 &dummy52cmd,
2003 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 }
2005 }
2006 }
2007 }
2008
San Mehat9d2bd732009-09-22 16:44:22 -07002009 ret = 1;
2010 } while (status);
2011
2012 spin_unlock(&host->lock);
2013
San Mehat9d2bd732009-09-22 16:44:22 -07002014 return IRQ_RETVAL(ret);
2015}
2016
2017static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302018msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2019 bool is_first_request)
2020{
2021 struct msmsdcc_host *host = mmc_priv(mmc);
2022 struct mmc_data *data = mrq->data;
2023 int rc = 0;
2024
2025 if (unlikely(!data)) {
2026 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2027 __func__);
2028 return;
2029 }
2030 if (unlikely(data->host_cookie)) {
2031 /* Very wrong */
2032 data->host_cookie = 0;
2033 pr_err("%s: %s Request reposted for prepare\n",
2034 mmc_hostname(mmc), __func__);
2035 return;
2036 }
2037
2038 if (!msmsdcc_is_dma_possible(host, data))
2039 return;
2040
2041 rc = msmsdcc_prep_xfer(host, data);
2042 if (unlikely(rc < 0)) {
2043 data->host_cookie = 0;
2044 return;
2045 }
2046
2047 data->host_cookie = 1;
2048}
2049
2050static void
2051msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2052{
2053 struct msmsdcc_host *host = mmc_priv(mmc);
2054 unsigned int dir;
2055 struct mmc_data *data = mrq->data;
2056
2057 if (unlikely(!data)) {
2058 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2059 __func__);
2060 return;
2061 }
2062 if (data->flags & MMC_DATA_READ)
2063 dir = DMA_FROM_DEVICE;
2064 else
2065 dir = DMA_TO_DEVICE;
2066
2067 if (data->host_cookie)
2068 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2069 data->sg_len, dir);
2070
2071 data->host_cookie = 0;
2072}
2073
2074static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2076{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302077 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302079 if ((mrq->data->flags & MMC_DATA_READ) ||
2080 host->curr.use_wr_data_pend)
2081 msmsdcc_start_data(host, mrq->data,
2082 mrq->sbc ? mrq->sbc : mrq->cmd,
2083 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302084 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302085 msmsdcc_start_command(host,
2086 mrq->sbc ? mrq->sbc : mrq->cmd,
2087 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 } else {
2089 msmsdcc_start_command(host, mrq->cmd, 0);
2090 }
2091}
2092
Maya Erez00d7be62013-02-05 13:19:52 +02002093/*
2094 * This function returns true if AUTO_PROG_DONE feature of host is
2095 * applicable for current request, returns "false" otherwise.
2096 *
2097 * NOTE: Caller should call this function only for data write operations.
2098 */
2099static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2100 struct mmc_request *mrq)
2101{
2102 /*
2103 * Auto-prog done will be enabled for following cases:
2104 * mrq->sbc | mrq->stop
2105 * _____________|________________
2106 * True | Don't care
2107 * False | False (CMD24, ACMD25 use case)
2108 */
2109 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2110 return true;
2111
2112 return false;
2113}
2114
2115/*
2116 * This function returns true if controller can wait for prog done
2117 * for current request, returns "false" otherwise.
2118 *
2119 * NOTE: Caller should call this function only for data write operations.
2120 */
2121static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2122 struct mmc_request *mrq)
2123{
2124 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2125 return true;
2126
2127 return false;
2128}
2129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130static void
San Mehat9d2bd732009-09-22 16:44:22 -07002131msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2132{
2133 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302134 unsigned long flags;
Maya Erezb7a086f2012-11-29 00:37:36 +02002135 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 /*
2138 * Get the SDIO AL client out of LPM.
2139 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002140 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 if (host->plat->is_sdio_al_client)
2142 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002143
Maya Erezb7a086f2012-11-29 00:37:36 +02002144 /* check if sps bam needs to be reset */
2145 if (is_sps_mode(host) && host->sps.reset_bam) {
2146 while (retries) {
2147 if (!msmsdcc_bam_dml_reset_and_restore(host))
2148 break;
2149 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2150 mmc_hostname(host->mmc), --retries);
2151 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302152 }
San Mehat9d2bd732009-09-22 16:44:22 -07002153
2154 spin_lock_irqsave(&host->lock, flags);
2155
San Mehat9d2bd732009-09-22 16:44:22 -07002156 if (host->eject) {
2157 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2158 mrq->cmd->error = 0;
2159 mrq->data->bytes_xfered = mrq->data->blksz *
2160 mrq->data->blocks;
2161 } else
2162 mrq->cmd->error = -ENOMEDIUM;
2163
2164 spin_unlock_irqrestore(&host->lock, flags);
2165 mmc_request_done(mmc, mrq);
2166 return;
2167 }
2168
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302169 /*
subhashjf181c292012-05-02 13:07:40 +05302170 * Don't start the request if SDCC is not in proper state to handle it
2171 */
Maya Erezb7a086f2012-11-29 00:37:36 +02002172 if (!host->pwr || !atomic_read(&host->clks_on) ||
2173 host->sdcc_irq_disabled ||
2174 host->sps.reset_bam) {
subhashjf181c292012-05-02 13:07:40 +05302175 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2176 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2177 __func__, mrq->cmd->opcode);
2178 msmsdcc_dump_sdcc_state(host);
2179 mrq->cmd->error = -EIO;
2180 if (mrq->data) {
2181 mrq->data->error = -EIO;
2182 mrq->data->bytes_xfered = 0;
2183 }
2184 spin_unlock_irqrestore(&host->lock, flags);
2185 mmc_request_done(mmc, mrq);
2186 return;
2187 }
2188
2189 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2190 " other request (CMD%d) is in progress\n",
2191 mmc_hostname(host->mmc), __func__,
2192 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2193
2194 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302195 * Set timeout value to 10 secs (or more in case of buggy cards)
2196 */
2197 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302198 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302199 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302200 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302201 /*
2202 * Kick the software request timeout timer here with the timeout
2203 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302204 */
2205 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302206 (jiffies +
2207 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002208
San Mehat9d2bd732009-09-22 16:44:22 -07002209 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302210 if (mrq->sbc) {
2211 mrq->sbc->mrq = mrq;
2212 mrq->sbc->data = mrq->data;
2213 }
2214
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302215 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Maya Erez00d7be62013-02-05 13:19:52 +02002216 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2217 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302218 } else {
2219 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2220 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 host->dummy_52_needed = 1;
2222 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302223
Subhash Jadavanif5277752011-10-12 16:47:52 +05302224 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2225 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2226 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002227 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302228
Subhash Jadavanif5277752011-10-12 16:47:52 +05302229 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302230
San Mehat9d2bd732009-09-22 16:44:22 -07002231 spin_unlock_irqrestore(&host->lock, flags);
2232}
2233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2235 int min_uV, int max_uV)
2236{
2237 int rc = 0;
2238
2239 if (vreg->set_voltage_sup) {
2240 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2241 if (rc) {
2242 pr_err("%s: regulator_set_voltage(%s) failed."
2243 " min_uV=%d, max_uV=%d, rc=%d\n",
2244 __func__, vreg->name, min_uV, max_uV, rc);
2245 }
2246 }
2247
2248 return rc;
2249}
2250
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302251static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2252{
2253 int rc = 0;
2254
2255 rc = regulator_get_voltage(vreg->reg);
2256 if (rc < 0)
2257 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2258 __func__, vreg->name, rc);
2259
2260 return rc;
2261}
2262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2264 int uA_load)
2265{
2266 int rc = 0;
2267
Krishna Kondafea60182011-11-01 16:01:34 -07002268 /* regulators that do not support regulator_set_voltage also
2269 do not support regulator_set_optimum_mode */
2270 if (vreg->set_voltage_sup) {
2271 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2272 if (rc < 0)
2273 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2274 "uA_load=%d) failed. rc=%d\n", __func__,
2275 vreg->name, uA_load, rc);
2276 else
2277 /* regulator_set_optimum_mode() can return non zero
2278 * value even for success case.
2279 */
2280 rc = 0;
2281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282
2283 return rc;
2284}
2285
2286static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2287 struct device *dev)
2288{
2289 int rc = 0;
2290
2291 /* check if regulator is already initialized? */
2292 if (vreg->reg)
2293 goto out;
2294
2295 /* Get the regulator handle */
2296 vreg->reg = regulator_get(dev, vreg->name);
2297 if (IS_ERR(vreg->reg)) {
2298 rc = PTR_ERR(vreg->reg);
2299 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2300 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002301 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002303
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302304 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002305 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302306 /* sanity check */
2307 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2308 pr_err("%s: %s invalid constraints specified\n",
2309 __func__, vreg->name);
2310 rc = -EINVAL;
2311 }
2312 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314out:
2315 return rc;
2316}
2317
2318static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2319{
2320 if (vreg->reg)
2321 regulator_put(vreg->reg);
2322}
2323
2324/* This init function should be called only once for each SDCC slot */
2325static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2326{
2327 int rc = 0;
2328 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302329 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330 struct device *dev = mmc_dev(host->mmc);
2331
2332 curr_slot = host->plat->vreg_data;
2333 if (!curr_slot)
2334 goto out;
2335
2336 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302337 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338
2339 if (is_init) {
2340 /*
2341 * Get the regulator handle from voltage regulator framework
2342 * and then try to set the voltage level for the regulator
2343 */
2344 if (curr_vdd_reg) {
2345 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2346 if (rc)
2347 goto out;
2348 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302349 if (curr_vdd_io_reg) {
2350 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351 if (rc)
2352 goto vdd_reg_deinit;
2353 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002354 rc = msmsdcc_vreg_reset(host);
2355 if (rc)
2356 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2357 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 goto out;
2359 } else {
2360 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302361 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302363vdd_io_reg_deinit:
2364 if (curr_vdd_io_reg)
2365 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366vdd_reg_deinit:
2367 if (curr_vdd_reg)
2368 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2369out:
2370 return rc;
2371}
2372
2373static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2374{
2375 int rc = 0;
2376
Subhash Jadavanicc922692011-08-01 23:05:01 +05302377 /* Put regulator in HPM (high power mode) */
2378 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2379 if (rc < 0)
2380 goto out;
2381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 if (!vreg->is_enabled) {
2383 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302384 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2385 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 if (rc)
2387 goto out;
2388
2389 rc = regulator_enable(vreg->reg);
2390 if (rc) {
2391 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2392 __func__, vreg->name, rc);
2393 goto out;
2394 }
2395 vreg->is_enabled = true;
2396 }
2397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398out:
2399 return rc;
2400}
2401
Krishna Konda3c4142d2012-06-27 11:01:56 -07002402static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403{
2404 int rc = 0;
2405
2406 /* Never disable regulator marked as always_on */
2407 if (vreg->is_enabled && !vreg->always_on) {
2408 rc = regulator_disable(vreg->reg);
2409 if (rc) {
2410 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2411 __func__, vreg->name, rc);
2412 goto out;
2413 }
2414 vreg->is_enabled = false;
2415
2416 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2417 if (rc < 0)
2418 goto out;
2419
2420 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302421 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 if (rc)
2423 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002424 } else if (vreg->is_enabled && vreg->always_on) {
2425 if (!is_init && vreg->lpm_sup) {
2426 /* Put always_on regulator in LPM (low power mode) */
2427 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2428 if (rc < 0)
2429 goto out;
2430 } else if (is_init && vreg->reset_at_init) {
2431 /**
2432 * The regulator might not actually be disabled if it
2433 * is shared and in use by other drivers.
2434 */
2435 rc = regulator_disable(vreg->reg);
2436 if (rc) {
2437 pr_err("%s: regulator_disable(%s) failed at " \
2438 "bootup. rc=%d\n", __func__,
2439 vreg->name, rc);
2440 goto out;
2441 }
2442 vreg->is_enabled = false;
2443 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444 }
2445out:
2446 return rc;
2447}
2448
Krishna Konda3c4142d2012-06-27 11:01:56 -07002449static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2450 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451{
2452 int rc = 0, i;
2453 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302454 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455
2456 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302457 if (!curr_slot) {
2458 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
Subhash Jadavani937c7502012-06-01 15:34:46 +05302462 vreg_table[0] = curr_slot->vdd_data;
2463 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464
2465 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2466 if (vreg_table[i]) {
2467 if (enable)
2468 rc = msmsdcc_vreg_enable(vreg_table[i]);
2469 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002470 rc = msmsdcc_vreg_disable(vreg_table[i],
2471 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 if (rc)
2473 goto out;
2474 }
2475 }
2476out:
2477 return rc;
2478}
2479
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002480/*
2481 * Reset vreg by ensuring it is off during probe. A call
2482 * to enable vreg is needed to balance disable vreg
2483 */
2484static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2485{
2486 int rc;
2487
Krishna Konda3c4142d2012-06-27 11:01:56 -07002488 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002489 if (rc)
2490 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002491 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002492 return rc;
2493}
2494
Subhash Jadavani937c7502012-06-01 15:34:46 +05302495enum vdd_io_level {
2496 /* set vdd_io_data->low_vol_level */
2497 VDD_IO_LOW,
2498 /* set vdd_io_data->high_vol_level */
2499 VDD_IO_HIGH,
2500 /*
2501 * set whatever there in voltage_level (third argument) of
2502 * msmsdcc_set_vdd_io_vol() function.
2503 */
2504 VDD_IO_SET_LEVEL,
2505};
2506
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302507/*
2508 * This function returns the current VDD IO voltage level.
2509 * Returns negative value if it fails to read the voltage level
2510 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2511 * regulator were not defined for host.
2512 */
2513static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2514{
2515 int rc = 0;
2516
2517 if (host->plat->vreg_data) {
2518 struct msm_mmc_reg_data *io_reg =
2519 host->plat->vreg_data->vdd_io_data;
2520
2521 /*
2522 * If vdd_io is not defined, then we can consider that
2523 * IO voltage is same as VDD.
2524 */
2525 if (!io_reg)
2526 io_reg = host->plat->vreg_data->vdd_data;
2527
2528 if (io_reg && io_reg->is_enabled)
2529 rc = msmsdcc_vreg_get_voltage(io_reg);
2530 }
2531
2532 return rc;
2533}
2534
2535/*
2536 * This function updates the IO pad power switch bit in MCI_CLK register
2537 * based on currrent IO pad voltage level.
2538 * NOTE: This function assumes that host lock was not taken by caller.
2539 */
2540static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2541{
2542 int rc = 0;
2543 unsigned long flags;
2544
2545 if (!is_io_pad_pwr_switch(host))
2546 return;
2547
2548 rc = msmsdcc_get_vdd_io_vol(host);
2549
2550 spin_lock_irqsave(&host->lock, flags);
2551 /*
2552 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2553 * the SDCC instances support the dual voltage pads.
2554 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2555 * bit before using the pads in 1.8V mode.
2556 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2557 * IO_PAD_PWR_SWITCH bit is a don't care.
2558 * But we don't have an option to know (by reading some SDCC register)
2559 * that a particular SDCC instance supports dual voltage pads or not,
2560 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2561 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2562 * is anyway ignored.
2563 */
2564 if (rc > 0 && rc < 2700000)
2565 host->io_pad_pwr_switch = 1;
2566 else
2567 host->io_pad_pwr_switch = 0;
2568
2569 if (atomic_read(&host->clks_on)) {
2570 if (host->io_pad_pwr_switch)
2571 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2572 IO_PAD_PWR_SWITCH),
2573 host->base + MMCICLOCK);
2574 else
2575 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2576 ~IO_PAD_PWR_SWITCH),
2577 host->base + MMCICLOCK);
2578 msmsdcc_sync_reg_wr(host);
2579 }
2580 spin_unlock_irqrestore(&host->lock, flags);
2581}
2582
Subhash Jadavani937c7502012-06-01 15:34:46 +05302583static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2584 enum vdd_io_level level,
2585 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586{
2587 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302588 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589
2590 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302591 struct msm_mmc_reg_data *vdd_io_reg =
2592 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593
Subhash Jadavani937c7502012-06-01 15:34:46 +05302594 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2595 switch (level) {
2596 case VDD_IO_LOW:
2597 set_level = vdd_io_reg->low_vol_level;
2598 break;
2599 case VDD_IO_HIGH:
2600 set_level = vdd_io_reg->high_vol_level;
2601 break;
2602 case VDD_IO_SET_LEVEL:
2603 set_level = voltage_level;
2604 break;
2605 default:
2606 pr_err("%s: %s: invalid argument level = %d",
2607 mmc_hostname(host->mmc), __func__,
2608 level);
2609 rc = -EINVAL;
2610 goto out;
2611 }
2612 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2613 set_level, set_level);
2614 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 }
2616
Subhash Jadavani937c7502012-06-01 15:34:46 +05302617out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302618 return rc;
2619}
2620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2622{
2623 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2624 return 1;
2625 return 0;
2626}
2627
Asutosh Dasf5298c32012-04-03 14:51:47 +05302628/*
2629 * Any function calling msmsdcc_setup_clocks must
2630 * acquire clk_mutex. May sleep.
2631 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302632static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302634 int rc = 0;
2635
2636 if (enable && !atomic_read(&host->clks_on)) {
2637 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2638 rc = clk_prepare_enable(host->bus_clk);
2639 if (rc) {
2640 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2641 mmc_hostname(host->mmc), __func__, rc);
2642 goto out;
2643 }
2644 }
2645 if (!IS_ERR(host->pclk)) {
2646 rc = clk_prepare_enable(host->pclk);
2647 if (rc) {
2648 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2649 mmc_hostname(host->mmc), __func__, rc);
2650 goto disable_bus;
2651 }
2652 }
2653 rc = clk_prepare_enable(host->clk);
2654 if (rc) {
2655 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2656 mmc_hostname(host->mmc), __func__, rc);
2657 goto disable_pclk;
2658 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302659 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302660 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302661 atomic_set(&host->clks_on, 1);
2662 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302663 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302664 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302665 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002666 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302667 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302668 if (!IS_ERR_OR_NULL(host->bus_clk))
2669 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302670 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002671 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302672 goto out;
2673
2674disable_pclk:
2675 if (!IS_ERR_OR_NULL(host->pclk))
2676 clk_disable_unprepare(host->pclk);
2677disable_bus:
2678 if (!IS_ERR_OR_NULL(host->bus_clk))
2679 clk_disable_unprepare(host->bus_clk);
2680out:
2681 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002682}
2683
2684static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2685 unsigned int req_clk)
2686{
2687 unsigned int sel_clk = -1;
2688
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302689 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2690 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2691 goto out;
2692 }
2693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2695 unsigned char cnt;
2696
2697 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2698 if (host->plat->sup_clk_table[cnt] > req_clk)
2699 break;
2700 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2701 sel_clk = host->plat->sup_clk_table[cnt];
2702 break;
2703 } else
2704 sel_clk = host->plat->sup_clk_table[cnt];
2705 }
2706 } else {
2707 if ((req_clk < host->plat->msmsdcc_fmax) &&
2708 (req_clk > host->plat->msmsdcc_fmid))
2709 sel_clk = host->plat->msmsdcc_fmid;
2710 else
2711 sel_clk = req_clk;
2712 }
2713
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302714out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002715 return sel_clk;
2716}
2717
2718static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2719 struct msmsdcc_host *host)
2720{
2721 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2722 return host->plat->sup_clk_table[0];
2723 else
2724 return host->plat->msmsdcc_fmin;
2725}
2726
2727static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2728 struct msmsdcc_host *host)
2729{
2730 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2731 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2732 else
2733 return host->plat->msmsdcc_fmax;
2734}
2735
2736static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302737{
2738 struct msm_mmc_gpio_data *curr;
2739 int i, rc = 0;
2740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302742 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302743 if (!gpio_is_valid(curr->gpio[i].no)) {
2744 rc = -EINVAL;
2745 pr_err("%s: Invalid gpio = %d\n",
2746 mmc_hostname(host->mmc), curr->gpio[i].no);
2747 goto free_gpios;
2748 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302749 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750 if (curr->gpio[i].is_always_on &&
2751 curr->gpio[i].is_enabled)
2752 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302753 rc = gpio_request(curr->gpio[i].no,
2754 curr->gpio[i].name);
2755 if (rc) {
2756 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2757 mmc_hostname(host->mmc),
2758 curr->gpio[i].no,
2759 curr->gpio[i].name, rc);
2760 goto free_gpios;
2761 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002762 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302763 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 if (curr->gpio[i].is_always_on)
2765 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302766 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302768 }
2769 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302771
2772free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302773 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302774 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002775 curr->gpio[i].is_enabled = false;
2776 }
2777out:
2778 return rc;
2779}
2780
2781static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2782{
2783 struct msm_mmc_pad_data *curr;
2784 int i;
2785
2786 curr = host->plat->pin_data->pad_data;
2787 for (i = 0; i < curr->drv->size; i++) {
2788 if (enable)
2789 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2790 curr->drv->on[i].val);
2791 else
2792 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2793 curr->drv->off[i].val);
2794 }
2795
2796 for (i = 0; i < curr->pull->size; i++) {
2797 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002798 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 curr->pull->on[i].val);
2800 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002801 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002802 curr->pull->off[i].val);
2803 }
2804
2805 return 0;
2806}
2807
2808static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2809{
2810 int rc = 0;
2811
2812 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2813 return 0;
2814
2815 if (host->plat->pin_data->is_gpio)
2816 rc = msmsdcc_setup_gpio(host, enable);
2817 else
2818 rc = msmsdcc_setup_pad(host, enable);
2819
2820 if (!rc)
2821 host->plat->pin_data->cfg_sts = enable;
2822
2823 return rc;
2824}
2825
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302826static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2827 unsigned mode)
2828{
2829 int ret = 0;
2830 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2831
2832 if (!pin)
2833 return 0;
2834
2835 switch (mode) {
2836 case SDC_DAT1_DISABLE:
2837 ret = msm_mpm_enable_pin(pin, 0);
2838 break;
2839 case SDC_DAT1_ENABLE:
2840 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2841 ret = msm_mpm_enable_pin(pin, 1);
2842 break;
2843 case SDC_DAT1_ENWAKE:
2844 ret = msm_mpm_set_pin_wake(pin, 1);
2845 break;
2846 case SDC_DAT1_DISWAKE:
2847 ret = msm_mpm_set_pin_wake(pin, 0);
2848 break;
2849 default:
2850 ret = -EINVAL;
2851 break;
2852 }
2853
2854 return ret;
2855}
2856
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302857static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2858{
2859 u32 pwr = 0;
2860 int ret = 0;
2861 struct mmc_host *mmc = host->mmc;
2862
2863 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2864 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2865 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002866 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302867
2868 if (ret) {
2869 pr_err("%s: Failed to setup voltage regulators\n",
2870 mmc_hostname(host->mmc));
2871 goto out;
2872 }
2873
2874 switch (ios->power_mode) {
2875 case MMC_POWER_OFF:
2876 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302877 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302878 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302879 * If VDD IO rail is always on, set low voltage for VDD
2880 * IO rail when slot is not in use (like when card is not
2881 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302882 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302883 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302884 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302885 msmsdcc_setup_pins(host, false);
Pratibhasagar Vbe4e3132012-09-20 19:46:11 +05302886 /*
2887 * Reset the mask to prevent hitting any pending interrupts
2888 * after powering up the card again.
2889 */
2890 if (atomic_read(&host->clks_on)) {
2891 writel_relaxed(0, host->base + MMCIMASK0);
2892 mb();
2893 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302894 break;
2895 case MMC_POWER_UP:
2896 /* writing PWR_UP bit is redundant */
2897 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302898 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302899
Subhash Jadavani937c7502012-06-01 15:34:46 +05302900 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05302901 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302902 msmsdcc_setup_pins(host, true);
2903 break;
2904 case MMC_POWER_ON:
2905 pwr = MCI_PWR_ON;
2906 break;
2907 }
2908
2909out:
2910 return pwr;
2911}
2912
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2914{
2915 unsigned int wakeup_irq;
2916
2917 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2918 host->plat->sdiowakeup_irq :
2919 host->core_irqres->start;
2920
2921 if (!host->irq_wake_enabled) {
2922 enable_irq_wake(wakeup_irq);
2923 host->irq_wake_enabled = true;
2924 }
2925}
2926
2927static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2928{
2929 unsigned int wakeup_irq;
2930
2931 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2932 host->plat->sdiowakeup_irq :
2933 host->core_irqres->start;
2934
2935 if (host->irq_wake_enabled) {
2936 disable_irq_wake(wakeup_irq);
2937 host->irq_wake_enabled = false;
2938 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302939}
2940
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302941/* Returns required bandwidth in Bytes per Sec */
2942static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2943 struct mmc_ios *ios)
2944{
2945 unsigned int bw;
2946
2947 bw = host->clk_rate;
2948 /*
2949 * For DDR mode, SDCC controller clock will be at
2950 * the double rate than the actual clock that goes to card.
2951 */
2952 if (ios->bus_width == MMC_BUS_WIDTH_4)
2953 bw /= 2;
2954 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2955 bw /= 8;
2956
2957 return bw;
2958}
2959
2960static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2961 unsigned int bw)
2962{
2963 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2964 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2965 int i;
2966
2967 if (host->msm_bus_vote.is_max_bw_needed && bw)
2968 return host->msm_bus_vote.max_bw_vote;
2969
2970 for (i = 0; i < size; i++) {
2971 if (bw <= table[i])
2972 break;
2973 }
2974
2975 if (i && (i == size))
2976 i--;
2977
2978 return i;
2979}
2980
2981static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2982{
2983 int rc = 0;
2984 struct msm_bus_scale_pdata *use_cases;
2985
2986 if (host->plat->msm_bus_voting_data &&
2987 host->plat->msm_bus_voting_data->use_cases &&
2988 host->plat->msm_bus_voting_data->bw_vecs &&
2989 host->plat->msm_bus_voting_data->bw_vecs_size) {
2990 use_cases = host->plat->msm_bus_voting_data->use_cases;
2991 host->msm_bus_vote.client_handle =
2992 msm_bus_scale_register_client(use_cases);
2993 } else {
2994 return 0;
2995 }
2996
2997 if (!host->msm_bus_vote.client_handle) {
2998 pr_err("%s: msm_bus_scale_register_client() failed\n",
2999 mmc_hostname(host->mmc));
3000 rc = -EFAULT;
3001 } else {
3002 /* cache the vote index for minimum and maximum bandwidth */
3003 host->msm_bus_vote.min_bw_vote =
3004 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3005 host->msm_bus_vote.max_bw_vote =
3006 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3007 }
3008
3009 return rc;
3010}
3011
3012static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3013{
3014 if (host->msm_bus_vote.client_handle)
3015 msm_bus_scale_unregister_client(
3016 host->msm_bus_vote.client_handle);
3017}
3018
3019/*
3020 * This function must be called with host lock acquired.
3021 * Caller of this function should also ensure that msm bus client
3022 * handle is not null.
3023 */
3024static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3025 int vote,
3026 unsigned long flags)
3027{
3028 int rc = 0;
3029
3030 if (vote != host->msm_bus_vote.curr_vote) {
3031 spin_unlock_irqrestore(&host->lock, flags);
3032 rc = msm_bus_scale_client_update_request(
3033 host->msm_bus_vote.client_handle, vote);
3034 if (rc)
3035 pr_err("%s: msm_bus_scale_client_update_request() failed."
3036 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3037 mmc_hostname(host->mmc),
3038 host->msm_bus_vote.client_handle, vote, rc);
3039 spin_lock_irqsave(&host->lock, flags);
3040 if (!rc)
3041 host->msm_bus_vote.curr_vote = vote;
3042 }
3043
3044 return rc;
3045}
3046
3047/*
3048 * Internal work. Work to set 0 bandwidth for msm bus.
3049 */
3050static void msmsdcc_msm_bus_work(struct work_struct *work)
3051{
3052 struct msmsdcc_host *host = container_of(work,
3053 struct msmsdcc_host,
3054 msm_bus_vote.vote_work.work);
3055 unsigned long flags;
3056
3057 if (!host->msm_bus_vote.client_handle)
3058 return;
3059
3060 spin_lock_irqsave(&host->lock, flags);
3061 /* don't vote for 0 bandwidth if any request is in progress */
3062 if (!host->curr.mrq)
3063 msmsdcc_msm_bus_set_vote(host,
3064 host->msm_bus_vote.min_bw_vote, flags);
3065 else
3066 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3067 " bus voting to 0 bandwidth\n",
3068 mmc_hostname(host->mmc), __func__);
3069 spin_unlock_irqrestore(&host->lock, flags);
3070}
3071
3072/*
3073 * This function cancels any scheduled delayed work
3074 * and sets the bus vote based on ios argument.
3075 * If "ios" argument is NULL, bandwidth required is 0 else
3076 * calculate the bandwidth based on ios parameters.
3077 */
3078static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3079 struct msmsdcc_host *host,
3080 struct mmc_ios *ios)
3081{
3082 unsigned long flags;
3083 unsigned int bw;
3084 int vote;
3085
3086 if (!host->msm_bus_vote.client_handle)
3087 return;
3088
3089 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3090
3091 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3092 spin_lock_irqsave(&host->lock, flags);
3093 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3094 msmsdcc_msm_bus_set_vote(host, vote, flags);
3095 spin_unlock_irqrestore(&host->lock, flags);
3096}
3097
3098/* This function queues a work which will set the bandwidth requiement to 0 */
3099static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3100{
3101 unsigned long flags;
3102
3103 if (!host->msm_bus_vote.client_handle)
3104 return;
3105
3106 spin_lock_irqsave(&host->lock, flags);
3107 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3108 queue_delayed_work(system_nrt_wq,
3109 &host->msm_bus_vote.vote_work,
3110 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3111 spin_unlock_irqrestore(&host->lock, flags);
3112}
3113
San Mehat9d2bd732009-09-22 16:44:22 -07003114static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303115msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3116{
3117 struct mmc_host *mmc = host->mmc;
3118
3119 /*
3120 * SDIO_AL clients has different mechanism of handling LPM through
3121 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3122 * part of that. Here, we are interested only in clients like WLAN.
3123 */
3124 if (!(mmc->card && mmc_card_sdio(mmc->card))
3125 || host->plat->is_sdio_al_client)
3126 goto out;
3127
3128 if (!host->sdcc_suspended) {
3129 /*
3130 * When MSM is not in power collapse and we
3131 * are disabling clocks, enable bit 22 in MASK0
3132 * to handle asynchronous SDIO interrupts.
3133 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303134 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303135 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303136 mb();
3137 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303138 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303139 msmsdcc_sync_reg_wr(host);
3140 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303141 goto out;
3142 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3143 /*
3144 * Wakeup MSM only if SDIO function drivers set
3145 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3146 */
3147 goto out;
3148 }
3149
3150 if (enable_wakeup_irq) {
3151 if (!host->plat->sdiowakeup_irq) {
3152 /*
3153 * When there is no gpio line that can be configured
3154 * as wakeup interrupt handle it by configuring
3155 * asynchronous sdio interrupts and DAT1 line.
3156 */
3157 writel_relaxed(MCI_SDIOINTMASK,
3158 host->base + MMCIMASK0);
3159 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303160 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303161 /* configure sdcc core interrupt as wakeup interrupt */
3162 msmsdcc_enable_irq_wake(host);
3163 } else {
3164 /* Let gpio line handle wakeup interrupt */
3165 writel_relaxed(0, host->base + MMCIMASK0);
3166 mb();
3167 if (host->sdio_wakeupirq_disabled) {
3168 host->sdio_wakeupirq_disabled = 0;
3169 /* configure gpio line as wakeup interrupt */
3170 msmsdcc_enable_irq_wake(host);
3171 enable_irq(host->plat->sdiowakeup_irq);
3172 }
3173 }
3174 } else {
3175 if (!host->plat->sdiowakeup_irq) {
3176 /*
3177 * We may not have cleared bit 22 in the interrupt
3178 * handler as the clocks might be off at that time.
3179 */
3180 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303181 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303182 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303183 msmsdcc_disable_irq_wake(host);
3184 } else if (!host->sdio_wakeupirq_disabled) {
3185 disable_irq_nosync(host->plat->sdiowakeup_irq);
3186 msmsdcc_disable_irq_wake(host);
3187 host->sdio_wakeupirq_disabled = 1;
3188 }
3189 }
3190out:
3191 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003192}
3193
3194static void
3195msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3196{
3197 struct msmsdcc_host *host = mmc_priv(mmc);
3198 u32 clk = 0, pwr = 0;
3199 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003200 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003202
Sahitya Tummala7a892482011-01-18 11:22:49 +05303203
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303204 /*
3205 * Disable SDCC core interrupt until set_ios is completed.
3206 * This avoids any race conditions with interrupt raised
3207 * when turning on/off the clocks. One possible
3208 * scenario is SDIO operational interrupt while the clock
3209 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303210 * host->lock is being released intermittently below.
3211 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303212 */
3213
Asutosh Dasf5298c32012-04-03 14:51:47 +05303214 mutex_lock(&host->clk_mutex);
3215 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003216 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303217 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303218 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303219 host->sdcc_irq_disabled = 1;
3220 }
San Mehatd0719e52009-12-03 10:58:54 -08003221 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003222
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303223 /* Make sure sdcc core irq is synchronized */
3224 synchronize_irq(host->core_irqres->start);
3225
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303226 pwr = msmsdcc_setup_pwr(host, ios);
3227
3228 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003229 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303230 spin_unlock_irqrestore(&host->lock, flags);
3231 rc = msmsdcc_setup_clocks(host, true);
3232 if (rc)
3233 goto out;
3234 spin_lock_irqsave(&host->lock, flags);
3235 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3236 mb();
3237 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 /*
3241 * For DDR50 mode, controller needs clock rate to be
3242 * double than what is required on the SD card CLK pin.
Subhash Jadavani2226d262012-10-09 20:01:56 +05303243 *
3244 * Setting DDR timing mode in controller before setting the
3245 * clock rate will make sure that card don't see the double
3246 * clock rate even for very small duration. Some eMMC
3247 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003248 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303249 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2226d262012-10-09 20:01:56 +05303250 u32 clk;
3251
3252 clk = readl_relaxed(host->base + MMCICLOCK);
3253 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3254 clk |= (3 << 14); /* set DDR timing mode */
3255 writel_relaxed(clk, host->base + MMCICLOCK);
3256 msmsdcc_sync_reg_wr(host);
3257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003258 /*
3259 * Make sure that we don't double the clock if
3260 * doubled clock rate is already set
3261 */
3262 if (!host->ddr_doubled_clk_rate ||
3263 (host->ddr_doubled_clk_rate &&
3264 (host->ddr_doubled_clk_rate != ios->clock))) {
3265 host->ddr_doubled_clk_rate =
3266 msmsdcc_get_sup_clk_rate(
3267 host, (ios->clock * 2));
3268 clock = host->ddr_doubled_clk_rate;
3269 }
3270 } else {
3271 host->ddr_doubled_clk_rate = 0;
3272 }
3273
3274 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303275 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003276 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303277 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303279 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280 mmc_hostname(mmc), clock);
3281 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303282 host->reg_write_delay =
3283 (1 + ((3 * USEC_PER_SEC) /
3284 (host->clk_rate ? host->clk_rate :
3285 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003286 }
3287 /*
3288 * give atleast 2 MCLK cycles delay for clocks
3289 * and SDCC core to stabilize
3290 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303291 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003292 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003293 clk |= MCI_CLK_ENABLE;
3294 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003295 if (ios->bus_width == MMC_BUS_WIDTH_8)
3296 clk |= MCI_CLK_WIDEBUS_8;
3297 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3298 clk |= MCI_CLK_WIDEBUS_4;
3299 else
3300 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302 if (msmsdcc_is_pwrsave(host))
3303 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307 host->tuning_needed = 0;
3308 /*
3309 * Select the controller timing mode according
3310 * to current bus speed mode
3311 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303312 if (host->clk_rate > (100 * 1000 * 1000) &&
3313 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3314 ios->timing == MMC_TIMING_MMC_HS200)) {
3315 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316 clk |= (4 << 14);
3317 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303318 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003319 clk |= (3 << 14);
3320 } else {
3321 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003322 }
3323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003324 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3325 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003327 if (host->io_pad_pwr_switch)
3328 clk |= IO_PAD_PWR_SWITCH;
3329
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303330 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303331 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303332 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3333 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303334 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303336 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3337 host->pwr = pwr;
3338 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303339 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003340 }
San Mehat9d2bd732009-09-22 16:44:22 -07003341 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003342
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303343 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303344 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303345 spin_unlock_irqrestore(&host->lock, flags);
3346 /*
3347 * May get a wake-up interrupt the instant we disable the
3348 * clocks. This would disable the wake-up interrupt.
3349 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003350 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303351 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303353
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303354 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303355 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303356 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303357
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303358 /* Let interrupts be disabled if the host is powered off */
3359 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3360 enable_irq(host->core_irqres->start);
3361 host->sdcc_irq_disabled = 0;
3362 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003363 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303364out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303365 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003366}
3367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003368int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3369{
3370 struct msmsdcc_host *host = mmc_priv(mmc);
3371 u32 clk;
3372
3373 clk = readl_relaxed(host->base + MMCICLOCK);
3374 pr_debug("Changing to pwr_save=%d", pwrsave);
3375 if (pwrsave && msmsdcc_is_pwrsave(host))
3376 clk |= MCI_CLK_PWRSAVE;
3377 else
3378 clk &= ~MCI_CLK_PWRSAVE;
3379 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303380 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003381
3382 return 0;
3383}
3384
3385static int msmsdcc_get_ro(struct mmc_host *mmc)
3386{
3387 int status = -ENOSYS;
3388 struct msmsdcc_host *host = mmc_priv(mmc);
3389
3390 if (host->plat->wpswitch) {
3391 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303392 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 status = gpio_request(host->plat->wpswitch_gpio,
3394 "SD_WP_Switch");
3395 if (status) {
3396 pr_err("%s: %s: Failed to request GPIO %d\n",
3397 mmc_hostname(mmc), __func__,
3398 host->plat->wpswitch_gpio);
3399 } else {
3400 status = gpio_direction_input(
3401 host->plat->wpswitch_gpio);
3402 if (!status) {
3403 /*
3404 * Wait for atleast 300ms as debounce
3405 * time for GPIO input to stabilize.
3406 */
3407 msleep(300);
3408 status = gpio_get_value_cansleep(
3409 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303410 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 }
3412 gpio_free(host->plat->wpswitch_gpio);
3413 }
3414 }
3415
3416 if (status < 0)
3417 status = -ENOSYS;
3418 pr_debug("%s: Card read-only status %d\n", __func__, status);
3419
3420 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003421}
3422
3423static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3424{
3425 struct msmsdcc_host *host = mmc_priv(mmc);
3426 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303428 /*
3429 * We may come here with clocks turned off in that case don't
3430 * attempt to write into MASK0 register. While turning on the
3431 * clocks mci_irqenable will be written to MASK0 register.
3432 */
San Mehat9d2bd732009-09-22 16:44:22 -07003433
3434 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303437 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303438 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303440 mb();
3441 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 } else {
3443 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303444 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303445 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303447 mb();
3448 }
San Mehat9d2bd732009-09-22 16:44:22 -07003449 }
3450 spin_unlock_irqrestore(&host->lock, flags);
3451}
3452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003453#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303454static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003455{
subhashj245831e2012-04-30 18:46:17 +05303456 struct device *dev = mmc_dev(host->mmc);
3457
Subhash Jadavani1371d192012-08-16 18:46:57 +05303458 pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
3459 mmc_hostname(host->mmc), host->sdcc_suspended,
3460 host->pending_resume, host->sdcc_suspending);
subhashj245831e2012-04-30 18:46:17 +05303461 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3462 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3463 " request_pending=%d, request=%d\n",
3464 mmc_hostname(host->mmc), dev->power.runtime_status,
3465 atomic_read(&dev->power.usage_count),
3466 dev->power.is_suspended, dev->power.disable_depth,
3467 dev->power.runtime_error, dev->power.request_pending,
3468 dev->power.request);
3469}
3470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471static int msmsdcc_enable(struct mmc_host *mmc)
3472{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003473 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003475 struct msmsdcc_host *host = mmc_priv(mmc);
3476
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303477 msmsdcc_pm_qos_update_latency(host, 1);
3478
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003479 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303480 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481
Subhash Jadavani1371d192012-08-16 18:46:57 +05303482 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003483 host->pending_resume = false;
3484 pm_runtime_get_noresume(dev);
3485 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303486 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003487 }
3488
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303489 if (dev->power.runtime_status == RPM_SUSPENDING) {
3490 if (mmc->suspend_task == current) {
3491 pm_runtime_get_noresume(dev);
3492 goto out;
3493 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303494 } else if (dev->power.runtime_status == RPM_RESUMING) {
3495 pm_runtime_get_noresume(dev);
3496 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303497 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303499 rc = pm_runtime_get_sync(dev);
3500
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303501skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303502 if (rc < 0) {
Subhash Jadavani1371d192012-08-16 18:46:57 +05303503 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3504 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303505 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303506 return rc;
3507 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303508out:
3509 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303510 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511}
3512
Steve Mucklef132c6c2012-06-06 18:30:57 -07003513static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514{
3515 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303516 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303518 msmsdcc_pm_qos_update_latency(host, 0);
3519
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303520 if (mmc->card && mmc_card_sdio(mmc->card)) {
3521 rc = 0;
3522 goto out;
3523 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303524
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303525 if (host->plat->disable_runtime_pm)
3526 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527
3528 rc = pm_runtime_put_sync(mmc->parent);
3529
Subhash Jadavani1371d192012-08-16 18:46:57 +05303530 if (rc < 0) {
3531 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3532 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303533 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003534 return rc;
3535 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303536
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303537out:
3538 msmsdcc_msm_bus_queue_work(host);
3539 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003540}
3541#else
subhashj245831e2012-04-30 18:46:17 +05303542static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3543
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303544static int msmsdcc_enable(struct mmc_host *mmc)
3545{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003546 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303547 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303548 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303549
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303550 msmsdcc_pm_qos_update_latency(host, 1);
3551
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303552 if (mmc->card && mmc_card_sdio(mmc->card)) {
3553 rc = 0;
3554 goto out;
3555 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003556
3557 if (host->sdcc_suspended && host->pending_resume) {
3558 host->pending_resume = false;
3559 rc = msmsdcc_runtime_resume(dev);
3560 goto out;
3561 }
3562
Asutosh Dasf5298c32012-04-03 14:51:47 +05303563 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303564 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303565 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303566
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003567out:
3568 if (rc < 0) {
3569 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3570 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303571 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003572 return rc;
3573 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303574 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303575 return 0;
3576}
3577
Steve Mucklef132c6c2012-06-06 18:30:57 -07003578static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303579{
3580 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303581 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303582
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303583 msmsdcc_pm_qos_update_latency(host, 0);
3584
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303585 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303586 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303587
Asutosh Dasf5298c32012-04-03 14:51:47 +05303588 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303589 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303590 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303591
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303592 if (rc) {
3593 msmsdcc_pm_qos_update_latency(host, 1);
3594 return rc;
3595 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303596out:
3597 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303598 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303599}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600#endif
3601
Subhash Jadavani937c7502012-06-01 15:34:46 +05303602static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3603 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604{
3605 struct msmsdcc_host *host = mmc_priv(mmc);
3606 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303607 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608
Subhash Jadavani937c7502012-06-01 15:34:46 +05303609 switch (ios->signal_voltage) {
3610 case MMC_SIGNAL_VOLTAGE_330:
3611 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3612 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303613 if (!rc)
3614 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303615 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303616 case MMC_SIGNAL_VOLTAGE_180:
3617 break;
3618 case MMC_SIGNAL_VOLTAGE_120:
3619 /*
3620 * For eMMC cards, VDD_IO voltage range must be changed
3621 * only if it operates in HS200 SDR 1.2V mode or in
3622 * DDR 1.2V mode.
3623 */
3624 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303625 if (!rc)
3626 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303628 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303630 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631 goto out;
3632 }
San Mehat9d2bd732009-09-22 16:44:22 -07003633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003634 /*
3635 * If we are here means voltage switch from high voltage to
3636 * low voltage is required
3637 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303638 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639
3640 /*
3641 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3642 * register until they become all zeros.
3643 */
3644 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303645 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3647 mmc_hostname(mmc), __func__);
3648 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003649 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650
3651 /* Stop SD CLK output. */
3652 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3653 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303654 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003655 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656
3657 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303658 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3659 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303661 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303662 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664
Subhash Jadavanibf09d802012-08-11 18:11:57 +05303665 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003666
3667 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3668 usleep_range(5000, 5500);
3669
3670 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303671 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003672 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3673 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303674 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003675 spin_unlock_irqrestore(&host->lock, flags);
3676
3677 /*
3678 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3679 * don't become all ones within 1 ms then a Voltage Switch
3680 * sequence has failed and a power cycle to the card is required.
3681 * Otherwise Voltage Switch sequence is completed successfully.
3682 */
3683 usleep_range(1000, 1500);
3684
3685 spin_lock_irqsave(&host->lock, flags);
3686 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3687 != (0xF << 1)) {
3688 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3689 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303690 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691 goto out_unlock;
3692 }
3693
3694out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303695 /* Enable PWRSAVE */
3696 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3697 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303698 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699 spin_unlock_irqrestore(&host->lock, flags);
3700out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303701 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003702}
3703
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303704static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003706 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707
3708 /* Program the MCLK value to MCLK_FREQ bit field */
3709 if (host->clk_rate <= 112000000)
3710 mclk_freq = 0;
3711 else if (host->clk_rate <= 125000000)
3712 mclk_freq = 1;
3713 else if (host->clk_rate <= 137000000)
3714 mclk_freq = 2;
3715 else if (host->clk_rate <= 150000000)
3716 mclk_freq = 3;
3717 else if (host->clk_rate <= 162000000)
3718 mclk_freq = 4;
3719 else if (host->clk_rate <= 175000000)
3720 mclk_freq = 5;
3721 else if (host->clk_rate <= 187000000)
3722 mclk_freq = 6;
3723 else if (host->clk_rate <= 200000000)
3724 mclk_freq = 7;
3725
3726 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3727 & ~(7 << 24)) | (mclk_freq << 24)),
3728 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003729}
3730
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303731/* Initialize the DLL (Programmable Delay Line ) */
3732static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003734 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303735 unsigned long flags;
3736 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303738 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003739 /*
3740 * Make sure that clock is always enabled when DLL
3741 * tuning is in progress. Keeping PWRSAVE ON may
3742 * turn off the clock. So let's disable the PWRSAVE
3743 * here and re-enable it once tuning is completed.
3744 */
3745 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3746 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303747 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303748
3749 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3750 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3751 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3752
3753 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3754 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3755 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3756
3757 msmsdcc_cm_sdc4_dll_set_freq(host);
3758
3759 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3760 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3761 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3762
3763 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3764 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3765 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3766
3767 /* Set DLL_EN bit to 1. */
3768 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3769 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3770
3771 /* Set CK_OUT_EN bit to 1. */
3772 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3773 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3774
3775 wait_cnt = 50;
3776 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3777 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3778 /* max. wait for 50us sec for LOCK bit to be set */
3779 if (--wait_cnt == 0) {
3780 pr_err("%s: %s: DLL failed to LOCK\n",
3781 mmc_hostname(host->mmc), __func__);
3782 rc = -ETIMEDOUT;
3783 goto out;
3784 }
3785 /* wait for 1us before polling again */
3786 udelay(1);
3787 }
3788
3789out:
3790 /* re-enable PWRSAVE */
3791 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3792 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303793 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303794 spin_unlock_irqrestore(&host->lock, flags);
3795
3796 return rc;
3797}
3798
3799static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3800 u8 poll)
3801{
3802 int rc = 0;
3803 u32 wait_cnt = 50;
3804 u8 ck_out_en = 0;
3805
3806 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3807 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3808 MCI_CK_OUT_EN);
3809
3810 while (ck_out_en != poll) {
3811 if (--wait_cnt == 0) {
3812 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3813 mmc_hostname(host->mmc), __func__, poll);
3814 rc = -ETIMEDOUT;
3815 goto out;
3816 }
3817 udelay(1);
3818
3819 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3820 MCI_CK_OUT_EN);
3821 }
3822out:
3823 return rc;
3824}
3825
3826/*
3827 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3828 * calibration sequence. This function should be called before
3829 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3830 * commands (CMD17/CMD18).
3831 *
3832 * This function gets called when host spinlock acquired.
3833 */
3834static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3835{
3836 int rc = 0;
3837 u32 config;
3838
3839 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3840 config |= MCI_CDR_EN;
3841 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3842 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3843
3844 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3845 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3846 if (rc)
3847 goto err_out;
3848
3849 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3850 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3851 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3852
3853 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3854 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3855 if (rc)
3856 goto err_out;
3857
3858 goto out;
3859
3860err_out:
3861 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3862out:
3863 return rc;
3864}
3865
3866static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3867 u8 phase)
3868{
3869 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303870 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3871 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3872 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303873 unsigned long flags;
3874 u32 config;
3875
3876 spin_lock_irqsave(&host->lock, flags);
3877
3878 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3879 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3880 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3881 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3882
3883 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3884 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3885 if (rc)
3886 goto err_out;
3887
3888 /*
3889 * Write the selected DLL clock output phase (0 ... 15)
3890 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3891 */
3892 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3893 & ~(0xF << 20))
3894 | (grey_coded_phase_table[phase] << 20)),
3895 host->base + MCI_DLL_CONFIG);
3896
3897 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3898 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3899 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3900
3901 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3902 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3903 if (rc)
3904 goto err_out;
3905
3906 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3907 config |= MCI_CDR_EN;
3908 config &= ~MCI_CDR_EXT_EN;
3909 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3910 goto out;
3911
3912err_out:
3913 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3914 mmc_hostname(host->mmc), __func__, phase);
3915out:
3916 spin_unlock_irqrestore(&host->lock, flags);
3917 return rc;
3918}
3919
3920/*
3921 * Find out the greatest range of consecuitive selected
3922 * DLL clock output phases that can be used as sampling
3923 * setting for SD3.0 UHS-I card read operation (in SDR104
3924 * timing mode) or for eMMC4.5 card read operation (in HS200
3925 * timing mode).
3926 * Select the 3/4 of the range and configure the DLL with the
3927 * selected DLL clock output phase.
3928*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303929static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303930 u8 *phase_table, u8 total_phases)
3931{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303932 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303933 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303934 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3935 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303936 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303937 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3938 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303939
Subhash Jadavani6159c622012-03-15 19:05:55 +05303940 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303941 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3942 mmc_hostname(host->mmc), __func__, total_phases);
3943 return -EINVAL;
3944 }
3945
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303946 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303947 ranges[row_index][col_index] = phase_table[cnt];
3948 phases_per_row[row_index] += 1;
3949 col_index++;
3950
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303951 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303952 continue;
3953 /* check if next phase in phase_table is consecutive or not */
3954 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3955 row_index++;
3956 col_index = 0;
3957 }
3958 }
3959
Subhash Jadavani6159c622012-03-15 19:05:55 +05303960 if (row_index >= MAX_PHASES)
3961 return -EINVAL;
3962
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303963 /* Check if phase-0 is present in first valid window? */
3964 if (!ranges[0][0]) {
3965 phase_0_found = true;
3966 phase_0_raw_index = 0;
3967 /* Check if cycle exist between 2 valid windows */
3968 for (cnt = 1; cnt <= row_index; cnt++) {
3969 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303970 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303971 if (ranges[cnt][i] == 15) {
3972 phase_15_found = true;
3973 phase_15_raw_index = cnt;
3974 break;
3975 }
3976 }
3977 }
3978 }
3979 }
3980
3981 /* If 2 valid windows form cycle then merge them as single window */
3982 if (phase_0_found && phase_15_found) {
3983 /* number of phases in raw where phase 0 is present */
3984 u8 phases_0 = phases_per_row[phase_0_raw_index];
3985 /* number of phases in raw where phase 15 is present */
3986 u8 phases_15 = phases_per_row[phase_15_raw_index];
3987
Subhash Jadavani6159c622012-03-15 19:05:55 +05303988 if (phases_0 + phases_15 >= MAX_PHASES)
3989 /*
3990 * If there are more than 1 phase windows then total
3991 * number of phases in both the windows should not be
3992 * more than or equal to MAX_PHASES.
3993 */
3994 return -EINVAL;
3995
3996 /* Merge 2 cyclic windows */
3997 i = phases_15;
3998 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303999 ranges[phase_15_raw_index][i] =
4000 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304001 if (++i >= MAX_PHASES)
4002 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304003 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304004
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304005 phases_per_row[phase_0_raw_index] = 0;
4006 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4007 }
4008
4009 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304010 if (phases_per_row[cnt] > curr_max) {
4011 curr_max = phases_per_row[cnt];
4012 selected_row_index = cnt;
4013 }
4014 }
4015
Subhash Jadavani6159c622012-03-15 19:05:55 +05304016 i = ((curr_max * 3) / 4);
4017 if (i)
4018 i--;
4019
Subhash Jadavani34187042012-03-02 10:59:49 +05304020 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304021
Subhash Jadavani6159c622012-03-15 19:05:55 +05304022 if (ret >= MAX_PHASES) {
4023 ret = -EINVAL;
4024 pr_err("%s: %s: invalid phase selected=%d\n",
4025 mmc_hostname(host->mmc), __func__, ret);
4026 }
4027
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304028 return ret;
4029}
4030
Girish K Sa3f41692012-02-29 12:00:09 +05304031static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304032{
4033 int rc = 0;
4034 struct msmsdcc_host *host = mmc_priv(mmc);
4035 unsigned long flags;
4036 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304037 const u32 *tuning_block_pattern = tuning_block_64;
4038 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304039
4040 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4041
4042 /* Tuning is only required for SDR104 modes */
4043 if (!host->tuning_needed) {
4044 rc = 0;
4045 goto exit;
4046 }
4047
4048 spin_lock_irqsave(&host->lock, flags);
4049 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304050 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304051 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4052
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304053 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304054 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4055 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4056 tuning_block_pattern = tuning_block_128;
4057 size = sizeof(tuning_block_128);
4058 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304059 spin_unlock_irqrestore(&host->lock, flags);
4060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061 /* first of all reset the tuning block */
4062 rc = msmsdcc_init_cm_sdc4_dll(host);
4063 if (rc)
4064 goto out;
4065
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304066 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 if (!data_buf) {
4068 rc = -ENOMEM;
4069 goto out;
4070 }
4071
4072 phase = 0;
4073 do {
4074 struct mmc_command cmd = {0};
4075 struct mmc_data data = {0};
4076 struct mmc_request mrq = {
4077 .cmd = &cmd,
4078 .data = &data
4079 };
4080 struct scatterlist sg;
4081
4082 /* set the phase in delay line hw block */
4083 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4084 if (rc)
4085 goto kfree;
4086
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304087 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4089
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304090 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004091 data.blocks = 1;
4092 data.flags = MMC_DATA_READ;
4093 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4094
4095 data.sg = &sg;
4096 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304097 sg_init_one(&sg, data_buf, size);
4098 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099 mmc_wait_for_req(mmc, &mrq);
4100
4101 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304102 !memcmp(data_buf, tuning_block_pattern, size)) {
4103 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304105 pr_debug("%s: %s: found good phase = %d\n",
4106 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 }
4108 } while (++phase < 16);
4109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004110 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304111 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304112 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304113 if (rc < 0)
4114 goto kfree;
4115 else
4116 phase = (u8)rc;
4117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118 /*
4119 * Finally set the selected phase in delay
4120 * line hw block.
4121 */
4122 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4123 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304124 goto kfree;
4125 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4126 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127 } else {
4128 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304129 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304131 msmsdcc_dump_sdcc_state(host);
4132 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004133 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134
4135kfree:
4136 kfree(data_buf);
4137out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304138 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304139 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304140 spin_unlock_irqrestore(&host->lock, flags);
4141exit:
4142 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004144}
4145
Asutosh Dasebd7d092012-07-09 19:08:26 +05304146/*
4147 * Work around of the unavailability of a power_reset functionality in SD cards
4148 * by turning the OFF & back ON the regulators supplying the SD card.
4149 */
4150void msmsdcc_hw_reset(struct mmc_host *mmc)
4151{
4152 struct mmc_card *card = mmc->card;
4153 struct msmsdcc_host *host = mmc_priv(mmc);
4154 int rc;
4155
4156 /* Write-protection bits would be lost on a hardware reset in emmc */
4157 if (!card || !mmc_card_sd(card))
4158 return;
4159
4160 /*
4161 * Continuing on failing to disable regulator would lead to a panic
4162 * anyway, since the commands would fail and console would be flooded
4163 * with prints, eventually leading to a watchdog bark
4164 */
4165 rc = msmsdcc_setup_vreg(host, false, false);
4166 if (rc) {
4167 pr_err("%s: %s disable regulator: failed: %d\n",
4168 mmc_hostname(mmc), __func__, rc);
4169 BUG_ON(rc);
4170 }
4171
4172 /* 10ms delay for the supply to reach the desired voltage level */
4173 usleep_range(10000, 12000);
4174
4175 /*
4176 * Continuing on failing to enable regulator would lead to a panic
4177 * anyway, since the commands would fail and console would be flooded
4178 * with prints, eventually leading to a watchdog bark
4179 */
4180 rc = msmsdcc_setup_vreg(host, true, false);
4181 if (rc) {
4182 pr_err("%s: %s enable regulator: failed: %d\n",
4183 mmc_hostname(mmc), __func__, rc);
4184 BUG_ON(rc);
4185 }
4186
4187 /* 10ms delay for the supply to reach the desired voltage level */
4188 usleep_range(10000, 12000);
4189}
4190
San Mehat9d2bd732009-09-22 16:44:22 -07004191static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004192 .enable = msmsdcc_enable,
4193 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304194 .pre_req = msmsdcc_pre_req,
4195 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004196 .request = msmsdcc_request,
4197 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004198 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004199 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304200 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304201 .execute_tuning = msmsdcc_execute_tuning,
4202 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004203};
4204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004205static unsigned int
4206msmsdcc_slot_status(struct msmsdcc_host *host)
4207{
4208 int status;
4209 unsigned int gpio_no = host->plat->status_gpio;
4210
4211 status = gpio_request(gpio_no, "SD_HW_Detect");
4212 if (status) {
4213 pr_err("%s: %s: Failed to request GPIO %d\n",
4214 mmc_hostname(host->mmc), __func__, gpio_no);
4215 } else {
4216 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004217 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08004218 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08004219 if (host->plat->is_status_gpio_active_low)
4220 status = !status;
4221 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 gpio_free(gpio_no);
4223 }
4224 return status;
4225}
4226
San Mehat9d2bd732009-09-22 16:44:22 -07004227static void
4228msmsdcc_check_status(unsigned long data)
4229{
4230 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4231 unsigned int status;
4232
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304233 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004234 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004236 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004237 status = msmsdcc_slot_status(host);
4238
Krishna Konda941604a2012-01-10 17:46:34 -08004239 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004242 if (host->plat->status)
4243 pr_info("%s: Slot status change detected "
4244 "(%d -> %d)\n",
4245 mmc_hostname(host->mmc),
4246 host->oldstat, status);
4247 else if (host->plat->is_status_gpio_active_low)
4248 pr_info("%s: Slot status change detected "
4249 "(%d -> %d) and the card detect GPIO"
4250 " is ACTIVE_LOW\n",
4251 mmc_hostname(host->mmc),
4252 host->oldstat, status);
4253 else
4254 pr_info("%s: Slot status change detected "
4255 "(%d -> %d) and the card detect GPIO"
4256 " is ACTIVE_HIGH\n",
4257 mmc_hostname(host->mmc),
4258 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004259 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004260 }
4261 host->oldstat = status;
4262 } else {
4263 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004264 }
San Mehat9d2bd732009-09-22 16:44:22 -07004265}
4266
4267static irqreturn_t
4268msmsdcc_platform_status_irq(int irq, void *dev_id)
4269{
4270 struct msmsdcc_host *host = dev_id;
4271
Girish K Sa3c76eb2011-10-11 11:44:09 +05304272 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004273 msmsdcc_check_status((unsigned long) host);
4274 return IRQ_HANDLED;
4275}
4276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004277static irqreturn_t
4278msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4279{
4280 struct msmsdcc_host *host = dev_id;
4281
4282 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4283 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304284 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004285 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304286 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287 wake_lock(&host->sdio_wlock);
4288 msmsdcc_disable_irq_wake(host);
4289 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304290 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004291 }
4292 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004293 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304294 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304295 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304296 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004297 }
4298 spin_unlock(&host->lock);
4299
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304300out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004301 return IRQ_HANDLED;
4302}
4303
San Mehat9d2bd732009-09-22 16:44:22 -07004304static void
4305msmsdcc_status_notify_cb(int card_present, void *dev_id)
4306{
4307 struct msmsdcc_host *host = dev_id;
4308
Girish K Sa3c76eb2011-10-11 11:44:09 +05304309 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004310 card_present);
4311 msmsdcc_check_status((unsigned long) host);
4312}
4313
San Mehat9d2bd732009-09-22 16:44:22 -07004314static int
4315msmsdcc_init_dma(struct msmsdcc_host *host)
4316{
4317 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4318 host->dma.host = host;
4319 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004320 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004321
4322 if (!host->dmares)
4323 return -ENODEV;
4324
4325 host->dma.nc = dma_alloc_coherent(NULL,
4326 sizeof(struct msmsdcc_nc_dmadata),
4327 &host->dma.nc_busaddr,
4328 GFP_KERNEL);
4329 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004330 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004331 return -ENOMEM;
4332 }
4333 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4334 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4335 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4336 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4337 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004338 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004339
4340 return 0;
4341}
4342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004343#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4344/**
4345 * Allocate and Connect a SDCC peripheral's SPS endpoint
4346 *
4347 * This function allocates endpoint context and
4348 * connect it with memory endpoint by calling
4349 * appropriate SPS driver APIs.
4350 *
4351 * Also registers a SPS callback function with
4352 * SPS driver
4353 *
4354 * This function should only be called once typically
4355 * during driver probe.
4356 *
4357 * @host - Pointer to sdcc host structure
4358 * @ep - Pointer to sps endpoint data structure
4359 * @is_produce - 1 means Producer endpoint
4360 * 0 means Consumer endpoint
4361 *
4362 * @return - 0 if successful else negative value.
4363 *
4364 */
4365static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4366 struct msmsdcc_sps_ep_conn_data *ep,
4367 bool is_producer)
4368{
4369 int rc = 0;
4370 struct sps_pipe *sps_pipe_handle;
4371 struct sps_connect *sps_config = &ep->config;
4372 struct sps_register_event *sps_event = &ep->event;
4373
4374 /* Allocate endpoint context */
4375 sps_pipe_handle = sps_alloc_endpoint();
4376 if (!sps_pipe_handle) {
4377 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4378 mmc_hostname(host->mmc), is_producer);
4379 rc = -ENOMEM;
4380 goto out;
4381 }
4382
4383 /* Get default connection configuration for an endpoint */
4384 rc = sps_get_config(sps_pipe_handle, sps_config);
4385 if (rc) {
4386 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4387 " rc=%d", mmc_hostname(host->mmc),
4388 (u32)sps_pipe_handle, rc);
4389 goto get_config_err;
4390 }
4391
4392 /* Modify the default connection configuration */
4393 if (is_producer) {
4394 /*
4395 * For SDCC producer transfer, source should be
4396 * SDCC peripheral where as destination should
4397 * be system memory.
4398 */
4399 sps_config->source = host->sps.bam_handle;
4400 sps_config->destination = SPS_DEV_HANDLE_MEM;
4401 /* Producer pipe will handle this connection */
4402 sps_config->mode = SPS_MODE_SRC;
4403 sps_config->options =
4404 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4405 } else {
4406 /*
4407 * For SDCC consumer transfer, source should be
4408 * system memory where as destination should
4409 * SDCC peripheral
4410 */
4411 sps_config->source = SPS_DEV_HANDLE_MEM;
4412 sps_config->destination = host->sps.bam_handle;
4413 sps_config->mode = SPS_MODE_DEST;
4414 sps_config->options =
4415 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4416 }
4417
4418 /* Producer pipe index */
4419 sps_config->src_pipe_index = host->sps.src_pipe_index;
4420 /* Consumer pipe index */
4421 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4422 /*
4423 * This event thresold value is only significant for BAM-to-BAM
4424 * transfer. It's ignored for BAM-to-System mode transfer.
4425 */
4426 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304427
4428 /* Allocate maximum descriptor fifo size */
4429 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4430 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004431 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4432 sps_config->desc.size,
4433 &sps_config->desc.phys_base,
4434 GFP_KERNEL);
4435
Pratibhasagar V00b94332011-10-18 14:57:27 +05304436 if (!sps_config->desc.base) {
4437 rc = -ENOMEM;
4438 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4439 , mmc_hostname(host->mmc));
4440 goto get_config_err;
4441 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004442 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4443
4444 /* Establish connection between peripheral and memory endpoint */
4445 rc = sps_connect(sps_pipe_handle, sps_config);
4446 if (rc) {
4447 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4448 " rc=%d", mmc_hostname(host->mmc),
4449 (u32)sps_pipe_handle, rc);
4450 goto sps_connect_err;
4451 }
4452
4453 sps_event->mode = SPS_TRIGGER_CALLBACK;
4454 sps_event->options = SPS_O_EOT;
4455 sps_event->callback = msmsdcc_sps_complete_cb;
4456 sps_event->xfer_done = NULL;
4457 sps_event->user = (void *)host;
4458
4459 /* Register callback event for EOT (End of transfer) event. */
4460 rc = sps_register_event(sps_pipe_handle, sps_event);
4461 if (rc) {
4462 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4463 " rc=%d", mmc_hostname(host->mmc),
4464 (u32)sps_pipe_handle, rc);
4465 goto reg_event_err;
4466 }
4467 /* Now save the sps pipe handle */
4468 ep->pipe_handle = sps_pipe_handle;
4469 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4470 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4471 __func__, is_producer ? "READ" : "WRITE",
4472 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4473 goto out;
4474
4475reg_event_err:
4476 sps_disconnect(sps_pipe_handle);
4477sps_connect_err:
4478 dma_free_coherent(mmc_dev(host->mmc),
4479 sps_config->desc.size,
4480 sps_config->desc.base,
4481 sps_config->desc.phys_base);
4482get_config_err:
4483 sps_free_endpoint(sps_pipe_handle);
4484out:
4485 return rc;
4486}
4487
4488/**
4489 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4490 *
4491 * This function disconnect endpoint and deallocates
4492 * endpoint context.
4493 *
4494 * This function should only be called once typically
4495 * during driver remove.
4496 *
4497 * @host - Pointer to sdcc host structure
4498 * @ep - Pointer to sps endpoint data structure
4499 *
4500 */
4501static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4502 struct msmsdcc_sps_ep_conn_data *ep)
4503{
4504 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4505 struct sps_connect *sps_config = &ep->config;
4506 struct sps_register_event *sps_event = &ep->event;
4507
4508 sps_event->xfer_done = NULL;
4509 sps_event->callback = NULL;
4510 sps_register_event(sps_pipe_handle, sps_event);
4511 sps_disconnect(sps_pipe_handle);
4512 dma_free_coherent(mmc_dev(host->mmc),
4513 sps_config->desc.size,
4514 sps_config->desc.base,
4515 sps_config->desc.phys_base);
4516 sps_free_endpoint(sps_pipe_handle);
4517}
4518
4519/**
4520 * Reset SDCC peripheral's SPS endpoint
4521 *
4522 * This function disconnects an endpoint.
4523 *
4524 * This function should be called for reseting
4525 * SPS endpoint when data transfer error is
4526 * encountered during data transfer. This
4527 * can be considered as soft reset to endpoint.
4528 *
4529 * This function should only be called if
4530 * msmsdcc_sps_init() is already called.
4531 *
4532 * @host - Pointer to sdcc host structure
4533 * @ep - Pointer to sps endpoint data structure
4534 *
4535 * @return - 0 if successful else negative value.
4536 */
4537static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4538 struct msmsdcc_sps_ep_conn_data *ep)
4539{
4540 int rc = 0;
4541 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4542
4543 rc = sps_disconnect(sps_pipe_handle);
4544 if (rc) {
4545 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4546 " rc=%d", mmc_hostname(host->mmc), __func__,
4547 (u32)sps_pipe_handle, rc);
4548 goto out;
4549 }
4550 out:
4551 return rc;
4552}
4553
4554/**
4555 * Restore SDCC peripheral's SPS endpoint
4556 *
4557 * This function connects an endpoint.
4558 *
4559 * This function should be called for restoring
4560 * SPS endpoint after data transfer error is
4561 * encountered during data transfer. This
4562 * can be considered as soft reset to endpoint.
4563 *
4564 * This function should only be called if
4565 * msmsdcc_sps_reset_ep() is called before.
4566 *
4567 * @host - Pointer to sdcc host structure
4568 * @ep - Pointer to sps endpoint data structure
4569 *
4570 * @return - 0 if successful else negative value.
4571 */
4572static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4573 struct msmsdcc_sps_ep_conn_data *ep)
4574{
4575 int rc = 0;
4576 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4577 struct sps_connect *sps_config = &ep->config;
4578 struct sps_register_event *sps_event = &ep->event;
4579
4580 /* Establish connection between peripheral and memory endpoint */
4581 rc = sps_connect(sps_pipe_handle, sps_config);
4582 if (rc) {
4583 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4584 " rc=%d", mmc_hostname(host->mmc), __func__,
4585 (u32)sps_pipe_handle, rc);
4586 goto out;
4587 }
4588
4589 /* Register callback event for EOT (End of transfer) event. */
4590 rc = sps_register_event(sps_pipe_handle, sps_event);
4591 if (rc) {
4592 pr_err("%s: %s: sps_register_event() failed!!!"
4593 " pipe_handle=0x%x, rc=%d",
4594 mmc_hostname(host->mmc), __func__,
4595 (u32)sps_pipe_handle, rc);
4596 goto reg_event_err;
4597 }
4598 goto out;
4599
4600reg_event_err:
4601 sps_disconnect(sps_pipe_handle);
4602out:
4603 return rc;
4604}
4605
4606/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004607 * Handle BAM device's global error condition
4608 *
4609 * This is an error handler for the SDCC bam device
4610 *
4611 * This function is registered as a callback with SPS-BAM
4612 * driver and will called in case there are an errors for
4613 * the SDCC BAM deivce. Any error conditions in the BAM
4614 * device are global and will be result in this function
4615 * being called once per device.
4616 *
4617 * This function will be called from the sps driver's
4618 * interrupt context.
4619 *
4620 * @sps_cb_case - indicates what error it is
4621 * @user - Pointer to sdcc host structure
4622 */
4623static void
4624msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4625{
4626 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4627 struct mmc_request *mrq;
4628 unsigned long flags;
4629 int32_t error = 0;
4630
4631 BUG_ON(!host);
4632 BUG_ON(!is_sps_mode(host));
4633
4634 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Maya Erezb7a086f2012-11-29 00:37:36 +02004635 /* Reset all endpoints along with resetting bam. */
4636 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004637
4638 pr_err("%s: BAM Global ERROR IRQ happened\n",
4639 mmc_hostname(host->mmc));
4640 error = EAGAIN;
4641 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4642 /**
4643 * This means that there was an AHB access error and
4644 * the address we are trying to read/write is something
4645 * we dont have priviliges to do so.
4646 */
4647 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4648 mmc_hostname(host->mmc));
4649 error = EACCES;
4650 } else {
4651 /**
4652 * This should not have happened ideally. If this happens
4653 * there is some seriously wrong.
4654 */
4655 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4656 mmc_hostname(host->mmc), (u32) sps_cb_case);
4657 error = EIO;
4658 }
4659
4660 spin_lock_irqsave(&host->lock, flags);
4661
4662 mrq = host->curr.mrq;
4663
4664 if (mrq && mrq->cmd) {
4665 msmsdcc_dump_sdcc_state(host);
4666
4667 if (!mrq->cmd->error)
4668 mrq->cmd->error = -error;
4669 if (host->curr.data) {
4670 if (mrq->data && !mrq->data->error)
4671 mrq->data->error = -error;
4672 host->curr.data_xfered = 0;
4673 if (host->sps.sg && is_sps_mode(host)) {
4674 /* Stop current SPS transfer */
4675 msmsdcc_sps_exit_curr_xfer(host);
4676 } else {
4677 /* this condition should not have happened */
4678 pr_err("%s: something is seriously wrong. "\
4679 "Funtion: %s, line: %d\n",
4680 mmc_hostname(host->mmc),
4681 __func__, __LINE__);
4682 }
4683 } else {
4684 /* this condition should not have happened */
4685 pr_err("%s: something is seriously wrong. Funtion: "\
4686 "%s, line: %d\n", mmc_hostname(host->mmc),
4687 __func__, __LINE__);
4688 }
4689 }
4690 spin_unlock_irqrestore(&host->lock, flags);
4691}
4692
4693/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004694 * Initialize SPS HW connected with SDCC core
4695 *
4696 * This function register BAM HW resources with
4697 * SPS driver and then initialize 2 SPS endpoints
4698 *
4699 * This function should only be called once typically
4700 * during driver probe.
4701 *
4702 * @host - Pointer to sdcc host structure
4703 *
4704 * @return - 0 if successful else negative value.
4705 *
4706 */
4707static int msmsdcc_sps_init(struct msmsdcc_host *host)
4708{
4709 int rc = 0;
4710 struct sps_bam_props bam = {0};
4711
4712 host->bam_base = ioremap(host->bam_memres->start,
4713 resource_size(host->bam_memres));
4714 if (!host->bam_base) {
4715 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4716 " size=0x%x", mmc_hostname(host->mmc),
4717 host->bam_memres->start,
4718 (host->bam_memres->end -
4719 host->bam_memres->start));
4720 rc = -ENOMEM;
4721 goto out;
4722 }
4723
4724 bam.phys_addr = host->bam_memres->start;
4725 bam.virt_addr = host->bam_base;
4726 /*
4727 * This event thresold value is only significant for BAM-to-BAM
4728 * transfer. It's ignored for BAM-to-System mode transfer.
4729 */
4730 bam.event_threshold = 0x10; /* Pipe event threshold */
4731 /*
4732 * This threshold controls when the BAM publish
4733 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304734 * SPS HW will be used for data transfer size even
4735 * less than SDCC FIFO size. So let's set BAM summing
4736 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304738 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004739 /* SPS driver wll handle the SDCC BAM IRQ */
4740 bam.irq = (u32)host->bam_irqres->start;
4741 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004742 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4743 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004744
4745 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4746 (u32)bam.phys_addr);
4747 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4748 (u32)bam.virt_addr);
4749
4750 /* Register SDCC Peripheral BAM device to SPS driver */
4751 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4752 if (rc) {
4753 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4754 mmc_hostname(host->mmc), rc);
4755 goto reg_bam_err;
4756 }
4757 pr_info("%s: BAM device registered. bam_handle=0x%x",
4758 mmc_hostname(host->mmc), host->sps.bam_handle);
4759
4760 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4761 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4762
4763 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4764 SPS_PROD_PERIPHERAL);
4765 if (rc)
4766 goto sps_reset_err;
4767 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4768 SPS_CONS_PERIPHERAL);
4769 if (rc)
4770 goto cons_conn_err;
4771
4772 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4773 mmc_hostname(host->mmc),
4774 (unsigned long long)host->bam_memres->start,
4775 (unsigned int)host->bam_irqres->start);
4776 goto out;
4777
4778cons_conn_err:
4779 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4780sps_reset_err:
4781 sps_deregister_bam_device(host->sps.bam_handle);
4782reg_bam_err:
4783 iounmap(host->bam_base);
4784out:
4785 return rc;
4786}
4787
4788/**
4789 * De-initialize SPS HW connected with SDCC core
4790 *
4791 * This function deinitialize SPS endpoints and then
4792 * deregisters BAM resources from SPS driver.
4793 *
4794 * This function should only be called once typically
4795 * during driver remove.
4796 *
4797 * @host - Pointer to sdcc host structure
4798 *
4799 */
4800static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4801{
4802 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4803 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4804 sps_deregister_bam_device(host->sps.bam_handle);
4805 iounmap(host->bam_base);
4806}
4807#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4808
4809static ssize_t
4810show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4811{
4812 struct mmc_host *mmc = dev_get_drvdata(dev);
4813 struct msmsdcc_host *host = mmc_priv(mmc);
4814 int poll;
4815 unsigned long flags;
4816
4817 spin_lock_irqsave(&host->lock, flags);
4818 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4819 spin_unlock_irqrestore(&host->lock, flags);
4820
4821 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4822}
4823
4824static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304825store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004826 const char *buf, size_t count)
4827{
4828 struct mmc_host *mmc = dev_get_drvdata(dev);
4829 struct msmsdcc_host *host = mmc_priv(mmc);
4830 int value;
4831 unsigned long flags;
4832
4833 sscanf(buf, "%d", &value);
4834
4835 spin_lock_irqsave(&host->lock, flags);
4836 if (value) {
4837 mmc->caps |= MMC_CAP_NEEDS_POLL;
4838 mmc_detect_change(host->mmc, 0);
4839 } else {
4840 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4841 }
4842#ifdef CONFIG_HAS_EARLYSUSPEND
4843 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4844#endif
4845 spin_unlock_irqrestore(&host->lock, flags);
4846 return count;
4847}
4848
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304849static ssize_t
4850show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4851 char *buf)
4852{
4853 struct mmc_host *mmc = dev_get_drvdata(dev);
4854 struct msmsdcc_host *host = mmc_priv(mmc);
4855
4856 return snprintf(buf, PAGE_SIZE, "%u\n",
4857 host->msm_bus_vote.is_max_bw_needed);
4858}
4859
4860static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304861store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304862 const char *buf, size_t count)
4863{
4864 struct mmc_host *mmc = dev_get_drvdata(dev);
4865 struct msmsdcc_host *host = mmc_priv(mmc);
4866 uint32_t value;
4867 unsigned long flags;
4868
4869 if (!kstrtou32(buf, 0, &value)) {
4870 spin_lock_irqsave(&host->lock, flags);
4871 host->msm_bus_vote.is_max_bw_needed = !!value;
4872 spin_unlock_irqrestore(&host->lock, flags);
4873 }
4874
4875 return count;
4876}
4877
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304878static ssize_t
4879show_idle_timeout(struct device *dev, struct device_attribute *attr,
4880 char *buf)
4881{
4882 struct mmc_host *mmc = dev_get_drvdata(dev);
4883 struct msmsdcc_host *host = mmc_priv(mmc);
4884
4885 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
4886 host->idle_tout_ms / 1000);
4887}
4888
4889static ssize_t
4890store_idle_timeout(struct device *dev, struct device_attribute *attr,
4891 const char *buf, size_t count)
4892{
4893 struct mmc_host *mmc = dev_get_drvdata(dev);
4894 struct msmsdcc_host *host = mmc_priv(mmc);
4895 unsigned int long flags;
4896 int timeout; /* in secs */
4897
4898 if (!kstrtou32(buf, 0, &timeout)
4899 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4900 spin_lock_irqsave(&host->lock, flags);
4901 host->idle_tout_ms = timeout * 1000;
4902 spin_unlock_irqrestore(&host->lock, flags);
4903 }
4904 return count;
4905}
4906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907#ifdef CONFIG_HAS_EARLYSUSPEND
4908static void msmsdcc_early_suspend(struct early_suspend *h)
4909{
4910 struct msmsdcc_host *host =
4911 container_of(h, struct msmsdcc_host, early_suspend);
4912 unsigned long flags;
4913
4914 spin_lock_irqsave(&host->lock, flags);
4915 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4916 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4917 spin_unlock_irqrestore(&host->lock, flags);
4918};
4919static void msmsdcc_late_resume(struct early_suspend *h)
4920{
4921 struct msmsdcc_host *host =
4922 container_of(h, struct msmsdcc_host, early_suspend);
4923 unsigned long flags;
4924
4925 if (host->polling_enabled) {
4926 spin_lock_irqsave(&host->lock, flags);
4927 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4928 mmc_detect_change(host->mmc, 0);
4929 spin_unlock_irqrestore(&host->lock, flags);
4930 }
4931};
4932#endif
4933
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304934static void msmsdcc_print_regs(const char *name, void __iomem *base,
4935 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304936{
4937 unsigned int i;
4938
4939 if (!base)
4940 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304941
4942 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4943 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304944 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304945 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4946 (u32)readl_relaxed(base + i*4),
4947 (u32)readl_relaxed(base + ((i+1)*4)),
4948 (u32)readl_relaxed(base + ((i+2)*4)),
4949 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304950 }
4951}
4952
4953static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4954{
4955 /* Dump current state of SDCC clocks, power and irq */
4956 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304957 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304958 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304959 mmc_hostname(host->mmc),
4960 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304961 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304962 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4963 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4964
4965 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304966 if (atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304967 msmsdcc_print_regs("SDCC-CORE", host->base,
4968 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304969
4970 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304971 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304972 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304973 else if (is_dma_mode(host))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304974 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4975 mmc_hostname(host->mmc), host->dma.busy,
4976 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05304977 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304978 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304979 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4980 host->dml_memres->start,
4981 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304982 pr_info("%s: SPS mode: busy=%d\n",
4983 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304984 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304985
4986 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4987 mmc_hostname(host->mmc), host->curr.xfer_size,
4988 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304989 }
4990
Maya Erezb7a086f2012-11-29 00:37:36 +02004991 if (host->sps.reset_bam)
4992 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
4993 mmc_hostname(host->mmc), host->sps.reset_bam);
4994
4995 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304996 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4997 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4998 host->curr.got_dataend, host->prog_enable,
4999 host->curr.wait_for_auto_prog_done,
5000 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305001 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305002}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5005{
5006 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5007 struct mmc_request *mrq;
5008 unsigned long flags;
5009
5010 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005011 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005012 pr_info("%s: %s: dummy CMD52 timeout\n",
5013 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005014 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005015 }
5016
5017 mrq = host->curr.mrq;
5018
5019 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305020 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
5021 mrq->cmd->opcode);
5022 msmsdcc_dump_sdcc_state(host);
5023
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005024 if (!mrq->cmd->error)
5025 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305026 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005027 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005028 if (mrq->data && !mrq->data->error)
5029 mrq->data->error = -ETIMEDOUT;
5030 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305031 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005032 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305033 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 /* Stop current SPS transfer */
5035 msmsdcc_sps_exit_curr_xfer(host);
5036 } else {
5037 msmsdcc_reset_and_restore(host);
5038 msmsdcc_stop_data(host);
5039 if (mrq->data && mrq->data->stop)
5040 msmsdcc_start_command(host,
5041 mrq->data->stop, 0);
5042 else
5043 msmsdcc_request_end(host, mrq);
5044 }
5045 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305046 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305047 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048 msmsdcc_reset_and_restore(host);
5049 msmsdcc_request_end(host, mrq);
5050 }
5051 }
5052 spin_unlock_irqrestore(&host->lock, flags);
5053}
5054
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305055/*
5056 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5057 *
5058 * @dev: device node from which the property value is to be read.
5059 * @prop_name: name of the property to be searched.
5060 * @out_array: filled array returned to caller
5061 * @len: filled array size returned to caller
5062 * @size: expected size of the array
5063 *
5064 * If expected "size" doesn't match with "len" an error is returned. If
5065 * expected size is zero, the length of actual array is returned provided
5066 * return value is zero.
5067 *
5068 * RETURNS:
5069 * zero on success, negative error if failed.
5070 */
5071static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5072 u32 **out_array, int *len, int size)
5073{
5074 int ret = 0;
5075 u32 *array = NULL;
5076 struct device_node *np = dev->of_node;
5077
5078 if (of_get_property(np, prop_name, len)) {
5079 size_t sz;
5080 sz = *len = *len / sizeof(*array);
5081
5082 if (sz > 0 && !(size > 0 && (sz != size))) {
5083 array = devm_kzalloc(dev, sz * sizeof(*array),
5084 GFP_KERNEL);
5085 if (!array) {
5086 dev_err(dev, "%s: no memory\n", prop_name);
5087 ret = -ENOMEM;
5088 goto out;
5089 }
5090
5091 ret = of_property_read_u32_array(np, prop_name,
5092 array, sz);
5093 if (ret < 0) {
5094 dev_err(dev, "%s: error reading array %d\n",
5095 prop_name, ret);
5096 goto out;
5097 }
5098 } else {
5099 dev_err(dev, "%s invalid size\n", prop_name);
5100 ret = -EINVAL;
5101 goto out;
5102 }
5103 } else {
5104 dev_err(dev, "%s not specified\n", prop_name);
5105 ret = -EINVAL;
5106 goto out;
5107 }
5108 *out_array = array;
5109out:
5110 if (ret)
5111 *len = 0;
5112 return ret;
5113}
5114
5115static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5116 struct msm_mmc_pad_pull_data **pad_pull_data)
5117{
5118 int ret = 0, base = 0, len, i;
5119 u32 *tmp;
5120 struct msm_mmc_pad_pull_data *pull_data;
5121 struct msm_mmc_pad_pull *pull;
5122
5123 switch (id) {
5124 case 1:
5125 base = TLMM_PULL_SDC1_CLK;
5126 break;
5127 case 2:
5128 base = TLMM_PULL_SDC2_CLK;
5129 break;
5130 case 3:
5131 base = TLMM_PULL_SDC3_CLK;
5132 break;
5133 case 4:
5134 base = TLMM_PULL_SDC4_CLK;
5135 break;
5136 default:
5137 dev_err(dev, "%s: Invalid slot id\n", __func__);
5138 ret = -EINVAL;
5139 goto err;
5140 }
5141
5142 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5143 GFP_KERNEL);
5144 if (!pull_data) {
5145 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5146 ret = -ENOMEM;
5147 goto err;
5148 }
5149 pull_data->size = 3; /* array size for clk, cmd, data */
5150
5151 /* Allocate on, off configs for clk, cmd, data */
5152 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5153 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5154 if (!pull) {
5155 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5156 ret = -ENOMEM;
5157 goto err;
5158 }
5159 pull_data->on = pull;
5160 pull_data->off = pull + pull_data->size;
5161
5162 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
5163 &tmp, &len, pull_data->size);
5164 if (!ret) {
5165 for (i = 0; i < len; i++) {
5166 pull_data->on[i].no = base + i;
5167 pull_data->on[i].val = tmp[i];
5168 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5169 i, pull_data->on[i].val);
5170 }
5171 } else {
5172 goto err;
5173 }
5174
5175 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
5176 &tmp, &len, pull_data->size);
5177 if (!ret) {
5178 for (i = 0; i < len; i++) {
5179 pull_data->off[i].no = base + i;
5180 pull_data->off[i].val = tmp[i];
5181 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5182 i, pull_data->off[i].val);
5183 }
5184 } else {
5185 goto err;
5186 }
5187
5188 *pad_pull_data = pull_data;
5189err:
5190 return ret;
5191}
5192
5193static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5194 struct msm_mmc_pad_drv_data **pad_drv_data)
5195{
5196 int ret = 0, base = 0, len, i;
5197 u32 *tmp;
5198 struct msm_mmc_pad_drv_data *drv_data;
5199 struct msm_mmc_pad_drv *drv;
5200
5201 switch (id) {
5202 case 1:
5203 base = TLMM_HDRV_SDC1_CLK;
5204 break;
5205 case 2:
5206 base = TLMM_HDRV_SDC2_CLK;
5207 break;
5208 case 3:
5209 base = TLMM_HDRV_SDC3_CLK;
5210 break;
5211 case 4:
5212 base = TLMM_HDRV_SDC4_CLK;
5213 break;
5214 default:
5215 dev_err(dev, "%s: Invalid slot id\n", __func__);
5216 ret = -EINVAL;
5217 goto err;
5218 }
5219
5220 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5221 GFP_KERNEL);
5222 if (!drv_data) {
5223 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5224 ret = -ENOMEM;
5225 goto err;
5226 }
5227 drv_data->size = 3; /* array size for clk, cmd, data */
5228
5229 /* Allocate on, off configs for clk, cmd, data */
5230 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5231 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5232 if (!drv) {
5233 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5234 ret = -ENOMEM;
5235 goto err;
5236 }
5237 drv_data->on = drv;
5238 drv_data->off = drv + drv_data->size;
5239
5240 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
5241 &tmp, &len, drv_data->size);
5242 if (!ret) {
5243 for (i = 0; i < len; i++) {
5244 drv_data->on[i].no = base + i;
5245 drv_data->on[i].val = tmp[i];
5246 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5247 i, drv_data->on[i].val);
5248 }
5249 } else {
5250 goto err;
5251 }
5252
5253 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
5254 &tmp, &len, drv_data->size);
5255 if (!ret) {
5256 for (i = 0; i < len; i++) {
5257 drv_data->off[i].no = base + i;
5258 drv_data->off[i].val = tmp[i];
5259 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5260 i, drv_data->off[i].val);
5261 }
5262 } else {
5263 goto err;
5264 }
5265
5266 *pad_drv_data = drv_data;
5267err:
5268 return ret;
5269}
5270
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305271static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5272 struct mmc_platform_data *pdata)
5273{
5274 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5275 struct device_node *np = dev->of_node;
5276
5277 pdata->status_gpio = of_get_named_gpio_flags(np,
5278 "cd-gpios", 0, &flags);
5279 if (gpio_is_valid(pdata->status_gpio)) {
5280 pdata->status_irq = gpio_to_irq(pdata->status_gpio);
5281 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5282 }
5283
5284 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5285 "wp-gpios", 0, &flags);
5286 if (gpio_is_valid(pdata->wpswitch_gpio))
5287 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5288}
5289
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305290static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5291 struct mmc_platform_data *pdata)
5292{
5293 int ret = 0, id = 0, cnt, i;
5294 struct msm_mmc_pin_data *pin_data;
5295 struct device_node *np = dev->of_node;
5296
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305297 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5298
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305299 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5300 if (!pin_data) {
5301 dev_err(dev, "No memory for pin_data\n");
5302 ret = -ENOMEM;
5303 goto err;
5304 }
5305
5306 cnt = of_gpio_count(np);
5307 if (cnt > 0) {
5308 pin_data->is_gpio = true;
5309
5310 pin_data->gpio_data = devm_kzalloc(dev,
5311 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5312 if (!pin_data->gpio_data) {
5313 dev_err(dev, "No memory for gpio_data\n");
5314 ret = -ENOMEM;
5315 goto err;
5316 }
5317 pin_data->gpio_data->size = cnt;
5318 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5319 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5320 if (!pin_data->gpio_data->gpio) {
5321 dev_err(dev, "No memory for gpio\n");
5322 ret = -ENOMEM;
5323 goto err;
5324 }
5325
5326 for (i = 0; i < cnt; i++) {
5327 const char *name = NULL;
5328 char result[32];
5329 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5330 of_property_read_string_index(np,
5331 "qcom,sdcc-gpio-names", i, &name);
5332
5333 snprintf(result, 32, "%s-%s",
5334 dev_name(dev), name ? name : "?");
5335 pin_data->gpio_data->gpio[i].name = result;
5336 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5337 pin_data->gpio_data->gpio[i].name,
5338 pin_data->gpio_data->gpio[i].no);
5339 }
5340 } else {
5341 pin_data->pad_data = devm_kzalloc(dev,
5342 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5343 if (!pin_data->pad_data) {
5344 dev_err(dev, "No memory for pin_data->pad_data\n");
5345 ret = -ENOMEM;
5346 goto err;
5347 }
5348
5349 of_property_read_u32(np, "cell-index", &id);
5350
5351 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5352 &pin_data->pad_data->pull);
5353 if (ret)
5354 goto err;
5355 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5356 &pin_data->pad_data->drv);
5357 if (ret)
5358 goto err;
5359 }
5360
5361 pdata->pin_data = pin_data;
5362err:
5363 if (ret)
5364 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5365 return ret;
5366}
5367
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305368#define MAX_PROP_SIZE 32
5369static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5370 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5371{
5372 int len, ret = 0;
5373 const __be32 *prop;
5374 char prop_name[MAX_PROP_SIZE];
5375 struct msm_mmc_reg_data *vreg;
5376 struct device_node *np = dev->of_node;
5377
5378 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5379 if (of_parse_phandle(np, prop_name, 0)) {
5380 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5381 if (!vreg) {
5382 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5383 ret = -ENOMEM;
5384 goto err;
5385 }
5386
5387 vreg->name = vreg_name;
5388
5389 snprintf(prop_name, MAX_PROP_SIZE,
5390 "qcom,sdcc-%s-always_on", vreg_name);
5391 if (of_get_property(np, prop_name, NULL))
5392 vreg->always_on = true;
5393
5394 snprintf(prop_name, MAX_PROP_SIZE,
5395 "qcom,sdcc-%s-lpm_sup", vreg_name);
5396 if (of_get_property(np, prop_name, NULL))
5397 vreg->lpm_sup = true;
5398
5399 snprintf(prop_name, MAX_PROP_SIZE,
5400 "qcom,sdcc-%s-voltage_level", vreg_name);
5401 prop = of_get_property(np, prop_name, &len);
5402 if (!prop || (len != (2 * sizeof(__be32)))) {
5403 dev_warn(dev, "%s %s property\n",
5404 prop ? "invalid format" : "no", prop_name);
5405 } else {
5406 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5407 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5408 }
5409
5410 snprintf(prop_name, MAX_PROP_SIZE,
5411 "qcom,sdcc-%s-current_level", vreg_name);
5412 prop = of_get_property(np, prop_name, &len);
5413 if (!prop || (len != (2 * sizeof(__be32)))) {
5414 dev_warn(dev, "%s %s property\n",
5415 prop ? "invalid format" : "no", prop_name);
5416 } else {
5417 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5418 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5419 }
5420
5421 *vreg_data = vreg;
5422 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5423 vreg->name, vreg->always_on ? "always_on," : "",
5424 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5425 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5426 }
5427
5428err:
5429 return ret;
5430}
5431
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305432static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5433{
5434 int i, ret;
5435 struct mmc_platform_data *pdata;
5436 struct device_node *np = dev->of_node;
Devin Kim9ccbff52012-07-16 20:55:14 -07005437 u32 bus_width = 0, current_limit = 0;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305438 u32 *clk_table, *sup_voltages;
Devin Kim9ccbff52012-07-16 20:55:14 -07005439 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305440
5441 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5442 if (!pdata) {
5443 dev_err(dev, "could not allocate memory for platform data\n");
5444 goto err;
5445 }
5446
5447 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
5448 if (bus_width == 8) {
5449 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5450 } else if (bus_width == 4) {
5451 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5452 } else {
5453 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5454 pdata->mmc_bus_width = 0;
5455 }
5456
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305457 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
5458 &sup_voltages, &sup_volt_len, 0);
5459 if (!ret) {
5460 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305461 u32 mask;
5462
5463 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5464 sup_voltages[i + 1]);
5465 if (!mask)
5466 dev_err(dev, "Invalide voltage range %d\n", i);
5467 pdata->ocr_mask |= mask;
5468 }
5469 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305470 }
5471
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305472 ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
5473 &clk_table, &clk_table_len, 0);
5474 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305475 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305476 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305477 }
5478
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305479 pdata->vreg_data = devm_kzalloc(dev,
5480 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5481 if (!pdata->vreg_data) {
5482 dev_err(dev, "could not allocate memory for vreg_data\n");
5483 goto err;
5484 }
5485
5486 if (msmsdcc_dt_parse_vreg_info(dev,
5487 &pdata->vreg_data->vdd_data, "vdd"))
5488 goto err;
5489
5490 if (msmsdcc_dt_parse_vreg_info(dev,
5491 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5492 goto err;
5493
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305494 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5495 goto err;
5496
Devin Kim9ccbff52012-07-16 20:55:14 -07005497 len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
5498
5499 for (i = 0; i < len; i++) {
5500 const char *name = NULL;
5501
5502 of_property_read_string_index(np,
5503 "qcom,sdcc-bus-speed-mode", i, &name);
5504 if (!name)
5505 continue;
5506
5507 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5508 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5509 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5510 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5511 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5512 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5513 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5514 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5515 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5516 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5517 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5518 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5519 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5520 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5521 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5522 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5523 | MMC_CAP_UHS_DDR50;
5524 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5525 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5526 | MMC_CAP_UHS_DDR50;
5527 }
5528
5529 of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
5530 if (current_limit == 800)
5531 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5532 else if (current_limit == 600)
5533 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5534 else if (current_limit == 400)
5535 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5536 else if (current_limit == 200)
5537 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5538
5539 if (of_get_property(np, "qcom,sdcc-xpc", NULL))
5540 pdata->xpc_cap = true;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305541 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
5542 pdata->nonremovable = true;
5543 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
5544 pdata->disable_cmd23 = true;
5545
5546 return pdata;
5547err:
5548 return NULL;
5549}
5550
San Mehat9d2bd732009-09-22 16:44:22 -07005551static int
5552msmsdcc_probe(struct platform_device *pdev)
5553{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305554 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005555 struct msmsdcc_host *host;
5556 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005557 unsigned long flags;
5558 struct resource *core_irqres = NULL;
5559 struct resource *bam_irqres = NULL;
5560 struct resource *core_memres = NULL;
5561 struct resource *dml_memres = NULL;
5562 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005563 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005564 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305565 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005566
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305567 if (pdev->dev.of_node) {
5568 plat = msmsdcc_populate_pdata(&pdev->dev);
5569 of_property_read_u32((&pdev->dev)->of_node,
5570 "cell-index", &pdev->id);
5571 } else {
5572 plat = pdev->dev.platform_data;
5573 }
San Mehat9d2bd732009-09-22 16:44:22 -07005574
5575 /* must have platform data */
5576 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005577 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005578 ret = -EINVAL;
5579 goto out;
5580 }
5581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005582 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005583 return -EINVAL;
5584
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305585 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5586 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5587 return -EINVAL;
5588 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005589
San Mehat9d2bd732009-09-22 16:44:22 -07005590 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005591 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005592 return -ENXIO;
5593 }
5594
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305595 core_memres = platform_get_resource_byname(pdev,
5596 IORESOURCE_MEM, "core_mem");
5597 bam_memres = platform_get_resource_byname(pdev,
5598 IORESOURCE_MEM, "bam_mem");
5599 dml_memres = platform_get_resource_byname(pdev,
5600 IORESOURCE_MEM, "dml_mem");
5601 core_irqres = platform_get_resource_byname(pdev,
5602 IORESOURCE_IRQ, "core_irq");
5603 bam_irqres = platform_get_resource_byname(pdev,
5604 IORESOURCE_IRQ, "bam_irq");
5605 dmares = platform_get_resource_byname(pdev,
5606 IORESOURCE_DMA, "dma_chnl");
5607 dma_crci_res = platform_get_resource_byname(pdev,
5608 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005610 if (!core_irqres || !core_memres) {
5611 pr_err("%s: Invalid sdcc core resource\n", __func__);
5612 return -ENXIO;
5613 }
5614
5615 /*
5616 * Both BAM and DML memory resource should be preset.
5617 * BAM IRQ resource should also be present.
5618 */
5619 if ((bam_memres && !dml_memres) ||
5620 (!bam_memres && dml_memres) ||
5621 ((bam_memres && dml_memres) && !bam_irqres)) {
5622 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005623 return -ENXIO;
5624 }
5625
5626 /*
5627 * Setup our host structure
5628 */
San Mehat9d2bd732009-09-22 16:44:22 -07005629 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5630 if (!mmc) {
5631 ret = -ENOMEM;
5632 goto out;
5633 }
5634
5635 host = mmc_priv(mmc);
5636 host->pdev_id = pdev->id;
5637 host->plat = plat;
5638 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005639 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305640
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305641 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305642 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005643 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305644 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005646 host->base = ioremap(core_memres->start,
5647 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005648 if (!host->base) {
5649 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305650 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005651 }
5652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005653 host->core_irqres = core_irqres;
5654 host->bam_irqres = bam_irqres;
5655 host->core_memres = core_memres;
5656 host->dml_memres = dml_memres;
5657 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005658 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005659 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005660 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305661 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005663#ifdef CONFIG_MMC_EMBEDDED_SDIO
5664 if (plat->embedded_sdio)
5665 mmc_set_embedded_sdio_data(mmc,
5666 &plat->embedded_sdio->cis,
5667 &plat->embedded_sdio->cccr,
5668 plat->embedded_sdio->funcs,
5669 plat->embedded_sdio->num_funcs);
5670#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005671
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305672 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5673 (unsigned long)host);
5674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005675 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5676 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305677 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005678 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305679 ret = msmsdcc_init_dma(host);
5680 if (ret)
5681 goto ioremap_free;
5682 } else {
5683 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005684 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305685 }
San Mehat9d2bd732009-09-22 16:44:22 -07005686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005687 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305688 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005689 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305690 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5691 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5692 /* Vote for max. clk rate for max. performance */
5693 ret = clk_set_rate(host->bus_clk, INT_MAX);
5694 if (ret)
5695 goto bus_clk_put;
5696 ret = clk_prepare_enable(host->bus_clk);
5697 if (ret)
5698 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005699 }
5700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005701 /*
5702 * Setup main peripheral bus clock
5703 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005704 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005705 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305706 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005707 if (ret)
5708 goto pclk_put;
5709
5710 host->pclk_rate = clk_get_rate(host->pclk);
5711 }
5712
5713 /*
5714 * Setup SDC MMC clock
5715 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005716 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005717 if (IS_ERR(host->clk)) {
5718 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005719 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005720 }
5721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005722 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305723 if (ret) {
5724 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5725 goto clk_put;
5726 }
5727
Asutosh Dasf5298c32012-04-03 14:51:47 +05305728 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005729 if (ret)
5730 goto clk_put;
5731
San Mehat9d2bd732009-09-22 16:44:22 -07005732 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305733 if (!host->clk_rate)
5734 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305735
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305736 set_default_hw_caps(host);
5737
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305738 /*
5739 * Set the register write delay according to min. clock frequency
5740 * supported and update later when the host->clk_rate changes.
5741 */
5742 host->reg_write_delay =
5743 (1 + ((3 * USEC_PER_SEC) /
5744 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005745
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305746 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305747 /* Apply Hard reset to SDCC to put it in power on default state */
5748 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005749
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005750#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305751 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005752 if (host->plat->cpu_dma_latency)
5753 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5754 else
5755 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5756 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305757 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5758
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305759 ret = msmsdcc_msm_bus_register(host);
5760 if (ret)
5761 goto pm_qos_remove;
5762
5763 if (host->msm_bus_vote.client_handle)
5764 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5765 msmsdcc_msm_bus_work);
5766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005767 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005768 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005769 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005770 goto clk_disable;
5771 }
5772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005773
5774 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305775 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005776 /* Initialize SPS */
5777 ret = msmsdcc_sps_init(host);
5778 if (ret)
5779 goto vreg_deinit;
5780 /* Initialize DML */
5781 ret = msmsdcc_dml_init(host);
5782 if (ret)
5783 goto sps_exit;
5784 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305785 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005786
San Mehat9d2bd732009-09-22 16:44:22 -07005787 /*
5788 * Setup MMC host structure
5789 */
5790 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005791 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5792 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005793 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305794 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005796 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5797 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005798 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305799 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305800 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305801 /*
5802 * If we send the CMD23 before multi block write/read command
5803 * then we need not to send CMD12 at the end of the transfer.
5804 * If we don't send the CMD12 then only way to detect the PROG_DONE
5805 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5806 * controller. So let's enable the CMD23 for SDCC4 only.
5807 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305808 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305809 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005811 mmc->caps |= plat->uhs_caps;
Devin Kim9ccbff52012-07-16 20:55:14 -07005812 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005813 /*
5814 * XPC controls the maximum current in the default speed mode of SDXC
5815 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5816 * XPC=1 means 150mA (max.) and speed class is supported.
5817 */
5818 if (plat->xpc_cap)
5819 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5820 MMC_CAP_SET_XPC_180);
5821
Maya Erez231dd082012-11-28 23:55:57 +02005822
5823 /* packed write */
5824 mmc->caps2 |= plat->packed_write;
5825
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305826 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005827 mmc->caps2 |= MMC_CAP2_SANITIZE;
Maya Erezd0ed5ae2012-11-01 21:39:00 +02005828 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Tatyana Brokhman139eabf2012-10-15 22:43:35 +02005829 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Yaniv Gardi14098552012-06-04 10:56:03 +03005830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005831 if (plat->nonremovable)
5832 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005833 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005834
5835 if (plat->is_sdio_al_client)
5836 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005837
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305838 mmc->max_segs = msmsdcc_get_nr_sg(host);
5839 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5840 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005841
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305842 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005843 mmc->max_seg_size = mmc->max_req_size;
5844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005845 writel_relaxed(0, host->base + MMCIMASK0);
5846 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305847 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005848
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005849 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5850 mb();
5851 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005853 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5854 DRIVER_NAME " (cmd)", host);
5855 if (ret)
5856 goto dml_exit;
5857
5858 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5859 DRIVER_NAME " (pio)", host);
5860 if (ret)
5861 goto irq_free;
5862
5863 /*
5864 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5865 * IRQ is un-necessarily being monitored by MPM (Modem power
5866 * management block) during idle-power collapse. The MPM will be
5867 * configured to monitor the DATA1 GPIO line with level-low trigger
5868 * and thus depending on the GPIO status, it prevents TCXO shutdown
5869 * during idle-power collapse.
5870 */
5871 disable_irq(core_irqres->start);
5872 host->sdcc_irq_disabled = 1;
5873
5874 if (plat->sdiowakeup_irq) {
5875 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5876 mmc_hostname(mmc));
5877 ret = request_irq(plat->sdiowakeup_irq,
5878 msmsdcc_platform_sdiowakeup_irq,
5879 IRQF_SHARED | IRQF_TRIGGER_LOW,
5880 DRIVER_NAME "sdiowakeup", host);
5881 if (ret) {
5882 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5883 plat->sdiowakeup_irq, ret);
5884 goto pio_irq_free;
5885 } else {
5886 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305887 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005888 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305889 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005890 }
5891 spin_unlock_irqrestore(&host->lock, flags);
5892 }
5893 }
5894
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305895 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005896 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5897 mmc_hostname(mmc));
5898 }
5899
5900 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5901 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005902 /*
5903 * Setup card detect change
5904 */
5905
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305906 if (!plat->status_gpio)
5907 plat->status_gpio = -ENOENT;
5908 if (!plat->wpswitch_gpio)
5909 plat->wpswitch_gpio = -ENOENT;
5910
5911 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08005912 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005913 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005914 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005915 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005916
Krishna Konda941604a2012-01-10 17:46:34 -08005917 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005918 }
San Mehat9d2bd732009-09-22 16:44:22 -07005919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005920 if (plat->status_irq) {
5921 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005922 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005923 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005924 DRIVER_NAME " (slot)",
5925 host);
5926 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005927 pr_err("Unable to get slot IRQ %d (%d)\n",
5928 plat->status_irq, ret);
5929 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005930 }
5931 } else if (plat->register_status_notify) {
5932 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5933 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005934 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005935 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005936
5937 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005938
5939 ret = pm_runtime_set_active(&(pdev)->dev);
5940 if (ret < 0)
5941 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5942 __func__, ret);
5943 /*
5944 * There is no notion of suspend/resume for SD/MMC/SDIO
5945 * cards. So host can be suspended/resumed with out
5946 * worrying about its children.
5947 */
5948 pm_suspend_ignore_children(&(pdev)->dev, true);
5949
5950 /*
5951 * MMC/SD/SDIO bus suspend/resume operations are defined
5952 * only for the slots that will be used for non-removable
5953 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5954 * defined. Otherwise, they simply become card removal and
5955 * insertion events during suspend and resume respectively.
5956 * Hence, enable run-time PM only for slots for which bus
5957 * suspend/resume operations are defined.
5958 */
5959#ifdef CONFIG_MMC_UNSAFE_RESUME
5960 /*
5961 * If this capability is set, MMC core will enable/disable host
5962 * for every claim/release operation on a host. We use this
5963 * notification to increment/decrement runtime pm usage count.
5964 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005965 pm_runtime_enable(&(pdev)->dev);
5966#else
5967 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005968 pm_runtime_enable(&(pdev)->dev);
5969 }
5970#endif
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305971 host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005972 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5973 (unsigned long)host);
5974
San Mehat9d2bd732009-09-22 16:44:22 -07005975 mmc_add_host(mmc);
5976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005977#ifdef CONFIG_HAS_EARLYSUSPEND
5978 host->early_suspend.suspend = msmsdcc_early_suspend;
5979 host->early_suspend.resume = msmsdcc_late_resume;
5980 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5981 register_early_suspend(&host->early_suspend);
5982#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005983
Krishna Konda25786ec2011-07-25 16:21:36 -07005984 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5985 " dmacrcri %d\n", mmc_hostname(mmc),
5986 (unsigned long long)core_memres->start,
5987 (unsigned int) core_irqres->start,
5988 (unsigned int) plat->status_irq, host->dma.channel,
5989 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005990
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305991 pr_info("%s: Controller capabilities: 0x%.8x\n",
5992 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005993 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5994 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5995 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5996 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5997 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5998 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5999 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6000 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6001 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6002 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6003 host->eject);
6004 pr_info("%s: Power save feature enable = %d\n",
6005 mmc_hostname(mmc), msmsdcc_pwrsave);
6006
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306007 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006008 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006009 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006010 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006011 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006012 mmc_hostname(mmc), host->dma.cmd_busaddr,
6013 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306014 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006015 pr_info("%s: SPS-BAM data transfer mode available\n",
6016 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006017 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006018 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006020#if defined(CONFIG_DEBUG_FS)
6021 msmsdcc_dbg_createhost(host);
6022#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306023
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306024 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6025 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6026 sysfs_attr_init(&host->max_bus_bw.attr);
6027 host->max_bus_bw.attr.name = "max_bus_bw";
6028 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6029 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306030 if (ret)
6031 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306032
6033 if (!plat->status_irq) {
6034 host->polling.show = show_polling;
6035 host->polling.store = store_polling;
6036 sysfs_attr_init(&host->polling.attr);
6037 host->polling.attr.name = "polling";
6038 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6039 ret = device_create_file(&pdev->dev, &host->polling);
6040 if (ret)
6041 goto remove_max_bus_bw_file;
6042 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306043 host->idle_timeout.show = show_idle_timeout;
6044 host->idle_timeout.store = store_idle_timeout;
6045 sysfs_attr_init(&host->idle_timeout.attr);
6046 host->idle_timeout.attr.name = "idle_timeout";
6047 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6048 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6049 if (ret)
6050 goto remove_polling_file;
San Mehat9d2bd732009-09-22 16:44:22 -07006051 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006052
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306053 remove_polling_file:
6054 if (!plat->status_irq)
6055 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306056 remove_max_bus_bw_file:
6057 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006058 platform_irq_free:
6059 del_timer_sync(&host->req_tout_timer);
6060 pm_runtime_disable(&(pdev)->dev);
6061 pm_runtime_set_suspended(&(pdev)->dev);
6062
6063 if (plat->status_irq)
6064 free_irq(plat->status_irq, host);
6065 sdiowakeup_irq_free:
6066 wake_lock_destroy(&host->sdio_suspend_wlock);
6067 if (plat->sdiowakeup_irq)
6068 free_irq(plat->sdiowakeup_irq, host);
6069 pio_irq_free:
6070 if (plat->sdiowakeup_irq)
6071 wake_lock_destroy(&host->sdio_wlock);
6072 free_irq(core_irqres->start, host);
6073 irq_free:
6074 free_irq(core_irqres->start, host);
6075 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306076 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006077 msmsdcc_dml_exit(host);
6078 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306079 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006080 msmsdcc_sps_exit(host);
6081 vreg_deinit:
6082 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006083 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006084 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306085 msmsdcc_msm_bus_unregister(host);
6086 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006087 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306088 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006089 clk_put:
6090 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006091 pclk_disable:
6092 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306093 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006094 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006095 if (!IS_ERR(host->pclk))
6096 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306097 if (!IS_ERR_OR_NULL(host->bus_clk))
6098 clk_disable_unprepare(host->bus_clk);
6099 bus_clk_put:
6100 if (!IS_ERR_OR_NULL(host->bus_clk))
6101 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306102 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103 if (host->dmares)
6104 dma_free_coherent(NULL,
6105 sizeof(struct msmsdcc_nc_dmadata),
6106 host->dma.nc, host->dma.nc_busaddr);
6107 }
6108 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306109 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006110 host_free:
6111 mmc_free_host(mmc);
6112 out:
6113 return ret;
6114}
6115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006116static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006117{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006118 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6119 struct mmc_platform_data *plat;
6120 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006122 if (!mmc)
6123 return -ENXIO;
6124
6125 if (pm_runtime_suspended(&(pdev)->dev))
6126 pm_runtime_resume(&(pdev)->dev);
6127
6128 host = mmc_priv(mmc);
6129
6130 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6131 plat = host->plat;
6132
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306133 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006134 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306135 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306136 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006137
6138 del_timer_sync(&host->req_tout_timer);
6139 tasklet_kill(&host->dma_tlet);
6140 tasklet_kill(&host->sps.tlet);
6141 mmc_remove_host(mmc);
6142
6143 if (plat->status_irq)
6144 free_irq(plat->status_irq, host);
6145
6146 wake_lock_destroy(&host->sdio_suspend_wlock);
6147 if (plat->sdiowakeup_irq) {
6148 wake_lock_destroy(&host->sdio_wlock);
6149 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6150 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006151 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006152
6153 free_irq(host->core_irqres->start, host);
6154 free_irq(host->core_irqres->start, host);
6155
6156 clk_put(host->clk);
6157 if (!IS_ERR(host->pclk))
6158 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306159 if (!IS_ERR_OR_NULL(host->bus_clk))
6160 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006162 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306163 pm_qos_remove_request(&host->pm_qos_req_dma);
6164
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306165 if (host->msm_bus_vote.client_handle) {
6166 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6167 msmsdcc_msm_bus_unregister(host);
6168 }
6169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006170 msmsdcc_vreg_init(host, false);
6171
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306172 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 if (host->dmares)
6174 dma_free_coherent(NULL,
6175 sizeof(struct msmsdcc_nc_dmadata),
6176 host->dma.nc, host->dma.nc_busaddr);
6177 }
6178
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306179 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006180 msmsdcc_dml_exit(host);
6181 msmsdcc_sps_exit(host);
6182 }
6183
6184 iounmap(host->base);
6185 mmc_free_host(mmc);
6186
6187#ifdef CONFIG_HAS_EARLYSUSPEND
6188 unregister_early_suspend(&host->early_suspend);
6189#endif
6190 pm_runtime_disable(&(pdev)->dev);
6191 pm_runtime_set_suspended(&(pdev)->dev);
6192
6193 return 0;
6194}
6195
6196#ifdef CONFIG_MSM_SDIO_AL
6197int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6198{
6199 struct msmsdcc_host *host = mmc_priv(mmc);
6200 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306201 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006202
Asutosh Dasf5298c32012-04-03 14:51:47 +05306203 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204 spin_lock_irqsave(&host->lock, flags);
6205 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6206 enable ? "En" : "Dis");
6207
6208 if (enable) {
6209 if (!host->sdcc_irq_disabled) {
6210 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306211 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006212 host->sdcc_irq_disabled = 1;
6213 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306214 rc = msmsdcc_setup_clocks(host, false);
6215 if (rc)
6216 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006217
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306218 if (host->plat->sdio_lpm_gpio_setup &&
6219 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006220 spin_unlock_irqrestore(&host->lock, flags);
6221 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6222 spin_lock_irqsave(&host->lock, flags);
6223 host->sdio_gpio_lpm = 1;
6224 }
6225
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306226 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006227 msmsdcc_enable_irq_wake(host);
6228 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306229 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006230 }
6231 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306232 rc = msmsdcc_setup_clocks(host, true);
6233 if (rc)
6234 goto out;
6235
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306236 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006237 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306238 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006239 msmsdcc_disable_irq_wake(host);
6240 }
6241
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306242 if (host->plat->sdio_lpm_gpio_setup &&
6243 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006244 spin_unlock_irqrestore(&host->lock, flags);
6245 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6246 spin_lock_irqsave(&host->lock, flags);
6247 host->sdio_gpio_lpm = 0;
6248 }
6249
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306250 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006251 writel_relaxed(host->mci_irqenable,
6252 host->base + MMCIMASK0);
6253 mb();
6254 enable_irq(host->core_irqres->start);
6255 host->sdcc_irq_disabled = 0;
6256 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006257 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306258out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006259 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306260 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306261 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006262}
6263#else
6264int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6265{
6266 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006267}
6268#endif
6269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006270#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306271#ifdef CONFIG_MMC_CLKGATE
6272static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6273{
6274 struct mmc_host *mmc = host->mmc;
6275 unsigned long flags;
6276
6277 mmc_host_clk_hold(mmc);
6278 spin_lock_irqsave(&mmc->clk_lock, flags);
6279 mmc->clk_old = mmc->ios.clock;
6280 mmc->ios.clock = 0;
6281 mmc->clk_gated = true;
6282 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6283 mmc_set_ios(mmc);
6284 mmc_host_clk_release(mmc);
6285}
6286
6287static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6288{
6289 struct mmc_host *mmc = host->mmc;
6290
6291 mmc_host_clk_hold(mmc);
6292 mmc->ios.clock = host->clk_rate;
6293 mmc_set_ios(mmc);
6294 mmc_host_clk_release(mmc);
6295}
6296#else
6297static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6298{
6299 struct mmc_host *mmc = host->mmc;
6300
6301 mmc->ios.clock = 0;
6302 mmc_set_ios(mmc);
6303}
6304
6305static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6306{
6307 struct mmc_host *mmc = host->mmc;
6308
6309 mmc->ios.clock = host->clk_rate;
6310 mmc_set_ios(mmc);
6311}
6312#endif
6313
San Mehat9d2bd732009-09-22 16:44:22 -07006314static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006315msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006316{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006317 struct mmc_host *mmc = dev_get_drvdata(dev);
6318 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006319 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306320 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006321
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306322 if (host->plat->is_sdio_al_client) {
6323 rc = 0;
6324 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006325 }
San Mehat9d2bd732009-09-22 16:44:22 -07006326
Sahitya Tummala7661a452011-07-18 13:28:35 +05306327 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006328 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006329 host->sdcc_suspending = 1;
6330 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006332 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006333 * MMC core thinks that host is disabled by now since
6334 * runtime suspend is scheduled after msmsdcc_disable()
6335 * is called. Thus, MMC core will try to enable the host
6336 * while suspending it. This results in a synchronous
6337 * runtime resume request while in runtime suspending
6338 * context and hence inorder to complete this resume
6339 * requet, it will wait for suspend to be complete,
6340 * but runtime suspend also can not proceed further
6341 * until the host is resumed. Thus, it leads to a hang.
6342 * Hence, increase the pm usage count before suspending
6343 * the host so that any resume requests after this will
6344 * simple become pm usage counter increment operations.
6345 */
6346 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306347 /* If there is pending detect work abort runtime suspend */
6348 if (unlikely(work_busy(&mmc->detect.work)))
6349 rc = -EAGAIN;
6350 else
6351 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006352 pm_runtime_put_noidle(dev);
6353
6354 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306355 spin_lock_irqsave(&host->lock, flags);
6356 host->sdcc_suspended = true;
6357 spin_unlock_irqrestore(&host->lock, flags);
6358 if (mmc->card && mmc_card_sdio(mmc->card) &&
6359 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006360 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306361 * If SDIO function driver doesn't want
6362 * to power off the card, atleast turn off
6363 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006364 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306365 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006366 }
6367 }
6368 host->sdcc_suspending = 0;
6369 mmc->suspend_task = NULL;
6370 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6371 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006372 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306373 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306374out:
6375 /* set bus bandwidth to 0 immediately */
6376 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07006377 return rc;
6378}
6379
6380static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006381msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006382{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006383 struct mmc_host *mmc = dev_get_drvdata(dev);
6384 struct msmsdcc_host *host = mmc_priv(mmc);
6385 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07006386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006387 if (host->plat->is_sdio_al_client)
6388 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07006389
Sahitya Tummala7661a452011-07-18 13:28:35 +05306390 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006391 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306392 if (mmc->card && mmc_card_sdio(mmc->card) &&
6393 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306394 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306395 }
San Mehat9d2bd732009-09-22 16:44:22 -07006396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006397 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006399 /*
6400 * FIXME: Clearing of flags must be handled in clients
6401 * resume handler.
6402 */
6403 spin_lock_irqsave(&host->lock, flags);
6404 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306405 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006406 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006408 /*
6409 * After resuming the host wait for sometime so that
6410 * the SDIO work will be processed.
6411 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306412 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306413 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006414 host->plat->sdiowakeup_irq) &&
6415 wake_lock_active(&host->sdio_wlock))
6416 wake_lock_timeout(&host->sdio_wlock, 1);
6417 }
6418
6419 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006420 }
Subhash Jadavani1371d192012-08-16 18:46:57 +05306421 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306422 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006423 return 0;
6424}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006425
6426static int msmsdcc_runtime_idle(struct device *dev)
6427{
6428 struct mmc_host *mmc = dev_get_drvdata(dev);
6429 struct msmsdcc_host *host = mmc_priv(mmc);
6430
6431 if (host->plat->is_sdio_al_client)
6432 return 0;
6433
6434 /* Idle timeout is not configurable for now */
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306435 pm_schedule_suspend(dev, host->idle_tout_ms);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006436
6437 return -EAGAIN;
6438}
6439
6440static int msmsdcc_pm_suspend(struct device *dev)
6441{
6442 struct mmc_host *mmc = dev_get_drvdata(dev);
6443 struct msmsdcc_host *host = mmc_priv(mmc);
6444 int rc = 0;
6445
6446 if (host->plat->is_sdio_al_client)
6447 return 0;
6448
6449
6450 if (host->plat->status_irq)
6451 disable_irq(host->plat->status_irq);
6452
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006453 if (!pm_runtime_suspended(dev))
6454 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006455
6456 return rc;
6457}
6458
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306459static int msmsdcc_suspend_noirq(struct device *dev)
6460{
6461 struct mmc_host *mmc = dev_get_drvdata(dev);
6462 struct msmsdcc_host *host = mmc_priv(mmc);
6463 int rc = 0;
6464
6465 /*
6466 * After platform suspend there may be active request
6467 * which might have enabled clocks. For example, in SDIO
6468 * case, ksdioirq thread might have scheduled after sdcc
6469 * suspend but before system freeze. In that case abort
6470 * suspend and retry instead of keeping the clocks on
6471 * during suspend and not allowing TCXO.
6472 */
6473
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306474 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306475 pr_warn("%s: clocks are on after suspend, aborting system "
6476 "suspend\n", mmc_hostname(mmc));
6477 rc = -EAGAIN;
6478 }
6479
6480 return rc;
6481}
6482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006483static int msmsdcc_pm_resume(struct device *dev)
6484{
6485 struct mmc_host *mmc = dev_get_drvdata(dev);
6486 struct msmsdcc_host *host = mmc_priv(mmc);
6487 int rc = 0;
6488
6489 if (host->plat->is_sdio_al_client)
6490 return 0;
6491
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006492 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306493 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani1371d192012-08-16 18:46:57 +05306494 /*
6495 * As runtime PM is enabled before calling the device's platform resume
6496 * callback, we use the pm_runtime_suspended API to know if SDCC is
6497 * really runtime suspended or not and set the pending_resume flag only
6498 * if its not runtime suspended.
6499 */
6500 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006501 host->pending_resume = true;
6502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006503 if (host->plat->status_irq) {
6504 msmsdcc_check_status((unsigned long)host);
6505 enable_irq(host->plat->status_irq);
6506 }
6507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006508 return rc;
6509}
6510
Daniel Walker08ecfde2010-06-23 12:32:20 -07006511#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006512static int msmsdcc_runtime_suspend(struct device *dev)
6513{
6514 return 0;
6515}
6516static int msmsdcc_runtime_idle(struct device *dev)
6517{
6518 return 0;
6519}
6520static int msmsdcc_pm_suspend(struct device *dev)
6521{
6522 return 0;
6523}
6524static int msmsdcc_pm_resume(struct device *dev)
6525{
6526 return 0;
6527}
6528static int msmsdcc_suspend_noirq(struct device *dev)
6529{
6530 return 0;
6531}
6532static int msmsdcc_runtime_resume(struct device *dev)
6533{
6534 return 0;
6535}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006536#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006538static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6539 .runtime_suspend = msmsdcc_runtime_suspend,
6540 .runtime_resume = msmsdcc_runtime_resume,
6541 .runtime_idle = msmsdcc_runtime_idle,
6542 .suspend = msmsdcc_pm_suspend,
6543 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306544 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006545};
6546
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306547static const struct of_device_id msmsdcc_dt_match[] = {
6548 {.compatible = "qcom,msm-sdcc"},
6549
6550};
6551MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6552
San Mehat9d2bd732009-09-22 16:44:22 -07006553static struct platform_driver msmsdcc_driver = {
6554 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006555 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006556 .driver = {
6557 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006558 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306559 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006560 },
6561};
6562
6563static int __init msmsdcc_init(void)
6564{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006565#if defined(CONFIG_DEBUG_FS)
6566 int ret = 0;
6567 ret = msmsdcc_dbg_init();
6568 if (ret) {
6569 pr_err("Failed to create debug fs dir \n");
6570 return ret;
6571 }
6572#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006573 return platform_driver_register(&msmsdcc_driver);
6574}
San Mehat9d2bd732009-09-22 16:44:22 -07006575
San Mehat9d2bd732009-09-22 16:44:22 -07006576static void __exit msmsdcc_exit(void)
6577{
6578 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006579
6580#if defined(CONFIG_DEBUG_FS)
6581 debugfs_remove(debugfs_file);
6582 debugfs_remove(debugfs_dir);
6583#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006584}
6585
6586module_init(msmsdcc_init);
6587module_exit(msmsdcc_exit);
6588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006589MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006590MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006591
6592#if defined(CONFIG_DEBUG_FS)
6593
6594static int
6595msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
6596{
6597 file->private_data = inode->i_private;
6598 return 0;
6599}
6600
6601static ssize_t
6602msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
6603 size_t count, loff_t *ppos)
6604{
6605 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08006606 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006607 int max, i;
6608
6609 i = 0;
6610 max = sizeof(buf) - 1;
6611
6612 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
6613 host->curr.cmd, host->curr.data);
6614 if (host->curr.cmd) {
6615 struct mmc_command *cmd = host->curr.cmd;
6616
6617 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
6618 cmd->opcode, cmd->arg, cmd->flags);
6619 }
6620 if (host->curr.data) {
6621 struct mmc_data *data = host->curr.data;
6622 i += scnprintf(buf + i, max - i,
6623 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
6624 data->timeout_ns, data->timeout_clks,
6625 data->blksz, data->blocks, data->error,
6626 data->flags);
6627 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
6628 host->curr.xfer_size, host->curr.xfer_remain,
6629 host->curr.data_xfered, host->dma.sg);
6630 }
6631
6632 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
6633}
6634
6635static const struct file_operations msmsdcc_dbg_state_ops = {
6636 .read = msmsdcc_dbg_state_read,
6637 .open = msmsdcc_dbg_state_open,
6638};
6639
6640static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6641{
6642 if (debugfs_dir) {
6643 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
6644 0644, debugfs_dir, host,
6645 &msmsdcc_dbg_state_ops);
6646 }
6647}
6648
6649static int __init msmsdcc_dbg_init(void)
6650{
6651 int err;
6652
6653 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
6654 if (IS_ERR(debugfs_dir)) {
6655 err = PTR_ERR(debugfs_dir);
6656 debugfs_dir = NULL;
6657 return err;
6658 }
6659
6660 return 0;
6661}
6662#endif