blob: 4f7d4c371f1811b0839e3e3804cbdee2e87737ba [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.
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07006 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
7 *
San Mehat9d2bd732009-09-22 16:44:22 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Based on mmci.c
14 *
15 * Author: San Mehat (san@android.com)
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/init.h>
22#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053023#include <linux/of.h>
Sujit Reddy Thumma38459152012-06-26 00:07:59 +053024#include <linux/of_gpio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070025#include <linux/device.h>
26#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070028#include <linux/delay.h>
29#include <linux/err.h>
30#include <linux/highmem.h>
31#include <linux/log2.h>
32#include <linux/mmc/host.h>
33#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080035#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070036#include <linux/clk.h>
37#include <linux/scatterlist.h>
38#include <linux/platform_device.h>
39#include <linux/dma-mapping.h>
40#include <linux/debugfs.h>
41#include <linux/io.h>
42#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043#include <linux/pm_runtime.h>
44#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053045#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#include <linux/regulator/consumer.h>
47#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070048#include <linux/pm_qos.h>
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -080049#include <linux/iopoll.h>
San Mehat9d2bd732009-09-22 16:44:22 -070050
51#include <asm/cacheflush.h>
52#include <asm/div64.h>
53#include <asm/sizes.h>
54
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070056#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053057#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053060#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053061#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070062
San Mehat9d2bd732009-09-22 16:44:22 -070063#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070065
66#define DRIVER_NAME "msm-sdcc"
67
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068#define DBG(host, fmt, args...) \
69 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
70
71#define IRQ_DEBUG 0
72#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
73#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
74#define SPS_CONS_PERIPHERAL 0
75#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053076/* Use SPS only if transfer size is more than this macro */
77#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053079#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +053080#define INVALID_TUNING_PHASE -1
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082#if defined(CONFIG_DEBUG_FS)
83static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
84static struct dentry *debugfs_dir;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085static int msmsdcc_dbg_init(void);
86#endif
87
Asutosh Dasaccacd42012-03-08 14:33:17 +053088static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
89 *data);
90
Subhash Jadavani8766e352011-11-30 11:30:32 +053091static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070092static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094static struct mmc_command dummy52cmd;
95static struct mmc_request dummy52mrq = {
96 .cmd = &dummy52cmd,
97 .data = NULL,
98 .stop = NULL,
99};
100static struct mmc_command dummy52cmd = {
101 .opcode = SD_IO_RW_DIRECT,
102 .flags = MMC_RSP_PRESENT,
103 .data = NULL,
104 .mrq = &dummy52mrq,
105};
106/*
107 * An array holding the Tuning pattern to compare with when
108 * executing a tuning cycle.
109 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530110static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
112 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
113 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
114 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
115};
San Mehat9d2bd732009-09-22 16:44:22 -0700116
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530117static const u32 tuning_block_128[] = {
118 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
119 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
120 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
121 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
122 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
123 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
124 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
125 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
126};
San Mehat865c8062009-11-13 13:42:06 -0800127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128#if IRQ_DEBUG == 1
129static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
130 "dattimeout", "txunderrun", "rxoverrun",
131 "cmdrespend", "cmdsent", "dataend", NULL,
132 "datablkend", "cmdactive", "txactive",
133 "rxactive", "txhalfempty", "rxhalffull",
134 "txfifofull", "rxfifofull", "txfifoempty",
135 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
136 "sdiointr", "progdone", "atacmdcompl",
137 "sdiointrope", "ccstimeout", NULL, NULL,
138 NULL, NULL, NULL };
139
140static void
141msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800142{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
146 for (i = 0; i < 32; i++) {
147 if (status & (1 << i))
148 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800149 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800151}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152#endif
San Mehat865c8062009-11-13 13:42:06 -0800153
San Mehat9d2bd732009-09-22 16:44:22 -0700154static void
155msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
156 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530157static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530158static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530159static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800160static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800161static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700162static int msmsdcc_runtime_resume(struct device *dev);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530163static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
164 u32 **out_array, int *len, int size);
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/**
Krishna Konda3ca90f02012-08-29 16:29:21 -0700220 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530221 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700222 * 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 */
Krishna Konda3ca90f02012-08-29 16:29:21 -0700230static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530231{
232 int rc;
233
Krishna Konda3ca90f02012-08-29 16:29:21 -0700234 /* Reset and init DML */
235 rc = msmsdcc_dml_init(host);
236 if (rc) {
237 pr_err("%s: msmsdcc_dml_init error=%d\n",
238 mmc_hostname(host->mmc), rc);
239 goto out;
240 }
241
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530242 /* Reset all SDCC BAM pipes */
243 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700244 if (rc) {
245 pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530246 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700247 goto out;
248 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530249
Krishna Konda3ca90f02012-08-29 16:29:21 -0700250 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
251 if (rc) {
252 pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
Krishna Konda5af8f972012-05-14 16:15:24 -0700253 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700254 goto out;
255 }
256
257 /* Reset BAM */
258 rc = sps_device_reset(host->sps.bam_handle);
259 if (rc) {
260 pr_err("%s: sps_device_reset error=%d\n",
261 mmc_hostname(host->mmc), rc);
262 goto out;
Krishna Konda5af8f972012-05-14 16:15:24 -0700263 }
264
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530265 /* Restore all BAM pipes connections */
266 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700267 if (rc) {
268 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530269 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700270 goto out;
271 }
272
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530273 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
274 if (rc)
Krishna Konda3ca90f02012-08-29 16:29:21 -0700275 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530276 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700277 else
278 host->sps.reset_bam = false;
279
280out:
281 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530282}
283
284/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 * Apply soft reset
286 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700287 * 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;
Krishna Kondabb97f922012-10-23 20:41:04 -0700305 uint32_t dll_config = 0;
306
307
308 if (is_sw_reset_save_config_broken(host))
309 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530310
311 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
312 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
313 msmsdcc_sync_reg_wr(host);
314
315 start = ktime_get();
316 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
317 /*
318 * SW reset can take upto 10HCLK + 15MCLK cycles.
319 * Calculating based on min clk rates (hclk = 27MHz,
320 * mclk = 400KHz) it comes to ~40us. Let's poll for
321 * max. 1ms for reset completion.
322 */
323 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
324 pr_err("%s: %s failed\n",
325 mmc_hostname(host->mmc), __func__);
326 BUG();
327 }
328 }
Krishna Kondabb97f922012-10-23 20:41:04 -0700329
330 if (is_sw_reset_save_config_broken(host)) {
331 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
332 mb();
333 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530334 } else {
335 writel_relaxed(0, host->base + MMCICOMMAND);
336 msmsdcc_sync_reg_wr(host);
337 writel_relaxed(0, host->base + MMCIDATACTRL);
338 msmsdcc_sync_reg_wr(host);
339 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530340}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530341
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530342static void msmsdcc_hard_reset(struct msmsdcc_host *host)
343{
344 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530345
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530346 /*
347 * Reset SDCC controller to power on default state.
348 * Don't issue a reset request to clock control block if
349 * SDCC controller itself can support hard reset.
350 */
351 if (is_sw_hard_reset(host)) {
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800352 u32 pwr;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530353
354 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
355 | MCI_SW_RST, host->base + MMCIPOWER);
356 msmsdcc_sync_reg_wr(host);
357
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800358 /*
359 * See comment in msmsdcc_soft_reset() on choosing 1ms
360 * poll timeout.
361 */
362 ret = readl_poll_timeout_noirq(host->base + MMCIPOWER,
363 pwr, !(pwr & MCI_SW_RST), 100, 10);
364
365 if (ret) {
366 pr_err("%s: %s failed (%d)\n",
367 mmc_hostname(host->mmc), __func__, ret);
368 BUG();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530369 }
370 } else {
371 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
372 if (ret)
373 pr_err("%s: Clock assert failed at %u Hz" \
374 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530375 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530376
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530377 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
378 if (ret)
379 pr_err("%s: Clock deassert failed at %u Hz" \
380 " with err %d\n", mmc_hostname(host->mmc),
381 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530382
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530383 mb();
384 /* Give some delay for clock reset to propogate to controller */
385 msmsdcc_delay(host);
386 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530387}
388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
390{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530391 if (is_soft_reset(host)) {
Krishna Konda3ca90f02012-08-29 16:29:21 -0700392 if (is_sps_mode(host))
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530393 /*
Krishna Konda3ca90f02012-08-29 16:29:21 -0700394 * delay the SPS BAM reset in thread context as
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530395 * sps_connect/sps_disconnect APIs can be called
396 * only from non-atomic context.
397 */
Krishna Konda3ca90f02012-08-29 16:29:21 -0700398 host->sps.reset_bam = true;
399
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530400 msmsdcc_soft_reset(host);
401
402 pr_debug("%s: Applied soft reset to Controller\n",
403 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 } else {
Krishna Konda3ca90f02012-08-29 16:29:21 -0700405 /*
406 * When there is a requirement to use this hard reset,
407 * BAM needs to be reconfigured as well by calling
408 * msmsdcc_sps_exit and msmsdcc_sps_init.
409 */
410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 /* Give Clock reset (hard reset) to controller */
412 u32 mci_clk = 0;
413 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414
415 /* Save the controller state */
416 mci_clk = readl_relaxed(host->base + MMCICLOCK);
417 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530418 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530421 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 pr_debug("%s: Controller has been reinitialized\n",
423 mmc_hostname(host->mmc));
424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 /* Restore the contoller state */
426 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530427 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530429 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530431 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530433
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700434 if (host->dummy_52_needed)
435 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436}
437
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530438static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
439{
440 struct mmc_request *mrq = host->curr.mrq;
441
442 if (!mrq || !mrq->cmd || (!mrq->data && !host->pending_dpsm_reset))
443 goto out;
444
445 /*
446 * For CMD24, if auto prog done is not supported defer
447 * dpsm reset until prog done is received. Otherwise,
448 * we poll here unnecessarily as TXACTIVE will not be
449 * deasserted until DAT0 goes high.
450 */
451 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) && !is_auto_prog_done(host)) {
452 host->pending_dpsm_reset = true;
453 goto out;
454 }
455
456 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
457 if (is_wait_for_tx_rx_active(host)) {
458 ktime_t start = ktime_get();
459
460 while (readl_relaxed(host->base + MMCISTATUS) &
461 (MCI_TXACTIVE | MCI_RXACTIVE)) {
462 /*
463 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
464 * cycles (~11us) after data transfer due to clock mux
465 * switching delays. Let's poll for 1ms and panic if
466 * still active.
467 */
468 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
469 pr_err("%s: %s still active\n",
470 mmc_hostname(host->mmc),
471 readl_relaxed(host->base + MMCISTATUS)
472 & MCI_TXACTIVE ? "TX" : "RX");
473 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530474 msmsdcc_reset_and_restore(host);
475 host->pending_dpsm_reset = false;
476 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530477 }
478 }
479 }
480
481 writel_relaxed(0, host->base + MMCIDATACTRL);
482 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
483 host->pending_dpsm_reset = false;
484out:
485 return;
486}
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488static int
San Mehat9d2bd732009-09-22 16:44:22 -0700489msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
490{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 int retval = 0;
492
San Mehat9d2bd732009-09-22 16:44:22 -0700493 BUG_ON(host->curr.data);
494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700496
497 if (mrq->data)
498 mrq->data->bytes_xfered = host->curr.data_xfered;
499 if (mrq->cmd->error == -ETIMEDOUT)
500 mdelay(5);
501
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530502 msmsdcc_reset_dpsm(host);
503
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530504 /* Clear current request information as current request has ended */
505 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
506
San Mehat9d2bd732009-09-22 16:44:22 -0700507 /*
508 * Need to drop the host lock here; mmc_request_done may call
509 * back into the driver...
510 */
511 spin_unlock(&host->lock);
512 mmc_request_done(host->mmc, mrq);
513 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514
515 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700516}
517
518static void
519msmsdcc_stop_data(struct msmsdcc_host *host)
520{
San Mehat9d2bd732009-09-22 16:44:22 -0700521 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530522 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530523 host->curr.wait_for_auto_prog_done = false;
524 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700525}
526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700528{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 return host->core_memres->start + MMCIFIFO;
530}
531
532static inline unsigned int msmsdcc_get_min_sup_clk_rate(
533 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530534
Subhash Jadavanidd432952012-03-28 11:25:56 +0530535static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536{
537 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530538 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530539 udelay(host->reg_write_delay);
540 else if (readl_relaxed(host->base + MCI_STATUS2) &
541 MCI_MCLK_REG_WR_ACTIVE) {
542 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530543
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530544 start = ktime_get();
545 while (readl_relaxed(host->base + MCI_STATUS2) &
546 MCI_MCLK_REG_WR_ACTIVE) {
547 diff = ktime_sub(ktime_get(), start);
548 /* poll for max. 1 ms */
549 if (ktime_to_us(diff) > 1000) {
550 pr_warning("%s: previous reg. write is"
551 " still active\n",
552 mmc_hostname(host->mmc));
553 break;
554 }
555 }
556 }
San Mehat9d2bd732009-09-22 16:44:22 -0700557}
558
Subhash Jadavanidd432952012-03-28 11:25:56 +0530559static inline void msmsdcc_delay(struct msmsdcc_host *host)
560{
561 udelay(host->reg_write_delay);
562
San Mehat9d2bd732009-09-22 16:44:22 -0700563}
564
San Mehat56a8b5b2009-11-21 12:29:46 -0800565static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
567{
568 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530570 /*
571 * As after sending the command, we don't write any of the
572 * controller registers and just wait for the
573 * CMD_RESPOND_END/CMD_SENT/Command failure notication
574 * from Controller.
575 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800577}
578
579static void
580msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
581{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
585 writel_relaxed((unsigned int)host->curr.xfer_size,
586 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530588 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800589
San Mehat6ac9ea62009-12-02 17:24:58 -0800590 if (host->cmd_cmd) {
591 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800593 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800594}
595
San Mehat9d2bd732009-09-22 16:44:22 -0700596static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530597msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700598{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530599 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700600 unsigned long flags;
601 struct mmc_request *mrq;
602
603 spin_lock_irqsave(&host->lock, flags);
604 mrq = host->curr.mrq;
605 BUG_ON(!mrq);
606
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530607 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700608 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700609 goto out;
610 }
611
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530612 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700613 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700615 } else {
616 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530617 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700618 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530619 mmc_hostname(host->mmc), host->dma.result);
620 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700621 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530622 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530623 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 host->dma.err.flush[0], host->dma.err.flush[1],
625 host->dma.err.flush[2], host->dma.err.flush[3],
626 host->dma.err.flush[4],
627 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530628 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700629 if (!mrq->data->error)
630 mrq->data->error = -EIO;
631 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530632 if (!mrq->data->host_cookie)
633 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
634 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 if (host->curr.user_pages) {
637 struct scatterlist *sg = host->dma.sg;
638 int i;
639
640 for (i = 0; i < host->dma.num_ents; i++, sg++)
641 flush_dcache_page(sg_page(sg));
642 }
San Mehat9d2bd732009-09-22 16:44:22 -0700643
San Mehat9d2bd732009-09-22 16:44:22 -0700644 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800645 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700646
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530647 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
648 (host->curr.wait_for_auto_prog_done &&
649 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700650 /*
651 * If we've already gotten our DATAEND / DATABLKEND
652 * for this request, then complete it through here.
653 */
San Mehat9d2bd732009-09-22 16:44:22 -0700654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700656 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 host->curr.xfer_remain -= host->curr.xfer_size;
658 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700659 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700660 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700661 host->dummy_52_sent = 1;
662 msmsdcc_start_command(host, &dummy52cmd,
663 MCI_CPSM_PROGENA);
664 goto out;
665 }
666 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530667 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530668 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700669 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530670 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530672 /*
673 * Clear current request information as current
674 * request has ended
675 */
676 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700677 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678
San Mehat9d2bd732009-09-22 16:44:22 -0700679 mmc_request_done(host->mmc, mrq);
680 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530681 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
682 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700683 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530684 }
San Mehat9d2bd732009-09-22 16:44:22 -0700685 }
686
687out:
688 spin_unlock_irqrestore(&host->lock, flags);
689 return;
690}
691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
693/**
694 * Callback notification from SPS driver
695 *
696 * This callback function gets triggered called from
697 * SPS driver when requested SPS data transfer is
698 * completed.
699 *
700 * SPS driver invokes this callback in BAM irq context so
701 * SDCC driver schedule a tasklet for further processing
702 * this callback notification at later point of time in
703 * tasklet context and immediately returns control back
704 * to SPS driver.
705 *
706 * @nofity - Pointer to sps event notify sturcture
707 *
708 */
709static void
710msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
711{
712 struct msmsdcc_host *host =
713 (struct msmsdcc_host *)
714 ((struct sps_event_notify *)notify)->user;
715
716 host->sps.notify = *notify;
717 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
718 mmc_hostname(host->mmc), __func__, notify->event_id,
719 notify->data.transfer.iovec.addr,
720 notify->data.transfer.iovec.size,
721 notify->data.transfer.iovec.flags);
722 /* Schedule a tasklet for completing data transfer */
723 tasklet_schedule(&host->sps.tlet);
724}
725
726/**
727 * Tasklet handler for processing SPS callback event
728 *
729 * This function processing SPS event notification and
730 * checks if the SPS transfer is completed or not and
731 * then accordingly notifies status to MMC core layer.
732 *
733 * This function is called in tasklet context.
734 *
735 * @data - Pointer to sdcc driver data
736 *
737 */
738static void msmsdcc_sps_complete_tlet(unsigned long data)
739{
740 unsigned long flags;
741 int i, rc;
742 u32 data_xfered = 0;
743 struct mmc_request *mrq;
744 struct sps_iovec iovec;
745 struct sps_pipe *sps_pipe_handle;
746 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
747 struct sps_event_notify *notify = &host->sps.notify;
748
749 spin_lock_irqsave(&host->lock, flags);
750 if (host->sps.dir == DMA_FROM_DEVICE)
751 sps_pipe_handle = host->sps.prod.pipe_handle;
752 else
753 sps_pipe_handle = host->sps.cons.pipe_handle;
754 mrq = host->curr.mrq;
755
756 if (!mrq) {
757 spin_unlock_irqrestore(&host->lock, flags);
758 return;
759 }
760
761 pr_debug("%s: %s: sps event_id=%d\n",
762 mmc_hostname(host->mmc), __func__,
763 notify->event_id);
764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 /*
766 * Got End of transfer event!!! Check if all of the data
767 * has been transferred?
768 */
769 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
770 rc = sps_get_iovec(sps_pipe_handle, &iovec);
771 if (rc) {
772 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
773 mmc_hostname(host->mmc), __func__, rc, i);
774 break;
775 }
776 data_xfered += iovec.size;
777 }
778
779 if (data_xfered == host->curr.xfer_size) {
780 host->curr.data_xfered = host->curr.xfer_size;
781 host->curr.xfer_remain -= host->curr.xfer_size;
782 pr_debug("%s: Data xfer success. data_xfered=0x%x",
783 mmc_hostname(host->mmc),
784 host->curr.xfer_size);
785 } else {
786 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
787 " xfer_size=%d", mmc_hostname(host->mmc),
788 data_xfered, host->curr.xfer_size);
789 msmsdcc_reset_and_restore(host);
790 if (!mrq->data->error)
791 mrq->data->error = -EIO;
792 }
793
794 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530795 if (!mrq->data->host_cookie)
796 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
797 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798 host->sps.sg = NULL;
799 host->sps.busy = 0;
800
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530801 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
802 (host->curr.wait_for_auto_prog_done &&
803 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 /*
805 * If we've already gotten our DATAEND / DATABLKEND
806 * for this request, then complete it through here.
807 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808
809 if (!mrq->data->error) {
810 host->curr.data_xfered = host->curr.xfer_size;
811 host->curr.xfer_remain -= host->curr.xfer_size;
812 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700813 if (host->dummy_52_needed) {
814 mrq->data->bytes_xfered = host->curr.data_xfered;
815 host->dummy_52_sent = 1;
816 msmsdcc_start_command(host, &dummy52cmd,
817 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700818 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700819 return;
820 }
821 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530822 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530823 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530825 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530827 /*
828 * Clear current request information as current
829 * request has ended
830 */
831 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832 spin_unlock_irqrestore(&host->lock, flags);
833
834 mmc_request_done(host->mmc, mrq);
835 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530836 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
837 || !mrq->sbc)) {
838 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839 }
840 }
841 spin_unlock_irqrestore(&host->lock, flags);
842}
843
844/**
845 * Exit from current SPS data transfer
846 *
847 * This function exits from current SPS data transfer.
848 *
849 * This function should be called when error condition
850 * is encountered during data transfer.
851 *
852 * @host - Pointer to sdcc host structure
853 *
854 */
855static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
856{
857 struct mmc_request *mrq;
858
859 mrq = host->curr.mrq;
860 BUG_ON(!mrq);
861
862 msmsdcc_reset_and_restore(host);
863 if (!mrq->data->error)
864 mrq->data->error = -EIO;
865
866 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530867 if (!mrq->data->host_cookie)
868 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
869 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870
871 host->sps.sg = NULL;
872 host->sps.busy = 0;
873 if (host->curr.data)
874 msmsdcc_stop_data(host);
875
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530876 if (!mrq->data->stop || mrq->cmd->error ||
877 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530879 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
880 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881 msmsdcc_start_command(host, mrq->data->stop, 0);
882
883}
884#else
885static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
886static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
887static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
888#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
889
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530890static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530892static void
893msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
894 unsigned int result,
895 struct msm_dmov_errdata *err)
896{
897 struct msmsdcc_dma_data *dma_data =
898 container_of(cmd, struct msmsdcc_dma_data, hdr);
899 struct msmsdcc_host *host = dma_data->host;
900
901 dma_data->result = result;
902 if (err)
903 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
904
905 tasklet_schedule(&host->dma_tlet);
906}
907
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530908static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
909 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700910{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530911 bool ret = true;
912 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700913
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530914 if (host->enforce_pio_mode) {
915 ret = false;
916 goto out;
917 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530918 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530919 /*
920 * BAM Mode: Fall back on PIO if size is less
921 * than or equal to SPS_MIN_XFER_SIZE bytes.
922 */
923 if (xfer_size <= SPS_MIN_XFER_SIZE)
924 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530925 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530926 /*
927 * ADM Mode: Fall back on PIO if size is less than FIFO size
928 * or not integer multiple of FIFO size
929 */
930 if (xfer_size % MCI_FIFOSIZE)
931 ret = false;
932 } else {
933 /* PIO Mode */
934 ret = false;
935 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530936 out:
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530937 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700938}
939
940static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
941{
942 struct msmsdcc_nc_dmadata *nc;
943 dmov_box *box;
944 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700945 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530946 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700947 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530948 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700949
Krishna Konda25786ec2011-07-25 16:21:36 -0700950 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700952
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530953 BUG_ON((host->pdev->id < 1) || (host->pdev->id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700954
955 host->dma.sg = data->sg;
956 host->dma.num_ents = data->sg_len;
957
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530958 /* Prevent memory corruption */
959 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800960
San Mehat9d2bd732009-09-22 16:44:22 -0700961 nc = host->dma.nc;
962
San Mehat9d2bd732009-09-22 16:44:22 -0700963 if (data->flags & MMC_DATA_READ)
964 host->dma.dir = DMA_FROM_DEVICE;
965 else
966 host->dma.dir = DMA_TO_DEVICE;
967
Asutosh Dasaccacd42012-03-08 14:33:17 +0530968 if (!data->host_cookie) {
969 n = msmsdcc_prep_xfer(host, data);
970 if (unlikely(n < 0)) {
971 host->dma.sg = NULL;
972 host->dma.num_ents = 0;
973 return -ENOMEM;
974 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800975 }
San Mehat9d2bd732009-09-22 16:44:22 -0700976
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530977 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
978 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700979 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530980 for (i = 0; i < host->dma.num_ents; i++) {
981 len = sg_dma_len(sg);
982 offset = 0;
983
984 do {
985 /* Check if we can do DMA */
986 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
987 err = -ENOTSUPP;
988 goto unmap;
989 }
990
991 box->cmd = CMD_MODE_BOX;
992
993 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
994 len = MMC_MAX_DMA_BOX_LENGTH;
995 len -= len % data->blksz;
996 }
997 rows = (len % MCI_FIFOSIZE) ?
998 (len / MCI_FIFOSIZE) + 1 :
999 (len / MCI_FIFOSIZE);
1000
1001 if (data->flags & MMC_DATA_READ) {
1002 box->src_row_addr = msmsdcc_fifo_addr(host);
1003 box->dst_row_addr = sg_dma_address(sg) + offset;
1004 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1005 (MCI_FIFOSIZE);
1006 box->row_offset = MCI_FIFOSIZE;
1007 box->num_rows = rows * ((1 << 16) + 1);
1008 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
1009 } else {
1010 box->src_row_addr = sg_dma_address(sg) + offset;
1011 box->dst_row_addr = msmsdcc_fifo_addr(host);
1012 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1013 (MCI_FIFOSIZE);
1014 box->row_offset = (MCI_FIFOSIZE << 16);
1015 box->num_rows = rows * ((1 << 16) + 1);
1016 box->cmd |= CMD_DST_CRCI(host->dma.crci);
1017 }
1018
1019 offset += len;
1020 len = sg_dma_len(sg) - offset;
1021 box++;
1022 box_cmd_cnt++;
1023 } while (len);
1024 sg++;
1025 }
1026 /* Mark last command */
1027 box--;
1028 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001029
1030 /* location of command block must be 64 bit aligned */
1031 BUG_ON(host->dma.cmd_busaddr & 0x07);
1032
1033 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1034 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1035 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1036 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1037
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301038 /* Flush all data to memory before starting dma */
1039 mb();
1040
1041unmap:
1042 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301043 if (!data->host_cookie)
1044 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1045 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301046 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1047 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001048 }
1049
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301050 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001051}
1052
Asutosh Dasaccacd42012-03-08 14:33:17 +05301053static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1054 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001055{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301056 int rc = 0;
1057 unsigned int dir;
1058
1059 /* Prevent memory corruption */
1060 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1061
1062 if (data->flags & MMC_DATA_READ)
1063 dir = DMA_FROM_DEVICE;
1064 else
1065 dir = DMA_TO_DEVICE;
1066
1067 /* Make sg buffers DMA ready */
1068 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1069 dir);
1070
1071 if (unlikely(rc != data->sg_len)) {
1072 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1073 mmc_hostname(host->mmc), rc);
1074 rc = -ENOMEM;
1075 goto dma_map_err;
1076 }
1077
1078 pr_debug("%s: %s: %s: sg_len=%d\n",
1079 mmc_hostname(host->mmc), __func__,
1080 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1081 data->sg_len);
1082
1083 goto out;
1084
1085dma_map_err:
1086 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1087 data->flags);
1088out:
1089 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001090}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1092/**
1093 * Submits data transfer request to SPS driver
1094 *
1095 * This function make sg (scatter gather) data buffers
1096 * DMA ready and then submits them to SPS driver for
1097 * transfer.
1098 *
1099 * @host - Pointer to sdcc host structure
1100 * @data - Pointer to mmc_data structure
1101 *
1102 * @return 0 if success else negative value
1103 */
1104static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301105 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001106{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 int rc = 0;
1108 u32 flags;
1109 int i;
1110 u32 addr, len, data_cnt;
1111 struct scatterlist *sg = data->sg;
1112 struct sps_pipe *sps_pipe_handle;
1113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 host->sps.sg = data->sg;
1115 host->sps.num_ents = data->sg_len;
1116 host->sps.xfer_req_cnt = 0;
1117 if (data->flags & MMC_DATA_READ) {
1118 host->sps.dir = DMA_FROM_DEVICE;
1119 sps_pipe_handle = host->sps.prod.pipe_handle;
1120 } else {
1121 host->sps.dir = DMA_TO_DEVICE;
1122 sps_pipe_handle = host->sps.cons.pipe_handle;
1123 }
1124
Asutosh Dasaccacd42012-03-08 14:33:17 +05301125 if (!data->host_cookie) {
1126 rc = msmsdcc_prep_xfer(host, data);
1127 if (unlikely(rc < 0)) {
1128 host->dma.sg = NULL;
1129 host->dma.num_ents = 0;
1130 goto out;
1131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 }
1133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 for (i = 0; i < data->sg_len; i++) {
1135 /*
1136 * Check if this is the last buffer to transfer?
1137 * If yes then set the INT and EOT flags.
1138 */
1139 len = sg_dma_len(sg);
1140 addr = sg_dma_address(sg);
1141 flags = 0;
1142 while (len > 0) {
1143 if (len > SPS_MAX_DESC_SIZE) {
1144 data_cnt = SPS_MAX_DESC_SIZE;
1145 } else {
1146 data_cnt = len;
1147 if (i == data->sg_len - 1)
1148 flags = SPS_IOVEC_FLAG_INT |
1149 SPS_IOVEC_FLAG_EOT;
1150 }
1151 rc = sps_transfer_one(sps_pipe_handle, addr,
1152 data_cnt, host, flags);
1153 if (rc) {
1154 pr_err("%s: sps_transfer_one() error! rc=%d,"
1155 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1156 mmc_hostname(host->mmc), rc,
1157 (u32)sps_pipe_handle, (u32)sg, i);
1158 goto dma_map_err;
1159 }
1160 addr += data_cnt;
1161 len -= data_cnt;
1162 host->sps.xfer_req_cnt++;
1163 }
1164 sg++;
1165 }
1166 goto out;
1167
1168dma_map_err:
1169 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301170 if (!data->host_cookie)
1171 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1172 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173out:
1174 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001175}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176#else
1177static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1178 struct mmc_data *data) { return 0; }
1179#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001180
1181static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001182msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1183 struct mmc_command *cmd, u32 *c)
1184{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301185 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 cmd->opcode, cmd->arg, cmd->flags);
1187
San Mehat56a8b5b2009-11-21 12:29:46 -08001188 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1189
1190 if (cmd->flags & MMC_RSP_PRESENT) {
1191 if (cmd->flags & MMC_RSP_136)
1192 *c |= MCI_CPSM_LONGRSP;
1193 *c |= MCI_CPSM_RESPONSE;
1194 }
1195
1196 if (/*interrupt*/0)
1197 *c |= MCI_CPSM_INTERRUPT;
1198
Asutosh Das05049132012-05-09 12:38:15 +05301199 /* DAT_CMD bit should be set for all ADTC */
1200 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001201 *c |= MCI_CSPM_DATCMD;
1202
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301203 /* Check if AUTO CMD19/CMD21 is required or not? */
1204 if (host->tuning_needed &&
1205 (host->en_auto_cmd19 || host->en_auto_cmd21)) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301206 /*
1207 * For open ended block read operation (without CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301208 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1209 * the READ command.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301210 * For close ended block read operation (with CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301211 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1212 * CMD23.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301213 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301214 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1215 host->curr.mrq->cmd->opcode ==
1216 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301217 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301218 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1219 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301220 msmsdcc_enable_cdr_cm_sdc4_dll(host);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05301221 if (host->en_auto_cmd19 &&
1222 host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
1223 *c |= MCI_CSPM_AUTO_CMD19;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301224 else if (host->en_auto_cmd21 &&
1225 host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
1226 *c |= MCI_CSPM_AUTO_CMD21;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301227 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 }
1229
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301230 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1231 writel_relaxed((readl_relaxed(host->base +
1232 MCI_DLL_CONFIG) | MCI_CDR_EN),
1233 host->base + MCI_DLL_CONFIG);
1234 else
1235 /* Clear CDR_EN bit for non read operations */
1236 writel_relaxed((readl_relaxed(host->base +
1237 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1238 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301239
Sujit Reddy Thumma02868752012-06-25 17:22:56 +05301240 if (((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) ||
1241 (cmd->opcode == MMC_SEND_STATUS &&
1242 !(cmd->flags & MMC_CMD_ADTC))) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301243 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301245 }
1246
San Mehat56a8b5b2009-11-21 12:29:46 -08001247 if (cmd == cmd->mrq->stop)
1248 *c |= MCI_CSPM_MCIABORT;
1249
San Mehat56a8b5b2009-11-21 12:29:46 -08001250 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301251 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001253 }
1254 host->curr.cmd = cmd;
1255}
1256
1257static void
1258msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1259 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001260{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301261 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001262 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001264 unsigned int pio_irqmask = 0;
1265
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301266 BUG_ON(!data->sg);
1267 BUG_ON(!data->sg_len);
1268
San Mehat9d2bd732009-09-22 16:44:22 -07001269 host->curr.data = data;
1270 host->curr.xfer_size = data->blksz * data->blocks;
1271 host->curr.xfer_remain = host->curr.xfer_size;
1272 host->curr.data_xfered = 0;
1273 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301274 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001275
San Mehat9d2bd732009-09-22 16:44:22 -07001276 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1277
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301278 if (host->curr.wait_for_auto_prog_done)
1279 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001280
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301281 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301282 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301284 } else if (is_sps_mode(host)) {
Krishna Konda7a05d532012-08-19 11:16:39 -07001285 if (!msmsdcc_sps_start_xfer(host, data)) {
1286 /* Now kick start DML transfer */
1287 mb();
1288 msmsdcc_dml_start_xfer(host, data);
1289 datactrl |= MCI_DPSM_DMAENABLE;
1290 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 }
1292 }
1293 }
1294
1295 /* Is data transfer in PIO mode required? */
1296 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001297 if (data->flags & MMC_DATA_READ) {
1298 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1299 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1300 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1301 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1303 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001304
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001305 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001306 }
1307
1308 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301309 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301310 else if (host->curr.use_wr_data_pend)
1311 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001312
San Mehat56a8b5b2009-11-21 12:29:46 -08001313 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001315 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301316 WARN(!timeout,
1317 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1318 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001319
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301320 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 /* Use ADM (Application Data Mover) HW for Data transfer */
1322 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001323 host->cmd_timeout = timeout;
1324 host->cmd_pio_irqmask = pio_irqmask;
1325 host->cmd_datactrl = datactrl;
1326 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1329 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001330 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001331
1332 if (cmd) {
1333 msmsdcc_start_command_deferred(host, cmd, &c);
1334 host->cmd_c = c;
1335 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1337 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1338 host->base + MMCIMASK0);
1339 mb();
1340 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001341 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1348 (~(MCI_IRQ_PIO))) | pio_irqmask,
1349 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001351
1352 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301353 /* Delay between data/command */
1354 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001355 /* Daisy-chain the command if requested */
1356 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301357 } else {
1358 /*
1359 * We don't need delay after writing to DATA_CTRL
1360 * register if we are not writing to CMD register
1361 * immediately after this. As we already have delay
1362 * before sending the command, we just need mb() here.
1363 */
1364 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001365 }
San Mehat9d2bd732009-09-22 16:44:22 -07001366 }
1367}
1368
1369static void
1370msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1371{
San Mehat56a8b5b2009-11-21 12:29:46 -08001372 msmsdcc_start_command_deferred(host, cmd, &c);
1373 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001374}
1375
1376static void
1377msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1378 unsigned int status)
1379{
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301380 if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
1381 u32 opcode = data->mrq->cmd->opcode;
1382
1383 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1384 || (opcode == MMC_BUS_TEST_R) ||
1385 (host->tuning_in_progress &&
1386 (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
1387 opcode == MMC_SEND_TUNING_BLOCK)))) {
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301388 /* Execute full tuning in case of CRC/timeout errors */
1389 host->saved_tuning_phase = INVALID_TUNING_PHASE;
1390
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301391 if (status & MCI_DATACRCFAIL) {
1392 pr_err("%s: Data CRC error\n",
1393 mmc_hostname(host->mmc));
1394 pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
1395 pr_err("%s: blksz %d, blocks %d\n", __func__,
1396 data->blksz, data->blocks);
1397 } else {
1398 pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
1399 mmc_hostname(host->mmc), opcode,
1400 (readl_relaxed(host->base
1401 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
1402 msmsdcc_dump_sdcc_state(host);
1403 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 }
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301405
1406 /*
1407 * CRC is optional for the bus test commands, not all
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 * cards respond back with CRC. However controller
1409 * waits for the CRC and times out. Hence ignore the
1410 * data timeouts during the Bustest.
1411 */
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301412 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1413 || (opcode == MMC_BUS_TEST_R))) {
1414 if (status & MCI_DATACRCFAIL)
1415 data->error = -EILSEQ;
1416 else
1417 data->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 }
San Mehat9d2bd732009-09-22 16:44:22 -07001419 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001420 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001421 data->error = -EIO;
1422 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001423 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001424 data->error = -EIO;
1425 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001426 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001428 data->error = -EIO;
1429 }
San Mehat9d2bd732009-09-22 16:44:22 -07001430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001432 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 host->dummy_52_needed = 0;
1434}
San Mehat9d2bd732009-09-22 16:44:22 -07001435
1436static int
1437msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1438{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001440 uint32_t *ptr = (uint32_t *) buffer;
1441 int count = 0;
1442
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301443 if (remain % 4)
1444 remain = ((remain >> 2) + 1) << 2;
1445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1447
1448 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001449 ptr++;
1450 count += sizeof(uint32_t);
1451
1452 remain -= sizeof(uint32_t);
1453 if (remain == 0)
1454 break;
1455 }
1456 return count;
1457}
1458
1459static int
1460msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001462{
1463 void __iomem *base = host->base;
1464 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 while (readl_relaxed(base + MMCISTATUS) &
1468 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1469 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001470
San Mehat9d2bd732009-09-22 16:44:22 -07001471 count = min(remain, maxcnt);
1472
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301473 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1474 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001475 ptr += count;
1476 remain -= count;
1477
1478 if (remain == 0)
1479 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 }
1481 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001482
1483 return ptr - buffer;
1484}
1485
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001486/*
1487 * Copy up to a word (4 bytes) between a scatterlist
1488 * and a temporary bounce buffer when the word lies across
1489 * two pages. The temporary buffer can then be read to/
1490 * written from the FIFO once.
1491 */
1492static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001493{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001494 struct msmsdcc_pio_data *pio = &host->pio;
1495 unsigned int bytes_avail;
1496
1497 if (host->curr.data->flags & MMC_DATA_READ)
1498 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1499 pio->bounce_buf_len);
1500 else
1501 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1502 pio->bounce_buf_len);
1503
1504 while (pio->bounce_buf_len != 4) {
1505 if (!sg_miter_next(&pio->sg_miter))
1506 break;
1507 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1508 4 - pio->bounce_buf_len);
1509 if (host->curr.data->flags & MMC_DATA_READ)
1510 memcpy(pio->sg_miter.addr,
1511 &pio->bounce_buf[pio->bounce_buf_len],
1512 bytes_avail);
1513 else
1514 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1515 pio->sg_miter.addr, bytes_avail);
1516
1517 pio->sg_miter.consumed = bytes_avail;
1518 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001519 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001520}
1521
1522/*
1523 * Use sg_miter_next to return as many 4-byte aligned
1524 * chunks as possible, using a temporary 4 byte buffer
1525 * for alignment if necessary
1526 */
1527static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1528{
1529 struct msmsdcc_pio_data *pio = &host->pio;
1530 unsigned int length, rlength;
1531 char *buffer;
1532
1533 if (!sg_miter_next(&pio->sg_miter))
1534 return 0;
1535
1536 buffer = pio->sg_miter.addr;
1537 length = pio->sg_miter.length;
1538
1539 if (length < host->curr.xfer_remain) {
1540 rlength = round_down(length, 4);
1541 if (rlength) {
1542 /*
1543 * We have a 4-byte aligned chunk.
1544 * The rounding will be reflected by
1545 * a call to msmsdcc_sg_consumed
1546 */
1547 length = rlength;
1548 goto sg_next_end;
1549 }
1550 /*
1551 * We have a length less than 4 bytes. Check to
1552 * see if more buffer is available, and combine
1553 * to make 4 bytes if possible.
1554 */
1555 pio->bounce_buf_len = length;
1556 memset(pio->bounce_buf, 0, 4);
1557
1558 /*
1559 * On a read, get 4 bytes from FIFO, and distribute
1560 * (4-bouce_buf_len) bytes into consecutive
1561 * sgl buffers when msmsdcc_sg_consumed is called
1562 */
1563 if (host->curr.data->flags & MMC_DATA_READ) {
1564 buffer = pio->bounce_buf;
1565 length = 4;
1566 goto sg_next_end;
1567 } else {
1568 _msmsdcc_sg_consume_word(host);
1569 buffer = pio->bounce_buf;
1570 length = pio->bounce_buf_len;
1571 }
1572 }
1573
1574sg_next_end:
1575 *buf = buffer;
1576 *len = length;
1577 return 1;
1578}
1579
1580/*
1581 * Update sg_miter.consumed based on how many bytes were
1582 * consumed. If the bounce buffer was used to read from FIFO,
1583 * redistribute into sgls.
1584 */
1585static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1586 unsigned int length)
1587{
1588 struct msmsdcc_pio_data *pio = &host->pio;
1589
1590 if (host->curr.data->flags & MMC_DATA_READ) {
1591 if (length > pio->sg_miter.consumed)
1592 /*
1593 * consumed 4 bytes, but sgl
1594 * describes < 4 bytes
1595 */
1596 _msmsdcc_sg_consume_word(host);
1597 else
1598 pio->sg_miter.consumed = length;
1599 } else
1600 if (length < pio->sg_miter.consumed)
1601 pio->sg_miter.consumed = length;
1602}
1603
1604static void msmsdcc_sg_start(struct msmsdcc_host *host)
1605{
1606 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1607
1608 host->pio.bounce_buf_len = 0;
1609
1610 if (host->curr.data->flags & MMC_DATA_READ)
1611 sg_miter_flags |= SG_MITER_TO_SG;
1612 else
1613 sg_miter_flags |= SG_MITER_FROM_SG;
1614
1615 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1616 host->curr.data->sg_len, sg_miter_flags);
1617}
1618
1619static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1620{
1621 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001622}
1623
San Mehat1cd22962010-02-03 12:59:29 -08001624static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001625msmsdcc_pio_irq(int irq, void *dev_id)
1626{
1627 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001629 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001630 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001631 unsigned int remain;
1632 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001633
Murali Palnati36448a42011-09-02 15:06:18 +05301634 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301639 (MCI_IRQ_PIO)) == 0) {
1640 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301641 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301642 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643#if IRQ_DEBUG
1644 msmsdcc_print_status(host, "irq1-r", status);
1645#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001646 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001647
1648 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001649 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1652 | MCI_RXDATAAVLBL)))
1653 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001654
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001655 if (!msmsdcc_sg_next(host, &buffer, &remain))
1656 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001657
San Mehat9d2bd732009-09-22 16:44:22 -07001658 len = 0;
1659 if (status & MCI_RXACTIVE)
1660 len = msmsdcc_pio_read(host, buffer, remain);
1661 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001663
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301664 /* len might have aligned to 32bits above */
1665 if (len > remain)
1666 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001667
San Mehat9d2bd732009-09-22 16:44:22 -07001668 host->curr.xfer_remain -= len;
1669 host->curr.data_xfered += len;
1670 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001671 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673 if (remain) /* Done with this page? */
1674 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001675
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001677 } while (1);
1678
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001679 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001680 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1683 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1684 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1685 host->base + MMCIMASK0);
1686 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301687 /*
1688 * back to back write to MASK0 register don't need
1689 * synchronization delay.
1690 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1692 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1693 }
1694 mb();
1695 } else if (!host->curr.xfer_remain) {
1696 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1697 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1698 mb();
1699 }
San Mehat9d2bd732009-09-22 16:44:22 -07001700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001702
1703 return IRQ_HANDLED;
1704}
1705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706static void
1707msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1708
1709static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1710 struct mmc_data *data)
1711{
1712 u32 loop_cnt = 0;
1713
1714 /*
1715 * For read commands with data less than fifo size, it is possible to
1716 * get DATAEND first and RXDATA_AVAIL might be set later because of
1717 * synchronization delay through the asynchronous RX FIFO. Thus, for
1718 * such cases, even after DATAEND interrupt is received software
1719 * should poll for RXDATA_AVAIL until the requested data is read out
1720 * of FIFO. This change is needed to get around this abnormal but
1721 * sometimes expected behavior of SDCC3 controller.
1722 *
1723 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1724 * after the data is loaded into RX FIFO. This would amount to less
1725 * than a microsecond and thus looping for 1000 times is good enough
1726 * for that delay.
1727 */
1728 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1729 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1730 spin_unlock(&host->lock);
1731 msmsdcc_pio_irq(1, host);
1732 spin_lock(&host->lock);
1733 }
1734 }
1735 if (loop_cnt == 1000) {
1736 pr_info("%s: Timed out while polling for Rx Data\n",
1737 mmc_hostname(host->mmc));
1738 data->error = -ETIMEDOUT;
1739 msmsdcc_reset_and_restore(host);
1740 }
1741}
1742
San Mehat9d2bd732009-09-22 16:44:22 -07001743static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1744{
1745 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001746
1747 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301748 if (mmc_resp_type(cmd))
1749 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1750 /*
1751 * Read rest of the response registers only if
1752 * long response is expected for this command
1753 */
1754 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1755 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1756 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1757 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1758 }
San Mehat9d2bd732009-09-22 16:44:22 -07001759
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301761 pr_debug("%s: CMD%d: Command timeout\n",
1762 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001763 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301765 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301766 pr_err("%s: CMD%d: Command CRC error\n",
1767 mmc_hostname(host->mmc), cmd->opcode);
1768 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301769 /* Execute full tuning in case of CRC errors */
1770 host->saved_tuning_phase = INVALID_TUNING_PHASE;
San Mehat9d2bd732009-09-22 16:44:22 -07001771 cmd->error = -EILSEQ;
1772 }
1773
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301774 if (!cmd->error) {
1775 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1776 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1777 mod_timer(&host->req_tout_timer, (jiffies +
1778 msecs_to_jiffies(host->curr.req_tout_ms)));
1779 }
1780 }
1781
San Mehat9d2bd732009-09-22 16:44:22 -07001782 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301784 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001785 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301787 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 /* Stop current SPS transfer */
1789 msmsdcc_sps_exit_curr_xfer(host);
1790 }
San Mehat9d2bd732009-09-22 16:44:22 -07001791 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301792 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001793 msmsdcc_stop_data(host);
1794 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301795 } else { /* host->data == NULL */
1796 if (!cmd->error && host->prog_enable) {
1797 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301799 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301801 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301802 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301803 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301804 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001805 if (host->dummy_52_needed)
1806 host->dummy_52_needed = 0;
1807 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301809 msmsdcc_request_end(host, cmd->mrq);
1810 }
1811 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301812 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301813 if (cmd == host->curr.mrq->sbc)
1814 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1815 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1816 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301817 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001818 }
1819}
1820
San Mehat9d2bd732009-09-22 16:44:22 -07001821static irqreturn_t
1822msmsdcc_irq(int irq, void *dev_id)
1823{
1824 struct msmsdcc_host *host = dev_id;
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301825 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001826 u32 status;
1827 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001829
1830 spin_lock(&host->lock);
1831
1832 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 struct mmc_command *cmd;
1834 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 if (timer) {
1837 timer = 0;
1838 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001839 }
San Mehat9d2bd732009-09-22 16:44:22 -07001840
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301841 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 pr_debug("%s: %s: SDIO async irq received\n",
1843 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301844
1845 /*
1846 * Only async interrupt can come when clocks are off,
1847 * disable further interrupts and enable them when
1848 * clocks are on.
1849 */
1850 if (!host->sdcc_irq_disabled) {
1851 disable_irq_nosync(irq);
1852 host->sdcc_irq_disabled = 1;
1853 }
1854
1855 /*
1856 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1857 * will take care of signaling sdio irq during
1858 * mmc_sdio_resume().
1859 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301860 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301861 /*
1862 * This is a wakeup interrupt so hold wakelock
1863 * until SDCC resume is handled.
1864 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301866 } else {
Oluwafemi Adeyemi3975e5d2012-10-11 15:30:14 -07001867 if (mmc->card && !mmc_card_sdio(mmc->card)) {
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301868 WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1869 mmc_hostname(mmc));
1870 ret = 1;
1871 break;
1872 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301873 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301874 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301875 spin_lock(&host->lock);
1876 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301877 ret = 1;
1878 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001879 }
1880
1881 status = readl_relaxed(host->base + MMCISTATUS);
1882
1883 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1884 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001885 break;
1886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887#if IRQ_DEBUG
1888 msmsdcc_print_status(host, "irq0-r", status);
1889#endif
1890 status &= readl_relaxed(host->base + MMCIMASK0);
1891 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301892 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301893 if (host->clk_rate <=
1894 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301895 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896#if IRQ_DEBUG
1897 msmsdcc_print_status(host, "irq0-p", status);
1898#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900 if (status & MCI_SDIOINTROPE) {
Oluwafemi Adeyemi3975e5d2012-10-11 15:30:14 -07001901 if (mmc->card && !mmc_card_sdio(mmc->card)) {
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301902 WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
1903 mmc_hostname(mmc));
1904 ret = 1;
1905 break;
1906 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907 if (host->sdcc_suspending)
1908 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301909 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301911 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001912 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001913 data = host->curr.data;
1914
1915 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1917 MCI_CMDTIMEOUT)) {
1918 if (status & MCI_CMDTIMEOUT)
1919 pr_debug("%s: dummy CMD52 timeout\n",
1920 mmc_hostname(host->mmc));
1921 if (status & MCI_CMDCRCFAIL)
1922 pr_debug("%s: dummy CMD52 CRC failed\n",
1923 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001924 host->dummy_52_sent = 0;
1925 host->dummy_52_needed = 0;
1926 if (data) {
1927 msmsdcc_stop_data(host);
1928 msmsdcc_request_end(host, data->mrq);
1929 }
1930 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 spin_unlock(&host->lock);
1932 return IRQ_HANDLED;
1933 }
1934 break;
1935 }
1936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937 /*
1938 * Check for proper command response
1939 */
1940 cmd = host->curr.cmd;
1941 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1942 MCI_CMDTIMEOUT | MCI_PROGDONE |
1943 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1944 msmsdcc_do_cmdirq(host, status);
1945 }
1946
Sathish Ambley081d7842011-11-29 11:19:41 -08001947 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 /* Check for data errors */
1949 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1950 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1951 msmsdcc_data_err(host, data, status);
1952 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301953 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001954 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301955 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 /* Stop current SPS transfer */
1957 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301958 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001959 msmsdcc_reset_and_restore(host);
1960 if (host->curr.data)
1961 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301962 if (!data->stop || (host->curr.mrq->sbc
1963 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001964 timer |=
1965 msmsdcc_request_end(host,
1966 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301967 else if ((host->curr.mrq->sbc
1968 && data->error) ||
1969 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001970 msmsdcc_start_command(host,
1971 data->stop,
1972 0);
1973 timer = 1;
1974 }
1975 }
1976 }
1977
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301978 /* Check for prog done */
1979 if (host->curr.wait_for_auto_prog_done &&
1980 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301981 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 /* Check for data done */
1984 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1985 host->curr.got_dataend = 1;
1986
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301987 if (host->curr.got_dataend &&
1988 (!host->curr.wait_for_auto_prog_done ||
1989 (host->curr.wait_for_auto_prog_done &&
1990 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 /*
1992 * If DMA is still in progress, we complete
1993 * via the completion handler
1994 */
1995 if (!host->dma.busy && !host->sps.busy) {
1996 /*
1997 * There appears to be an issue in the
1998 * controller where if you request a
1999 * small block transfer (< fifo size),
2000 * you may get your DATAEND/DATABLKEND
2001 * irq without the PIO data irq.
2002 *
2003 * Check to see if theres still data
2004 * to be read, and simulate a PIO irq.
2005 */
2006 if (data->flags & MMC_DATA_READ)
2007 msmsdcc_wait_for_rxdata(host,
2008 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 if (!data->error) {
2010 host->curr.data_xfered =
2011 host->curr.xfer_size;
2012 host->curr.xfer_remain -=
2013 host->curr.xfer_size;
2014 }
2015
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002016 if (!host->dummy_52_needed) {
2017 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302018 if (!data->stop ||
2019 (host->curr.mrq->sbc
2020 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002021 msmsdcc_request_end(
2022 host,
2023 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302024 else if ((host->curr.mrq->sbc
2025 && data->error) ||
2026 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002027 msmsdcc_start_command(
2028 host,
2029 data->stop, 0);
2030 timer = 1;
2031 }
2032 } else {
2033 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002035 &dummy52cmd,
2036 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 }
2038 }
2039 }
2040 }
2041
San Mehat9d2bd732009-09-22 16:44:22 -07002042 ret = 1;
2043 } while (status);
2044
2045 spin_unlock(&host->lock);
2046
San Mehat9d2bd732009-09-22 16:44:22 -07002047 return IRQ_RETVAL(ret);
2048}
2049
2050static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302051msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2052 bool is_first_request)
2053{
2054 struct msmsdcc_host *host = mmc_priv(mmc);
2055 struct mmc_data *data = mrq->data;
2056 int rc = 0;
2057
2058 if (unlikely(!data)) {
2059 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2060 __func__);
2061 return;
2062 }
2063 if (unlikely(data->host_cookie)) {
2064 /* Very wrong */
2065 data->host_cookie = 0;
2066 pr_err("%s: %s Request reposted for prepare\n",
2067 mmc_hostname(mmc), __func__);
2068 return;
2069 }
2070
2071 if (!msmsdcc_is_dma_possible(host, data))
2072 return;
2073
2074 rc = msmsdcc_prep_xfer(host, data);
2075 if (unlikely(rc < 0)) {
2076 data->host_cookie = 0;
2077 return;
2078 }
2079
2080 data->host_cookie = 1;
2081}
2082
2083static void
2084msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2085{
2086 struct msmsdcc_host *host = mmc_priv(mmc);
2087 unsigned int dir;
2088 struct mmc_data *data = mrq->data;
2089
2090 if (unlikely(!data)) {
2091 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2092 __func__);
2093 return;
2094 }
2095 if (data->flags & MMC_DATA_READ)
2096 dir = DMA_FROM_DEVICE;
2097 else
2098 dir = DMA_TO_DEVICE;
2099
2100 if (data->host_cookie)
2101 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2102 data->sg_len, dir);
2103
2104 data->host_cookie = 0;
2105}
2106
2107static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2109{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302110 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302112 if ((mrq->data->flags & MMC_DATA_READ) ||
2113 host->curr.use_wr_data_pend)
2114 msmsdcc_start_data(host, mrq->data,
2115 mrq->sbc ? mrq->sbc : mrq->cmd,
2116 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302117 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302118 msmsdcc_start_command(host,
2119 mrq->sbc ? mrq->sbc : mrq->cmd,
2120 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 } else {
2122 msmsdcc_start_command(host, mrq->cmd, 0);
2123 }
2124}
2125
2126static void
San Mehat9d2bd732009-09-22 16:44:22 -07002127msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2128{
2129 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302130 unsigned long flags;
Krishna Konda3ca90f02012-08-29 16:29:21 -07002131 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 /*
2134 * Get the SDIO AL client out of LPM.
2135 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002136 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 if (host->plat->is_sdio_al_client)
2138 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002139
Krishna Konda3ca90f02012-08-29 16:29:21 -07002140 /* check if sps bam needs to be reset */
2141 if (is_sps_mode(host) && host->sps.reset_bam) {
2142 while (retries) {
2143 if (!msmsdcc_bam_dml_reset_and_restore(host))
2144 break;
2145 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2146 mmc_hostname(host->mmc), --retries);
2147 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302148 }
San Mehat9d2bd732009-09-22 16:44:22 -07002149
2150 spin_lock_irqsave(&host->lock, flags);
2151
San Mehat9d2bd732009-09-22 16:44:22 -07002152 if (host->eject) {
2153 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
2154 mrq->cmd->error = 0;
2155 mrq->data->bytes_xfered = mrq->data->blksz *
2156 mrq->data->blocks;
2157 } else
2158 mrq->cmd->error = -ENOMEDIUM;
2159
2160 spin_unlock_irqrestore(&host->lock, flags);
2161 mmc_request_done(mmc, mrq);
2162 return;
2163 }
2164
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302165 /*
subhashjf181c292012-05-02 13:07:40 +05302166 * Don't start the request if SDCC is not in proper state to handle it
2167 */
Krishna Konda3ca90f02012-08-29 16:29:21 -07002168 if (!host->pwr || !atomic_read(&host->clks_on) ||
2169 host->sdcc_irq_disabled ||
2170 host->sps.reset_bam) {
subhashjf181c292012-05-02 13:07:40 +05302171 WARN(1, "%s: %s: SDCC is in bad state. don't process"
2172 " new request (CMD%d)\n", mmc_hostname(host->mmc),
2173 __func__, mrq->cmd->opcode);
2174 msmsdcc_dump_sdcc_state(host);
2175 mrq->cmd->error = -EIO;
2176 if (mrq->data) {
2177 mrq->data->error = -EIO;
2178 mrq->data->bytes_xfered = 0;
2179 }
2180 spin_unlock_irqrestore(&host->lock, flags);
2181 mmc_request_done(mmc, mrq);
2182 return;
2183 }
2184
2185 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2186 " other request (CMD%d) is in progress\n",
2187 mmc_hostname(host->mmc), __func__,
2188 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2189
2190 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302191 * Set timeout value to 10 secs (or more in case of buggy cards)
2192 */
2193 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302194 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302195 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302196 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302197 /*
2198 * Kick the software request timeout timer here with the timeout
2199 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302200 */
2201 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302202 (jiffies +
2203 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002204
San Mehat9d2bd732009-09-22 16:44:22 -07002205 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302206 if (mrq->sbc) {
2207 mrq->sbc->mrq = mrq;
2208 mrq->sbc->data = mrq->data;
2209 }
2210
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302211 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302212 if (is_auto_prog_done(host)) {
Sujit Reddy Thummab8e83692012-07-17 15:08:13 +05302213 /*
2214 * Auto-prog done will be enabled for following cases:
2215 * mrq->sbc | mrq->stop
2216 * _____________|________________
2217 * True | Don't care
2218 * False | False (CMD24, ACMD25 use case)
2219 */
2220 if (mrq->sbc || !mrq->stop)
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302221 host->curr.wait_for_auto_prog_done = true;
2222 } else {
2223 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2224 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225 host->dummy_52_needed = 1;
2226 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302227
Subhash Jadavanif5277752011-10-12 16:47:52 +05302228 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
Subhash Jadavanicf58e6f2012-10-05 20:45:54 +05302229 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
2230 ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
2231 is_data_pend_for_cmd53(host)))
Subhash Jadavanif5277752011-10-12 16:47:52 +05302232 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002233 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302234
Subhash Jadavanif5277752011-10-12 16:47:52 +05302235 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302236
San Mehat9d2bd732009-09-22 16:44:22 -07002237 spin_unlock_irqrestore(&host->lock, flags);
2238}
2239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2241 int min_uV, int max_uV)
2242{
2243 int rc = 0;
2244
2245 if (vreg->set_voltage_sup) {
2246 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2247 if (rc) {
2248 pr_err("%s: regulator_set_voltage(%s) failed."
2249 " min_uV=%d, max_uV=%d, rc=%d\n",
2250 __func__, vreg->name, min_uV, max_uV, rc);
2251 }
2252 }
2253
2254 return rc;
2255}
2256
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302257static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2258{
2259 int rc = 0;
2260
2261 rc = regulator_get_voltage(vreg->reg);
2262 if (rc < 0)
2263 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2264 __func__, vreg->name, rc);
2265
2266 return rc;
2267}
2268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2270 int uA_load)
2271{
2272 int rc = 0;
2273
Krishna Kondafea60182011-11-01 16:01:34 -07002274 /* regulators that do not support regulator_set_voltage also
2275 do not support regulator_set_optimum_mode */
2276 if (vreg->set_voltage_sup) {
2277 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2278 if (rc < 0)
2279 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2280 "uA_load=%d) failed. rc=%d\n", __func__,
2281 vreg->name, uA_load, rc);
2282 else
2283 /* regulator_set_optimum_mode() can return non zero
2284 * value even for success case.
2285 */
2286 rc = 0;
2287 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288
2289 return rc;
2290}
2291
2292static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2293 struct device *dev)
2294{
2295 int rc = 0;
2296
2297 /* check if regulator is already initialized? */
2298 if (vreg->reg)
2299 goto out;
2300
2301 /* Get the regulator handle */
2302 vreg->reg = regulator_get(dev, vreg->name);
2303 if (IS_ERR(vreg->reg)) {
2304 rc = PTR_ERR(vreg->reg);
2305 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2306 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002307 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002308 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002309
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302310 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002311 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302312 /* sanity check */
2313 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2314 pr_err("%s: %s invalid constraints specified\n",
2315 __func__, vreg->name);
2316 rc = -EINVAL;
2317 }
2318 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320out:
2321 return rc;
2322}
2323
2324static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2325{
2326 if (vreg->reg)
2327 regulator_put(vreg->reg);
2328}
2329
2330/* This init function should be called only once for each SDCC slot */
2331static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2332{
2333 int rc = 0;
2334 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302335 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 struct device *dev = mmc_dev(host->mmc);
2337
2338 curr_slot = host->plat->vreg_data;
2339 if (!curr_slot)
2340 goto out;
2341
2342 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302343 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344
2345 if (is_init) {
2346 /*
2347 * Get the regulator handle from voltage regulator framework
2348 * and then try to set the voltage level for the regulator
2349 */
2350 if (curr_vdd_reg) {
2351 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2352 if (rc)
2353 goto out;
2354 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302355 if (curr_vdd_io_reg) {
2356 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 if (rc)
2358 goto vdd_reg_deinit;
2359 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002360 rc = msmsdcc_vreg_reset(host);
2361 if (rc)
2362 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302363 host->pdev->id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 goto out;
2365 } else {
2366 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302367 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302369vdd_io_reg_deinit:
2370 if (curr_vdd_io_reg)
2371 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372vdd_reg_deinit:
2373 if (curr_vdd_reg)
2374 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2375out:
2376 return rc;
2377}
2378
2379static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2380{
2381 int rc = 0;
2382
Subhash Jadavanicc922692011-08-01 23:05:01 +05302383 /* Put regulator in HPM (high power mode) */
2384 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2385 if (rc < 0)
2386 goto out;
2387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388 if (!vreg->is_enabled) {
2389 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302390 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2391 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 if (rc)
2393 goto out;
2394
2395 rc = regulator_enable(vreg->reg);
2396 if (rc) {
2397 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2398 __func__, vreg->name, rc);
2399 goto out;
2400 }
2401 vreg->is_enabled = true;
2402 }
2403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404out:
2405 return rc;
2406}
2407
Krishna Konda3c4142d2012-06-27 11:01:56 -07002408static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409{
2410 int rc = 0;
2411
2412 /* Never disable regulator marked as always_on */
2413 if (vreg->is_enabled && !vreg->always_on) {
2414 rc = regulator_disable(vreg->reg);
2415 if (rc) {
2416 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2417 __func__, vreg->name, rc);
2418 goto out;
2419 }
2420 vreg->is_enabled = false;
2421
2422 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2423 if (rc < 0)
2424 goto out;
2425
2426 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302427 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 if (rc)
2429 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002430 } else if (vreg->is_enabled && vreg->always_on) {
2431 if (!is_init && vreg->lpm_sup) {
2432 /* Put always_on regulator in LPM (low power mode) */
2433 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2434 if (rc < 0)
2435 goto out;
2436 } else if (is_init && vreg->reset_at_init) {
2437 /**
2438 * The regulator might not actually be disabled if it
2439 * is shared and in use by other drivers.
2440 */
2441 rc = regulator_disable(vreg->reg);
2442 if (rc) {
2443 pr_err("%s: regulator_disable(%s) failed at " \
2444 "bootup. rc=%d\n", __func__,
2445 vreg->name, rc);
2446 goto out;
2447 }
2448 vreg->is_enabled = false;
2449 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 }
2451out:
2452 return rc;
2453}
2454
Krishna Konda3c4142d2012-06-27 11:01:56 -07002455static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2456 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457{
2458 int rc = 0, i;
2459 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302460 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
2462 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302463 if (!curr_slot) {
Asutosh Dasd5902bf2012-10-03 18:28:20 +05302464 pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
2465 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302467 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468
Subhash Jadavani937c7502012-06-01 15:34:46 +05302469 vreg_table[0] = curr_slot->vdd_data;
2470 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471
2472 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2473 if (vreg_table[i]) {
2474 if (enable)
2475 rc = msmsdcc_vreg_enable(vreg_table[i]);
2476 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002477 rc = msmsdcc_vreg_disable(vreg_table[i],
2478 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 if (rc)
2480 goto out;
2481 }
2482 }
2483out:
2484 return rc;
2485}
2486
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002487/*
2488 * Reset vreg by ensuring it is off during probe. A call
2489 * to enable vreg is needed to balance disable vreg
2490 */
2491static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2492{
2493 int rc;
2494
Krishna Konda3c4142d2012-06-27 11:01:56 -07002495 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002496 if (rc)
2497 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002498 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002499 return rc;
2500}
2501
Subhash Jadavani937c7502012-06-01 15:34:46 +05302502enum vdd_io_level {
2503 /* set vdd_io_data->low_vol_level */
2504 VDD_IO_LOW,
2505 /* set vdd_io_data->high_vol_level */
2506 VDD_IO_HIGH,
2507 /*
2508 * set whatever there in voltage_level (third argument) of
2509 * msmsdcc_set_vdd_io_vol() function.
2510 */
2511 VDD_IO_SET_LEVEL,
2512};
2513
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302514/*
2515 * This function returns the current VDD IO voltage level.
2516 * Returns negative value if it fails to read the voltage level
2517 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2518 * regulator were not defined for host.
2519 */
2520static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2521{
2522 int rc = 0;
2523
2524 if (host->plat->vreg_data) {
2525 struct msm_mmc_reg_data *io_reg =
2526 host->plat->vreg_data->vdd_io_data;
2527
2528 /*
2529 * If vdd_io is not defined, then we can consider that
2530 * IO voltage is same as VDD.
2531 */
2532 if (!io_reg)
2533 io_reg = host->plat->vreg_data->vdd_data;
2534
2535 if (io_reg && io_reg->is_enabled)
2536 rc = msmsdcc_vreg_get_voltage(io_reg);
2537 }
2538
2539 return rc;
2540}
2541
2542/*
2543 * This function updates the IO pad power switch bit in MCI_CLK register
2544 * based on currrent IO pad voltage level.
2545 * NOTE: This function assumes that host lock was not taken by caller.
2546 */
2547static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2548{
2549 int rc = 0;
2550 unsigned long flags;
2551
2552 if (!is_io_pad_pwr_switch(host))
2553 return;
2554
2555 rc = msmsdcc_get_vdd_io_vol(host);
2556
2557 spin_lock_irqsave(&host->lock, flags);
2558 /*
2559 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2560 * the SDCC instances support the dual voltage pads.
2561 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2562 * bit before using the pads in 1.8V mode.
2563 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2564 * IO_PAD_PWR_SWITCH bit is a don't care.
2565 * But we don't have an option to know (by reading some SDCC register)
2566 * that a particular SDCC instance supports dual voltage pads or not,
2567 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2568 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2569 * is anyway ignored.
2570 */
2571 if (rc > 0 && rc < 2700000)
2572 host->io_pad_pwr_switch = 1;
2573 else
2574 host->io_pad_pwr_switch = 0;
2575
2576 if (atomic_read(&host->clks_on)) {
2577 if (host->io_pad_pwr_switch)
2578 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2579 IO_PAD_PWR_SWITCH),
2580 host->base + MMCICLOCK);
2581 else
2582 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2583 ~IO_PAD_PWR_SWITCH),
2584 host->base + MMCICLOCK);
2585 msmsdcc_sync_reg_wr(host);
2586 }
2587 spin_unlock_irqrestore(&host->lock, flags);
2588}
2589
Subhash Jadavani937c7502012-06-01 15:34:46 +05302590static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2591 enum vdd_io_level level,
2592 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593{
2594 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302595 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596
2597 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302598 struct msm_mmc_reg_data *vdd_io_reg =
2599 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600
Subhash Jadavani937c7502012-06-01 15:34:46 +05302601 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2602 switch (level) {
2603 case VDD_IO_LOW:
2604 set_level = vdd_io_reg->low_vol_level;
2605 break;
2606 case VDD_IO_HIGH:
2607 set_level = vdd_io_reg->high_vol_level;
2608 break;
2609 case VDD_IO_SET_LEVEL:
2610 set_level = voltage_level;
2611 break;
2612 default:
2613 pr_err("%s: %s: invalid argument level = %d",
2614 mmc_hostname(host->mmc), __func__,
2615 level);
2616 rc = -EINVAL;
2617 goto out;
2618 }
2619 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2620 set_level, set_level);
2621 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 }
2623
Subhash Jadavani937c7502012-06-01 15:34:46 +05302624out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302625 return rc;
2626}
2627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2629{
2630 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2631 return 1;
2632 return 0;
2633}
2634
Asutosh Dasf5298c32012-04-03 14:51:47 +05302635/*
2636 * Any function calling msmsdcc_setup_clocks must
2637 * acquire clk_mutex. May sleep.
2638 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302639static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302641 int rc = 0;
2642
2643 if (enable && !atomic_read(&host->clks_on)) {
2644 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2645 rc = clk_prepare_enable(host->bus_clk);
2646 if (rc) {
2647 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2648 mmc_hostname(host->mmc), __func__, rc);
2649 goto out;
2650 }
2651 }
2652 if (!IS_ERR(host->pclk)) {
2653 rc = clk_prepare_enable(host->pclk);
2654 if (rc) {
2655 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2656 mmc_hostname(host->mmc), __func__, rc);
2657 goto disable_bus;
2658 }
2659 }
2660 rc = clk_prepare_enable(host->clk);
2661 if (rc) {
2662 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2663 mmc_hostname(host->mmc), __func__, rc);
2664 goto disable_pclk;
2665 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302666 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302667 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302668 atomic_set(&host->clks_on, 1);
2669 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302670 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302671 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302672 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002673 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302674 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302675 if (!IS_ERR_OR_NULL(host->bus_clk))
2676 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302677 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302679 goto out;
2680
2681disable_pclk:
2682 if (!IS_ERR_OR_NULL(host->pclk))
2683 clk_disable_unprepare(host->pclk);
2684disable_bus:
2685 if (!IS_ERR_OR_NULL(host->bus_clk))
2686 clk_disable_unprepare(host->bus_clk);
2687out:
2688 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689}
2690
2691static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2692 unsigned int req_clk)
2693{
2694 unsigned int sel_clk = -1;
2695
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302696 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2697 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2698 goto out;
2699 }
2700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2702 unsigned char cnt;
2703
2704 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2705 if (host->plat->sup_clk_table[cnt] > req_clk)
2706 break;
2707 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2708 sel_clk = host->plat->sup_clk_table[cnt];
2709 break;
2710 } else
2711 sel_clk = host->plat->sup_clk_table[cnt];
2712 }
2713 } else {
2714 if ((req_clk < host->plat->msmsdcc_fmax) &&
2715 (req_clk > host->plat->msmsdcc_fmid))
2716 sel_clk = host->plat->msmsdcc_fmid;
2717 else
2718 sel_clk = req_clk;
2719 }
2720
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302721out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 return sel_clk;
2723}
2724
2725static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2726 struct msmsdcc_host *host)
2727{
2728 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2729 return host->plat->sup_clk_table[0];
2730 else
2731 return host->plat->msmsdcc_fmin;
2732}
2733
2734static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2735 struct msmsdcc_host *host)
2736{
2737 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2738 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2739 else
2740 return host->plat->msmsdcc_fmax;
2741}
2742
2743static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302744{
2745 struct msm_mmc_gpio_data *curr;
2746 int i, rc = 0;
2747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302749 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302750 if (!gpio_is_valid(curr->gpio[i].no)) {
2751 rc = -EINVAL;
2752 pr_err("%s: Invalid gpio = %d\n",
2753 mmc_hostname(host->mmc), curr->gpio[i].no);
2754 goto free_gpios;
2755 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302756 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002757 if (curr->gpio[i].is_always_on &&
2758 curr->gpio[i].is_enabled)
2759 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302760 rc = gpio_request(curr->gpio[i].no,
2761 curr->gpio[i].name);
2762 if (rc) {
2763 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2764 mmc_hostname(host->mmc),
2765 curr->gpio[i].no,
2766 curr->gpio[i].name, rc);
2767 goto free_gpios;
2768 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302770 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 if (curr->gpio[i].is_always_on)
2772 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302773 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302775 }
2776 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302778
2779free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302780 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302781 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782 curr->gpio[i].is_enabled = false;
2783 }
2784out:
2785 return rc;
2786}
2787
2788static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2789{
2790 struct msm_mmc_pad_data *curr;
2791 int i;
2792
2793 curr = host->plat->pin_data->pad_data;
2794 for (i = 0; i < curr->drv->size; i++) {
2795 if (enable)
2796 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2797 curr->drv->on[i].val);
2798 else
2799 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2800 curr->drv->off[i].val);
2801 }
2802
2803 for (i = 0; i < curr->pull->size; i++) {
2804 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002805 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 curr->pull->on[i].val);
2807 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002808 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809 curr->pull->off[i].val);
2810 }
2811
2812 return 0;
2813}
2814
2815static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2816{
2817 int rc = 0;
2818
2819 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2820 return 0;
2821
2822 if (host->plat->pin_data->is_gpio)
2823 rc = msmsdcc_setup_gpio(host, enable);
2824 else
2825 rc = msmsdcc_setup_pad(host, enable);
2826
2827 if (!rc)
2828 host->plat->pin_data->cfg_sts = enable;
2829
2830 return rc;
2831}
2832
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302833static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2834 unsigned mode)
2835{
2836 int ret = 0;
2837 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2838
2839 if (!pin)
2840 return 0;
2841
2842 switch (mode) {
2843 case SDC_DAT1_DISABLE:
2844 ret = msm_mpm_enable_pin(pin, 0);
2845 break;
2846 case SDC_DAT1_ENABLE:
2847 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2848 ret = msm_mpm_enable_pin(pin, 1);
2849 break;
2850 case SDC_DAT1_ENWAKE:
2851 ret = msm_mpm_set_pin_wake(pin, 1);
2852 break;
2853 case SDC_DAT1_DISWAKE:
2854 ret = msm_mpm_set_pin_wake(pin, 0);
2855 break;
2856 default:
2857 ret = -EINVAL;
2858 break;
2859 }
2860
2861 return ret;
2862}
2863
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302864static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2865{
2866 u32 pwr = 0;
2867 int ret = 0;
2868 struct mmc_host *mmc = host->mmc;
2869
2870 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2871 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2872 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002873 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302874
2875 if (ret) {
2876 pr_err("%s: Failed to setup voltage regulators\n",
2877 mmc_hostname(host->mmc));
2878 goto out;
2879 }
2880
2881 switch (ios->power_mode) {
2882 case MMC_POWER_OFF:
2883 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302884 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302885 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302886 * If VDD IO rail is always on, set low voltage for VDD
2887 * IO rail when slot is not in use (like when card is not
2888 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302889 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302890 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302891 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302892 msmsdcc_setup_pins(host, false);
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05302893 /*
2894 * Reset the mask to prevent hitting any pending interrupts
2895 * after powering up the card again.
2896 */
2897 if (atomic_read(&host->clks_on)) {
2898 writel_relaxed(0, host->base + MMCIMASK0);
2899 mb();
2900 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302901 break;
2902 case MMC_POWER_UP:
2903 /* writing PWR_UP bit is redundant */
2904 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302905 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302906
Subhash Jadavani937c7502012-06-01 15:34:46 +05302907 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302908 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302909 msmsdcc_setup_pins(host, true);
2910 break;
2911 case MMC_POWER_ON:
2912 pwr = MCI_PWR_ON;
2913 break;
2914 }
2915
2916out:
2917 return pwr;
2918}
2919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2921{
2922 unsigned int wakeup_irq;
2923
2924 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2925 host->plat->sdiowakeup_irq :
2926 host->core_irqres->start;
2927
2928 if (!host->irq_wake_enabled) {
2929 enable_irq_wake(wakeup_irq);
2930 host->irq_wake_enabled = true;
2931 }
2932}
2933
2934static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2935{
2936 unsigned int wakeup_irq;
2937
2938 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2939 host->plat->sdiowakeup_irq :
2940 host->core_irqres->start;
2941
2942 if (host->irq_wake_enabled) {
2943 disable_irq_wake(wakeup_irq);
2944 host->irq_wake_enabled = false;
2945 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302946}
2947
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302948/* Returns required bandwidth in Bytes per Sec */
2949static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2950 struct mmc_ios *ios)
2951{
2952 unsigned int bw;
2953
2954 bw = host->clk_rate;
2955 /*
2956 * For DDR mode, SDCC controller clock will be at
2957 * the double rate than the actual clock that goes to card.
2958 */
2959 if (ios->bus_width == MMC_BUS_WIDTH_4)
2960 bw /= 2;
2961 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2962 bw /= 8;
2963
2964 return bw;
2965}
2966
2967static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2968 unsigned int bw)
2969{
2970 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2971 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2972 int i;
2973
2974 if (host->msm_bus_vote.is_max_bw_needed && bw)
2975 return host->msm_bus_vote.max_bw_vote;
2976
2977 for (i = 0; i < size; i++) {
2978 if (bw <= table[i])
2979 break;
2980 }
2981
2982 if (i && (i == size))
2983 i--;
2984
2985 return i;
2986}
2987
2988static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2989{
2990 int rc = 0;
2991 struct msm_bus_scale_pdata *use_cases;
2992
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302993 if (host->pdev->dev.of_node) {
2994 struct msm_mmc_bus_voting_data *data;
2995 struct device *dev = &host->pdev->dev;
2996
2997 data = devm_kzalloc(dev,
2998 sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
2999 if (!data) {
3000 dev_err(&host->pdev->dev,
3001 "%s: failed to allocate memory\n", __func__);
3002 rc = -ENOMEM;
3003 goto out;
3004 }
3005
3006 rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
3007 &data->bw_vecs, &data->bw_vecs_size, 0);
3008 if (!rc) {
3009 data->use_cases = msm_bus_cl_get_pdata(host->pdev);
3010 host->plat->msm_bus_voting_data = data;
3011 }
3012 }
3013
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303014 if (host->plat->msm_bus_voting_data &&
3015 host->plat->msm_bus_voting_data->use_cases &&
3016 host->plat->msm_bus_voting_data->bw_vecs &&
3017 host->plat->msm_bus_voting_data->bw_vecs_size) {
3018 use_cases = host->plat->msm_bus_voting_data->use_cases;
3019 host->msm_bus_vote.client_handle =
3020 msm_bus_scale_register_client(use_cases);
3021 } else {
3022 return 0;
3023 }
3024
3025 if (!host->msm_bus_vote.client_handle) {
3026 pr_err("%s: msm_bus_scale_register_client() failed\n",
3027 mmc_hostname(host->mmc));
3028 rc = -EFAULT;
3029 } else {
3030 /* cache the vote index for minimum and maximum bandwidth */
3031 host->msm_bus_vote.min_bw_vote =
3032 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3033 host->msm_bus_vote.max_bw_vote =
3034 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3035 }
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303036out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303037 return rc;
3038}
3039
3040static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3041{
3042 if (host->msm_bus_vote.client_handle)
3043 msm_bus_scale_unregister_client(
3044 host->msm_bus_vote.client_handle);
3045}
3046
3047/*
3048 * This function must be called with host lock acquired.
3049 * Caller of this function should also ensure that msm bus client
3050 * handle is not null.
3051 */
3052static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3053 int vote,
3054 unsigned long flags)
3055{
3056 int rc = 0;
3057
3058 if (vote != host->msm_bus_vote.curr_vote) {
3059 spin_unlock_irqrestore(&host->lock, flags);
3060 rc = msm_bus_scale_client_update_request(
3061 host->msm_bus_vote.client_handle, vote);
3062 if (rc)
3063 pr_err("%s: msm_bus_scale_client_update_request() failed."
3064 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3065 mmc_hostname(host->mmc),
3066 host->msm_bus_vote.client_handle, vote, rc);
3067 spin_lock_irqsave(&host->lock, flags);
3068 if (!rc)
3069 host->msm_bus_vote.curr_vote = vote;
3070 }
3071
3072 return rc;
3073}
3074
3075/*
3076 * Internal work. Work to set 0 bandwidth for msm bus.
3077 */
3078static void msmsdcc_msm_bus_work(struct work_struct *work)
3079{
3080 struct msmsdcc_host *host = container_of(work,
3081 struct msmsdcc_host,
3082 msm_bus_vote.vote_work.work);
3083 unsigned long flags;
3084
3085 if (!host->msm_bus_vote.client_handle)
3086 return;
3087
3088 spin_lock_irqsave(&host->lock, flags);
3089 /* don't vote for 0 bandwidth if any request is in progress */
3090 if (!host->curr.mrq)
3091 msmsdcc_msm_bus_set_vote(host,
3092 host->msm_bus_vote.min_bw_vote, flags);
3093 else
3094 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3095 " bus voting to 0 bandwidth\n",
3096 mmc_hostname(host->mmc), __func__);
3097 spin_unlock_irqrestore(&host->lock, flags);
3098}
3099
3100/*
3101 * This function cancels any scheduled delayed work
3102 * and sets the bus vote based on ios argument.
3103 * If "ios" argument is NULL, bandwidth required is 0 else
3104 * calculate the bandwidth based on ios parameters.
3105 */
3106static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3107 struct msmsdcc_host *host,
3108 struct mmc_ios *ios)
3109{
3110 unsigned long flags;
3111 unsigned int bw;
3112 int vote;
3113
3114 if (!host->msm_bus_vote.client_handle)
3115 return;
3116
3117 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3118
3119 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3120 spin_lock_irqsave(&host->lock, flags);
3121 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3122 msmsdcc_msm_bus_set_vote(host, vote, flags);
3123 spin_unlock_irqrestore(&host->lock, flags);
3124}
3125
3126/* This function queues a work which will set the bandwidth requiement to 0 */
3127static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3128{
3129 unsigned long flags;
3130
3131 if (!host->msm_bus_vote.client_handle)
3132 return;
3133
3134 spin_lock_irqsave(&host->lock, flags);
3135 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3136 queue_delayed_work(system_nrt_wq,
3137 &host->msm_bus_vote.vote_work,
3138 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3139 spin_unlock_irqrestore(&host->lock, flags);
3140}
3141
San Mehat9d2bd732009-09-22 16:44:22 -07003142static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303143msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3144{
3145 struct mmc_host *mmc = host->mmc;
3146
3147 /*
3148 * SDIO_AL clients has different mechanism of handling LPM through
3149 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3150 * part of that. Here, we are interested only in clients like WLAN.
3151 */
3152 if (!(mmc->card && mmc_card_sdio(mmc->card))
3153 || host->plat->is_sdio_al_client)
3154 goto out;
3155
3156 if (!host->sdcc_suspended) {
3157 /*
3158 * When MSM is not in power collapse and we
3159 * are disabling clocks, enable bit 22 in MASK0
3160 * to handle asynchronous SDIO interrupts.
3161 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303162 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303163 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303164 mb();
3165 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303166 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303167 msmsdcc_sync_reg_wr(host);
3168 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303169 goto out;
3170 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3171 /*
3172 * Wakeup MSM only if SDIO function drivers set
3173 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3174 */
3175 goto out;
3176 }
3177
3178 if (enable_wakeup_irq) {
3179 if (!host->plat->sdiowakeup_irq) {
3180 /*
3181 * When there is no gpio line that can be configured
3182 * as wakeup interrupt handle it by configuring
3183 * asynchronous sdio interrupts and DAT1 line.
3184 */
3185 writel_relaxed(MCI_SDIOINTMASK,
3186 host->base + MMCIMASK0);
3187 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303188 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303189 /* configure sdcc core interrupt as wakeup interrupt */
3190 msmsdcc_enable_irq_wake(host);
3191 } else {
3192 /* Let gpio line handle wakeup interrupt */
3193 writel_relaxed(0, host->base + MMCIMASK0);
3194 mb();
3195 if (host->sdio_wakeupirq_disabled) {
3196 host->sdio_wakeupirq_disabled = 0;
3197 /* configure gpio line as wakeup interrupt */
3198 msmsdcc_enable_irq_wake(host);
3199 enable_irq(host->plat->sdiowakeup_irq);
3200 }
3201 }
3202 } else {
3203 if (!host->plat->sdiowakeup_irq) {
3204 /*
3205 * We may not have cleared bit 22 in the interrupt
3206 * handler as the clocks might be off at that time.
3207 */
3208 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303209 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303210 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303211 msmsdcc_disable_irq_wake(host);
3212 } else if (!host->sdio_wakeupirq_disabled) {
3213 disable_irq_nosync(host->plat->sdiowakeup_irq);
3214 msmsdcc_disable_irq_wake(host);
3215 host->sdio_wakeupirq_disabled = 1;
3216 }
3217 }
3218out:
3219 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003220}
3221
3222static void
3223msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3224{
3225 struct msmsdcc_host *host = mmc_priv(mmc);
3226 u32 clk = 0, pwr = 0;
3227 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003228 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003230
Sahitya Tummala7a892482011-01-18 11:22:49 +05303231
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303232 /*
3233 * Disable SDCC core interrupt until set_ios is completed.
3234 * This avoids any race conditions with interrupt raised
3235 * when turning on/off the clocks. One possible
3236 * scenario is SDIO operational interrupt while the clock
3237 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303238 * host->lock is being released intermittently below.
3239 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303240 */
3241
Asutosh Dasf5298c32012-04-03 14:51:47 +05303242 mutex_lock(&host->clk_mutex);
3243 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003244 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303245 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303246 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303247 host->sdcc_irq_disabled = 1;
3248 }
San Mehatd0719e52009-12-03 10:58:54 -08003249 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003250
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303251 /* Make sure sdcc core irq is synchronized */
3252 synchronize_irq(host->core_irqres->start);
3253
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303254 pwr = msmsdcc_setup_pwr(host, ios);
3255
3256 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003257 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303258 spin_unlock_irqrestore(&host->lock, flags);
3259 rc = msmsdcc_setup_clocks(host, true);
3260 if (rc)
3261 goto out;
3262 spin_lock_irqsave(&host->lock, flags);
3263 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3264 mb();
3265 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003268 /*
3269 * For DDR50 mode, controller needs clock rate to be
3270 * double than what is required on the SD card CLK pin.
Subhash Jadavani2877d912012-10-09 20:01:56 +05303271 *
3272 * Setting DDR timing mode in controller before setting the
3273 * clock rate will make sure that card don't see the double
3274 * clock rate even for very small duration. Some eMMC
3275 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003276 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303277 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2877d912012-10-09 20:01:56 +05303278 u32 clk;
3279
3280 clk = readl_relaxed(host->base + MMCICLOCK);
3281 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3282 clk |= (3 << 14); /* set DDR timing mode */
3283 writel_relaxed(clk, host->base + MMCICLOCK);
3284 msmsdcc_sync_reg_wr(host);
3285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003286 /*
3287 * Make sure that we don't double the clock if
3288 * doubled clock rate is already set
3289 */
3290 if (!host->ddr_doubled_clk_rate ||
3291 (host->ddr_doubled_clk_rate &&
3292 (host->ddr_doubled_clk_rate != ios->clock))) {
3293 host->ddr_doubled_clk_rate =
3294 msmsdcc_get_sup_clk_rate(
3295 host, (ios->clock * 2));
3296 clock = host->ddr_doubled_clk_rate;
3297 }
3298 } else {
3299 host->ddr_doubled_clk_rate = 0;
3300 }
3301
3302 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303303 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003304 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303305 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303307 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003308 mmc_hostname(mmc), clock);
3309 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303310 host->reg_write_delay =
3311 (1 + ((3 * USEC_PER_SEC) /
3312 (host->clk_rate ? host->clk_rate :
3313 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 }
3315 /*
3316 * give atleast 2 MCLK cycles delay for clocks
3317 * and SDCC core to stabilize
3318 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303319 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003321 clk |= MCI_CLK_ENABLE;
3322 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003323 if (ios->bus_width == MMC_BUS_WIDTH_8)
3324 clk |= MCI_CLK_WIDEBUS_8;
3325 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3326 clk |= MCI_CLK_WIDEBUS_4;
3327 else
3328 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 if (msmsdcc_is_pwrsave(host))
3331 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003333 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 host->tuning_needed = 0;
3336 /*
3337 * Select the controller timing mode according
3338 * to current bus speed mode
3339 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303340 if (host->clk_rate > (100 * 1000 * 1000) &&
3341 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3342 ios->timing == MMC_TIMING_MMC_HS200)) {
3343 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 clk |= (4 << 14);
3345 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303346 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347 clk |= (3 << 14);
3348 } else {
3349 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07003350 }
3351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3353 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003355 if (host->io_pad_pwr_switch)
3356 clk |= IO_PAD_PWR_SWITCH;
3357
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303358 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303359 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303360 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3361 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303362 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003363 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303364 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3365 host->pwr = pwr;
3366 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303367 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003368 }
San Mehat9d2bd732009-09-22 16:44:22 -07003369 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003370
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303371 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303372 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303373 spin_unlock_irqrestore(&host->lock, flags);
3374 /*
3375 * May get a wake-up interrupt the instant we disable the
3376 * clocks. This would disable the wake-up interrupt.
3377 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303379 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003380 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303381
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303382 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303383 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303384 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303385
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303386 /* Let interrupts be disabled if the host is powered off */
3387 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3388 enable_irq(host->core_irqres->start);
3389 host->sdcc_irq_disabled = 0;
3390 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003391 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303392out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303393 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003394}
3395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3397{
3398 struct msmsdcc_host *host = mmc_priv(mmc);
3399 u32 clk;
3400
3401 clk = readl_relaxed(host->base + MMCICLOCK);
3402 pr_debug("Changing to pwr_save=%d", pwrsave);
3403 if (pwrsave && msmsdcc_is_pwrsave(host))
3404 clk |= MCI_CLK_PWRSAVE;
3405 else
3406 clk &= ~MCI_CLK_PWRSAVE;
3407 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303408 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409
3410 return 0;
3411}
3412
3413static int msmsdcc_get_ro(struct mmc_host *mmc)
3414{
3415 int status = -ENOSYS;
3416 struct msmsdcc_host *host = mmc_priv(mmc);
3417
3418 if (host->plat->wpswitch) {
3419 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303420 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003421 status = gpio_request(host->plat->wpswitch_gpio,
3422 "SD_WP_Switch");
3423 if (status) {
3424 pr_err("%s: %s: Failed to request GPIO %d\n",
3425 mmc_hostname(mmc), __func__,
3426 host->plat->wpswitch_gpio);
3427 } else {
3428 status = gpio_direction_input(
3429 host->plat->wpswitch_gpio);
3430 if (!status) {
3431 /*
3432 * Wait for atleast 300ms as debounce
3433 * time for GPIO input to stabilize.
3434 */
3435 msleep(300);
3436 status = gpio_get_value_cansleep(
3437 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303438 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 }
3440 gpio_free(host->plat->wpswitch_gpio);
3441 }
3442 }
3443
3444 if (status < 0)
3445 status = -ENOSYS;
3446 pr_debug("%s: Card read-only status %d\n", __func__, status);
3447
3448 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003449}
3450
3451static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3452{
3453 struct msmsdcc_host *host = mmc_priv(mmc);
3454 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003455
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303456 /*
3457 * We may come here with clocks turned off in that case don't
3458 * attempt to write into MASK0 register. While turning on the
3459 * clocks mci_irqenable will be written to MASK0 register.
3460 */
San Mehat9d2bd732009-09-22 16:44:22 -07003461
3462 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003463 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303465 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303466 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303468 mb();
3469 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003470 } else {
3471 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303472 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303473 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303475 mb();
3476 }
San Mehat9d2bd732009-09-22 16:44:22 -07003477 }
3478 spin_unlock_irqrestore(&host->lock, flags);
3479}
3480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303482static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003483{
subhashj245831e2012-04-30 18:46:17 +05303484 struct device *dev = mmc_dev(host->mmc);
3485
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303486 pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
Subhash Jadavani386ad802012-08-16 18:46:57 +05303487 mmc_hostname(host->mmc), host->sdcc_suspended,
3488 host->pending_resume, host->sdcc_suspending);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303489 pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
subhashj245831e2012-04-30 18:46:17 +05303490 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3491 " request_pending=%d, request=%d\n",
3492 mmc_hostname(host->mmc), dev->power.runtime_status,
3493 atomic_read(&dev->power.usage_count),
3494 dev->power.is_suspended, dev->power.disable_depth,
3495 dev->power.runtime_error, dev->power.request_pending,
3496 dev->power.request);
3497}
3498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499static int msmsdcc_enable(struct mmc_host *mmc)
3500{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003501 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003503 struct msmsdcc_host *host = mmc_priv(mmc);
3504
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303505 msmsdcc_pm_qos_update_latency(host, 1);
3506
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003507 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303508 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509
Subhash Jadavani386ad802012-08-16 18:46:57 +05303510 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003511 host->pending_resume = false;
3512 pm_runtime_get_noresume(dev);
3513 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303514 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003515 }
3516
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303517 if (dev->power.runtime_status == RPM_SUSPENDING) {
3518 if (mmc->suspend_task == current) {
3519 pm_runtime_get_noresume(dev);
3520 goto out;
3521 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303522 } else if (dev->power.runtime_status == RPM_RESUMING) {
3523 pm_runtime_get_noresume(dev);
3524 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303525 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303527 rc = pm_runtime_get_sync(dev);
3528
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303529skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303530 if (rc < 0) {
Subhash Jadavani386ad802012-08-16 18:46:57 +05303531 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);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303534 return rc;
3535 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303536out:
3537 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303538 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539}
3540
Steve Mucklef132c6c2012-06-06 18:30:57 -07003541static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542{
3543 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303544 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303546 msmsdcc_pm_qos_update_latency(host, 0);
3547
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303548 if (mmc->card && mmc_card_sdio(mmc->card)) {
3549 rc = 0;
3550 goto out;
3551 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303552
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303553 if (host->plat->disable_runtime_pm)
3554 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003555
3556 rc = pm_runtime_put_sync(mmc->parent);
3557
Subhash Jadavani386ad802012-08-16 18:46:57 +05303558 if (rc < 0) {
3559 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3560 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303561 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003562 return rc;
3563 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303564
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303565out:
3566 msmsdcc_msm_bus_queue_work(host);
3567 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003568}
3569#else
subhashj245831e2012-04-30 18:46:17 +05303570static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3571
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303572static int msmsdcc_enable(struct mmc_host *mmc)
3573{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003574 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303575 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303576 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303577
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303578 msmsdcc_pm_qos_update_latency(host, 1);
3579
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303580 if (mmc->card && mmc_card_sdio(mmc->card)) {
3581 rc = 0;
3582 goto out;
3583 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003584
3585 if (host->sdcc_suspended && host->pending_resume) {
3586 host->pending_resume = false;
3587 rc = msmsdcc_runtime_resume(dev);
3588 goto out;
3589 }
3590
Asutosh Dasf5298c32012-04-03 14:51:47 +05303591 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303592 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303593 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303594
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003595out:
3596 if (rc < 0) {
3597 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3598 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303599 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003600 return rc;
3601 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303602 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303603 return 0;
3604}
3605
Steve Mucklef132c6c2012-06-06 18:30:57 -07003606static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303607{
3608 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303609 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303610
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303611 msmsdcc_pm_qos_update_latency(host, 0);
3612
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303613 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303614 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303615
Asutosh Dasf5298c32012-04-03 14:51:47 +05303616 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303617 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303618 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303619
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303620 if (rc) {
3621 msmsdcc_pm_qos_update_latency(host, 1);
3622 return rc;
3623 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303624out:
3625 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303626 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303627}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628#endif
3629
Subhash Jadavani937c7502012-06-01 15:34:46 +05303630static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3631 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632{
3633 struct msmsdcc_host *host = mmc_priv(mmc);
3634 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303635 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636
Subhash Jadavani937c7502012-06-01 15:34:46 +05303637 switch (ios->signal_voltage) {
3638 case MMC_SIGNAL_VOLTAGE_330:
3639 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3640 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303641 if (!rc)
3642 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303643 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303644 case MMC_SIGNAL_VOLTAGE_180:
3645 break;
3646 case MMC_SIGNAL_VOLTAGE_120:
3647 /*
3648 * For eMMC cards, VDD_IO voltage range must be changed
3649 * only if it operates in HS200 SDR 1.2V mode or in
3650 * DDR 1.2V mode.
3651 */
3652 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303653 if (!rc)
3654 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303656 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003657 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303658 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659 goto out;
3660 }
San Mehat9d2bd732009-09-22 16:44:22 -07003661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662 /*
3663 * If we are here means voltage switch from high voltage to
3664 * low voltage is required
3665 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303666 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003667
3668 /*
3669 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3670 * register until they become all zeros.
3671 */
3672 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303673 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3675 mmc_hostname(mmc), __func__);
3676 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003677 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678
3679 /* Stop SD CLK output. */
3680 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3681 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303682 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003683 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003684
3685 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303686 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3687 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303689 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303690 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303693 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003694
3695 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3696 usleep_range(5000, 5500);
3697
3698 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303699 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003700 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3701 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303702 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 spin_unlock_irqrestore(&host->lock, flags);
3704
3705 /*
3706 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3707 * don't become all ones within 1 ms then a Voltage Switch
3708 * sequence has failed and a power cycle to the card is required.
3709 * Otherwise Voltage Switch sequence is completed successfully.
3710 */
3711 usleep_range(1000, 1500);
3712
3713 spin_lock_irqsave(&host->lock, flags);
3714 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3715 != (0xF << 1)) {
3716 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3717 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303718 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003719 goto out_unlock;
3720 }
3721
3722out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303723 /* Enable PWRSAVE */
3724 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3725 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303726 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003727 spin_unlock_irqrestore(&host->lock, flags);
3728out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303729 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730}
3731
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303732static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003734 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003735
3736 /* Program the MCLK value to MCLK_FREQ bit field */
3737 if (host->clk_rate <= 112000000)
3738 mclk_freq = 0;
3739 else if (host->clk_rate <= 125000000)
3740 mclk_freq = 1;
3741 else if (host->clk_rate <= 137000000)
3742 mclk_freq = 2;
3743 else if (host->clk_rate <= 150000000)
3744 mclk_freq = 3;
3745 else if (host->clk_rate <= 162000000)
3746 mclk_freq = 4;
3747 else if (host->clk_rate <= 175000000)
3748 mclk_freq = 5;
3749 else if (host->clk_rate <= 187000000)
3750 mclk_freq = 6;
3751 else if (host->clk_rate <= 200000000)
3752 mclk_freq = 7;
3753
3754 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3755 & ~(7 << 24)) | (mclk_freq << 24)),
3756 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003757}
3758
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303759/* Initialize the DLL (Programmable Delay Line ) */
3760static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303763 unsigned long flags;
3764 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303766 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003767 /*
3768 * Make sure that clock is always enabled when DLL
3769 * tuning is in progress. Keeping PWRSAVE ON may
3770 * turn off the clock. So let's disable the PWRSAVE
3771 * here and re-enable it once tuning is completed.
3772 */
3773 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3774 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303775 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303776
3777 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3778 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3779 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3780
3781 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3782 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3783 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3784
3785 msmsdcc_cm_sdc4_dll_set_freq(host);
3786
3787 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3788 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3789 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3790
3791 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3792 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3793 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3794
3795 /* Set DLL_EN bit to 1. */
3796 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3797 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3798
3799 /* Set CK_OUT_EN bit to 1. */
3800 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3801 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3802
3803 wait_cnt = 50;
3804 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3805 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3806 /* max. wait for 50us sec for LOCK bit to be set */
3807 if (--wait_cnt == 0) {
3808 pr_err("%s: %s: DLL failed to LOCK\n",
3809 mmc_hostname(host->mmc), __func__);
3810 rc = -ETIMEDOUT;
3811 goto out;
3812 }
3813 /* wait for 1us before polling again */
3814 udelay(1);
3815 }
3816
3817out:
3818 /* re-enable PWRSAVE */
3819 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3820 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303821 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303822 spin_unlock_irqrestore(&host->lock, flags);
3823
3824 return rc;
3825}
3826
3827static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3828 u8 poll)
3829{
3830 int rc = 0;
3831 u32 wait_cnt = 50;
3832 u8 ck_out_en = 0;
3833
3834 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3835 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3836 MCI_CK_OUT_EN);
3837
3838 while (ck_out_en != poll) {
3839 if (--wait_cnt == 0) {
3840 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3841 mmc_hostname(host->mmc), __func__, poll);
3842 rc = -ETIMEDOUT;
3843 goto out;
3844 }
3845 udelay(1);
3846
3847 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3848 MCI_CK_OUT_EN);
3849 }
3850out:
3851 return rc;
3852}
3853
3854/*
3855 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3856 * calibration sequence. This function should be called before
3857 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3858 * commands (CMD17/CMD18).
3859 *
3860 * This function gets called when host spinlock acquired.
3861 */
3862static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3863{
3864 int rc = 0;
3865 u32 config;
3866
3867 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3868 config |= MCI_CDR_EN;
3869 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3870 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3871
3872 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3873 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3874 if (rc)
3875 goto err_out;
3876
3877 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3878 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3879 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3880
3881 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3882 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3883 if (rc)
3884 goto err_out;
3885
3886 goto out;
3887
3888err_out:
3889 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3890out:
3891 return rc;
3892}
3893
3894static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3895 u8 phase)
3896{
3897 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303898 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3899 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3900 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303901 unsigned long flags;
3902 u32 config;
3903
3904 spin_lock_irqsave(&host->lock, flags);
3905
3906 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3907 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3908 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3909 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3910
3911 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3912 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3913 if (rc)
3914 goto err_out;
3915
3916 /*
3917 * Write the selected DLL clock output phase (0 ... 15)
3918 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3919 */
3920 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3921 & ~(0xF << 20))
3922 | (grey_coded_phase_table[phase] << 20)),
3923 host->base + MCI_DLL_CONFIG);
3924
3925 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3926 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3927 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3928
3929 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3930 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3931 if (rc)
3932 goto err_out;
3933
3934 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3935 config |= MCI_CDR_EN;
3936 config &= ~MCI_CDR_EXT_EN;
3937 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3938 goto out;
3939
3940err_out:
3941 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3942 mmc_hostname(host->mmc), __func__, phase);
3943out:
3944 spin_unlock_irqrestore(&host->lock, flags);
3945 return rc;
3946}
3947
3948/*
3949 * Find out the greatest range of consecuitive selected
3950 * DLL clock output phases that can be used as sampling
3951 * setting for SD3.0 UHS-I card read operation (in SDR104
3952 * timing mode) or for eMMC4.5 card read operation (in HS200
3953 * timing mode).
3954 * Select the 3/4 of the range and configure the DLL with the
3955 * selected DLL clock output phase.
3956*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303957static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303958 u8 *phase_table, u8 total_phases)
3959{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303960 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303961 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303962 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3963 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303964 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303965 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3966 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303967
Subhash Jadavani6159c622012-03-15 19:05:55 +05303968 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303969 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3970 mmc_hostname(host->mmc), __func__, total_phases);
3971 return -EINVAL;
3972 }
3973
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303974 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303975 ranges[row_index][col_index] = phase_table[cnt];
3976 phases_per_row[row_index] += 1;
3977 col_index++;
3978
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303979 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303980 continue;
3981 /* check if next phase in phase_table is consecutive or not */
3982 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3983 row_index++;
3984 col_index = 0;
3985 }
3986 }
3987
Subhash Jadavani6159c622012-03-15 19:05:55 +05303988 if (row_index >= MAX_PHASES)
3989 return -EINVAL;
3990
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303991 /* Check if phase-0 is present in first valid window? */
3992 if (!ranges[0][0]) {
3993 phase_0_found = true;
3994 phase_0_raw_index = 0;
3995 /* Check if cycle exist between 2 valid windows */
3996 for (cnt = 1; cnt <= row_index; cnt++) {
3997 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303998 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303999 if (ranges[cnt][i] == 15) {
4000 phase_15_found = true;
4001 phase_15_raw_index = cnt;
4002 break;
4003 }
4004 }
4005 }
4006 }
4007 }
4008
4009 /* If 2 valid windows form cycle then merge them as single window */
4010 if (phase_0_found && phase_15_found) {
4011 /* number of phases in raw where phase 0 is present */
4012 u8 phases_0 = phases_per_row[phase_0_raw_index];
4013 /* number of phases in raw where phase 15 is present */
4014 u8 phases_15 = phases_per_row[phase_15_raw_index];
4015
Subhash Jadavani6159c622012-03-15 19:05:55 +05304016 if (phases_0 + phases_15 >= MAX_PHASES)
4017 /*
4018 * If there are more than 1 phase windows then total
4019 * number of phases in both the windows should not be
4020 * more than or equal to MAX_PHASES.
4021 */
4022 return -EINVAL;
4023
4024 /* Merge 2 cyclic windows */
4025 i = phases_15;
4026 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304027 ranges[phase_15_raw_index][i] =
4028 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304029 if (++i >= MAX_PHASES)
4030 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304031 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304032
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304033 phases_per_row[phase_0_raw_index] = 0;
4034 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4035 }
4036
4037 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304038 if (phases_per_row[cnt] > curr_max) {
4039 curr_max = phases_per_row[cnt];
4040 selected_row_index = cnt;
4041 }
4042 }
4043
Subhash Jadavani6159c622012-03-15 19:05:55 +05304044 i = ((curr_max * 3) / 4);
4045 if (i)
4046 i--;
4047
Subhash Jadavani34187042012-03-02 10:59:49 +05304048 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304049
Subhash Jadavani6159c622012-03-15 19:05:55 +05304050 if (ret >= MAX_PHASES) {
4051 ret = -EINVAL;
4052 pr_err("%s: %s: invalid phase selected=%d\n",
4053 mmc_hostname(host->mmc), __func__, ret);
4054 }
4055
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304056 return ret;
4057}
4058
Girish K Sa3f41692012-02-29 12:00:09 +05304059static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304060{
4061 int rc = 0;
4062 struct msmsdcc_host *host = mmc_priv(mmc);
4063 unsigned long flags;
4064 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304065 const u32 *tuning_block_pattern = tuning_block_64;
4066 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304067 bool is_tuning_all_phases;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304068
4069 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4070
4071 /* Tuning is only required for SDR104 modes */
4072 if (!host->tuning_needed) {
4073 rc = 0;
4074 goto exit;
4075 }
4076
4077 spin_lock_irqsave(&host->lock, flags);
4078 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304079 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304080 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4081
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304082 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304083 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4084 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4085 tuning_block_pattern = tuning_block_128;
4086 size = sizeof(tuning_block_128);
4087 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304088 spin_unlock_irqrestore(&host->lock, flags);
4089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 /* first of all reset the tuning block */
4091 rc = msmsdcc_init_cm_sdc4_dll(host);
4092 if (rc)
4093 goto out;
4094
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304095 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004096 if (!data_buf) {
4097 rc = -ENOMEM;
4098 goto out;
4099 }
4100
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304101 is_tuning_all_phases = !(host->mmc->card &&
4102 (host->saved_tuning_phase != INVALID_TUNING_PHASE));
4103retry:
4104 if (is_tuning_all_phases)
4105 phase = 0; /* start from phase 0 during init */
4106 else
4107 phase = (u8)host->saved_tuning_phase;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 do {
4109 struct mmc_command cmd = {0};
4110 struct mmc_data data = {0};
4111 struct mmc_request mrq = {
4112 .cmd = &cmd,
4113 .data = &data
4114 };
4115 struct scatterlist sg;
4116
4117 /* set the phase in delay line hw block */
4118 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4119 if (rc)
4120 goto kfree;
4121
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304122 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004123 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4124
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304125 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 data.blocks = 1;
4127 data.flags = MMC_DATA_READ;
4128 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4129
4130 data.sg = &sg;
4131 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304132 sg_init_one(&sg, data_buf, size);
4133 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 mmc_wait_for_req(mmc, &mrq);
4135
4136 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304137 !memcmp(data_buf, tuning_block_pattern, size)) {
4138 /* tuning is successful at this tuning point */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304139 if (!is_tuning_all_phases)
4140 goto kfree;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304142 pr_debug("%s: %s: found good phase = %d\n",
4143 mmc_hostname(mmc), __func__, phase);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304144 } else if (!is_tuning_all_phases) {
4145 pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
4146 mmc_hostname(mmc), (u32)phase);
4147 is_tuning_all_phases = true;
4148 goto retry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149 }
4150 } while (++phase < 16);
4151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004152 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304153 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304154 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304155 if (rc < 0)
4156 goto kfree;
4157 else
4158 phase = (u8)rc;
4159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160 /*
4161 * Finally set the selected phase in delay
4162 * line hw block.
4163 */
4164 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4165 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304166 goto kfree;
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304167 else
4168 host->saved_tuning_phase = phase;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304169 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4170 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171 } else {
4172 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304173 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304175 msmsdcc_dump_sdcc_state(host);
4176 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004177 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004178
4179kfree:
4180 kfree(data_buf);
4181out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304182 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304183 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304184 spin_unlock_irqrestore(&host->lock, flags);
4185exit:
4186 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004188}
4189
Asutosh Dasebd7d092012-07-09 19:08:26 +05304190/*
4191 * Work around of the unavailability of a power_reset functionality in SD cards
4192 * by turning the OFF & back ON the regulators supplying the SD card.
4193 */
4194void msmsdcc_hw_reset(struct mmc_host *mmc)
4195{
4196 struct mmc_card *card = mmc->card;
4197 struct msmsdcc_host *host = mmc_priv(mmc);
4198 int rc;
4199
4200 /* Write-protection bits would be lost on a hardware reset in emmc */
4201 if (!card || !mmc_card_sd(card))
4202 return;
4203
4204 /*
4205 * Continuing on failing to disable regulator would lead to a panic
4206 * anyway, since the commands would fail and console would be flooded
4207 * with prints, eventually leading to a watchdog bark
4208 */
4209 rc = msmsdcc_setup_vreg(host, false, false);
4210 if (rc) {
4211 pr_err("%s: %s disable regulator: failed: %d\n",
4212 mmc_hostname(mmc), __func__, rc);
4213 BUG_ON(rc);
4214 }
4215
4216 /* 10ms delay for the supply to reach the desired voltage level */
4217 usleep_range(10000, 12000);
4218
4219 /*
4220 * Continuing on failing to enable regulator would lead to a panic
4221 * anyway, since the commands would fail and console would be flooded
4222 * with prints, eventually leading to a watchdog bark
4223 */
4224 rc = msmsdcc_setup_vreg(host, true, false);
4225 if (rc) {
4226 pr_err("%s: %s enable regulator: failed: %d\n",
4227 mmc_hostname(mmc), __func__, rc);
4228 BUG_ON(rc);
4229 }
4230
4231 /* 10ms delay for the supply to reach the desired voltage level */
4232 usleep_range(10000, 12000);
4233}
4234
San Mehat9d2bd732009-09-22 16:44:22 -07004235static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 .enable = msmsdcc_enable,
4237 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304238 .pre_req = msmsdcc_pre_req,
4239 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004240 .request = msmsdcc_request,
4241 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004242 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004243 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304244 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304245 .execute_tuning = msmsdcc_execute_tuning,
4246 .hw_reset = msmsdcc_hw_reset,
San Mehat9d2bd732009-09-22 16:44:22 -07004247};
4248
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304249static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4250{
4251 unsigned int gpio_no = host->plat->status_gpio;
4252 int status;
4253
4254 if (!gpio_is_valid(gpio_no))
4255 return;
4256
4257 status = gpio_request(gpio_no, "SD_HW_Detect");
4258 if (status)
4259 pr_err("%s: %s: gpio_request(%d) failed\n",
4260 mmc_hostname(host->mmc), __func__, gpio_no);
4261}
4262
4263static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4264{
4265 if (gpio_is_valid(host->plat->status_gpio))
4266 gpio_free(host->plat->status_gpio);
4267}
4268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004269static unsigned int
4270msmsdcc_slot_status(struct msmsdcc_host *host)
4271{
4272 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304274 status = gpio_get_value_cansleep(host->plat->status_gpio);
4275 if (host->plat->is_status_gpio_active_low)
4276 status = !status;
4277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 return status;
4279}
4280
San Mehat9d2bd732009-09-22 16:44:22 -07004281static void
4282msmsdcc_check_status(unsigned long data)
4283{
4284 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4285 unsigned int status;
4286
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304287 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004288 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004290 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004291 status = msmsdcc_slot_status(host);
4292
Krishna Konda941604a2012-01-10 17:46:34 -08004293 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004295 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004296 if (host->plat->status)
4297 pr_info("%s: Slot status change detected "
4298 "(%d -> %d)\n",
4299 mmc_hostname(host->mmc),
4300 host->oldstat, status);
4301 else if (host->plat->is_status_gpio_active_low)
4302 pr_info("%s: Slot status change detected "
4303 "(%d -> %d) and the card detect GPIO"
4304 " is ACTIVE_LOW\n",
4305 mmc_hostname(host->mmc),
4306 host->oldstat, status);
4307 else
4308 pr_info("%s: Slot status change detected "
4309 "(%d -> %d) and the card detect GPIO"
4310 " is ACTIVE_HIGH\n",
4311 mmc_hostname(host->mmc),
4312 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004313 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004314 }
4315 host->oldstat = status;
4316 } else {
4317 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004318 }
San Mehat9d2bd732009-09-22 16:44:22 -07004319}
4320
4321static irqreturn_t
4322msmsdcc_platform_status_irq(int irq, void *dev_id)
4323{
4324 struct msmsdcc_host *host = dev_id;
4325
Girish K Sa3c76eb2011-10-11 11:44:09 +05304326 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004327 msmsdcc_check_status((unsigned long) host);
4328 return IRQ_HANDLED;
4329}
4330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004331static irqreturn_t
4332msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4333{
4334 struct msmsdcc_host *host = dev_id;
4335
4336 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4337 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304338 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004339 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304340 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341 wake_lock(&host->sdio_wlock);
4342 msmsdcc_disable_irq_wake(host);
4343 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304344 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 }
4346 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004347 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304348 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304349 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304350 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004351 }
4352 spin_unlock(&host->lock);
4353
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304354out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004355 return IRQ_HANDLED;
4356}
4357
San Mehat9d2bd732009-09-22 16:44:22 -07004358static void
4359msmsdcc_status_notify_cb(int card_present, void *dev_id)
4360{
4361 struct msmsdcc_host *host = dev_id;
4362
Girish K Sa3c76eb2011-10-11 11:44:09 +05304363 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004364 card_present);
4365 msmsdcc_check_status((unsigned long) host);
4366}
4367
San Mehat9d2bd732009-09-22 16:44:22 -07004368static int
4369msmsdcc_init_dma(struct msmsdcc_host *host)
4370{
4371 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4372 host->dma.host = host;
4373 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004374 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004375
4376 if (!host->dmares)
4377 return -ENODEV;
4378
4379 host->dma.nc = dma_alloc_coherent(NULL,
4380 sizeof(struct msmsdcc_nc_dmadata),
4381 &host->dma.nc_busaddr,
4382 GFP_KERNEL);
4383 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004384 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004385 return -ENOMEM;
4386 }
4387 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4388 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4389 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4390 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4391 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004392 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004393
4394 return 0;
4395}
4396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004397#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4398/**
4399 * Allocate and Connect a SDCC peripheral's SPS endpoint
4400 *
4401 * This function allocates endpoint context and
4402 * connect it with memory endpoint by calling
4403 * appropriate SPS driver APIs.
4404 *
4405 * Also registers a SPS callback function with
4406 * SPS driver
4407 *
4408 * This function should only be called once typically
4409 * during driver probe.
4410 *
4411 * @host - Pointer to sdcc host structure
4412 * @ep - Pointer to sps endpoint data structure
4413 * @is_produce - 1 means Producer endpoint
4414 * 0 means Consumer endpoint
4415 *
4416 * @return - 0 if successful else negative value.
4417 *
4418 */
4419static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4420 struct msmsdcc_sps_ep_conn_data *ep,
4421 bool is_producer)
4422{
4423 int rc = 0;
4424 struct sps_pipe *sps_pipe_handle;
4425 struct sps_connect *sps_config = &ep->config;
4426 struct sps_register_event *sps_event = &ep->event;
4427
4428 /* Allocate endpoint context */
4429 sps_pipe_handle = sps_alloc_endpoint();
4430 if (!sps_pipe_handle) {
4431 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4432 mmc_hostname(host->mmc), is_producer);
4433 rc = -ENOMEM;
4434 goto out;
4435 }
4436
4437 /* Get default connection configuration for an endpoint */
4438 rc = sps_get_config(sps_pipe_handle, sps_config);
4439 if (rc) {
4440 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4441 " rc=%d", mmc_hostname(host->mmc),
4442 (u32)sps_pipe_handle, rc);
4443 goto get_config_err;
4444 }
4445
4446 /* Modify the default connection configuration */
4447 if (is_producer) {
4448 /*
4449 * For SDCC producer transfer, source should be
4450 * SDCC peripheral where as destination should
4451 * be system memory.
4452 */
4453 sps_config->source = host->sps.bam_handle;
4454 sps_config->destination = SPS_DEV_HANDLE_MEM;
4455 /* Producer pipe will handle this connection */
4456 sps_config->mode = SPS_MODE_SRC;
4457 sps_config->options =
4458 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4459 } else {
4460 /*
4461 * For SDCC consumer transfer, source should be
4462 * system memory where as destination should
4463 * SDCC peripheral
4464 */
4465 sps_config->source = SPS_DEV_HANDLE_MEM;
4466 sps_config->destination = host->sps.bam_handle;
4467 sps_config->mode = SPS_MODE_DEST;
4468 sps_config->options =
4469 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4470 }
4471
4472 /* Producer pipe index */
4473 sps_config->src_pipe_index = host->sps.src_pipe_index;
4474 /* Consumer pipe index */
4475 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4476 /*
4477 * This event thresold value is only significant for BAM-to-BAM
4478 * transfer. It's ignored for BAM-to-System mode transfer.
4479 */
4480 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304481
4482 /* Allocate maximum descriptor fifo size */
4483 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4484 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004485 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4486 sps_config->desc.size,
4487 &sps_config->desc.phys_base,
4488 GFP_KERNEL);
4489
Pratibhasagar V00b94332011-10-18 14:57:27 +05304490 if (!sps_config->desc.base) {
4491 rc = -ENOMEM;
4492 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4493 , mmc_hostname(host->mmc));
4494 goto get_config_err;
4495 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004496 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4497
4498 /* Establish connection between peripheral and memory endpoint */
4499 rc = sps_connect(sps_pipe_handle, sps_config);
4500 if (rc) {
4501 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4502 " rc=%d", mmc_hostname(host->mmc),
4503 (u32)sps_pipe_handle, rc);
4504 goto sps_connect_err;
4505 }
4506
4507 sps_event->mode = SPS_TRIGGER_CALLBACK;
4508 sps_event->options = SPS_O_EOT;
4509 sps_event->callback = msmsdcc_sps_complete_cb;
4510 sps_event->xfer_done = NULL;
4511 sps_event->user = (void *)host;
4512
4513 /* Register callback event for EOT (End of transfer) event. */
4514 rc = sps_register_event(sps_pipe_handle, sps_event);
4515 if (rc) {
4516 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4517 " rc=%d", mmc_hostname(host->mmc),
4518 (u32)sps_pipe_handle, rc);
4519 goto reg_event_err;
4520 }
4521 /* Now save the sps pipe handle */
4522 ep->pipe_handle = sps_pipe_handle;
4523 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4524 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4525 __func__, is_producer ? "READ" : "WRITE",
4526 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4527 goto out;
4528
4529reg_event_err:
4530 sps_disconnect(sps_pipe_handle);
4531sps_connect_err:
4532 dma_free_coherent(mmc_dev(host->mmc),
4533 sps_config->desc.size,
4534 sps_config->desc.base,
4535 sps_config->desc.phys_base);
4536get_config_err:
4537 sps_free_endpoint(sps_pipe_handle);
4538out:
4539 return rc;
4540}
4541
4542/**
4543 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4544 *
4545 * This function disconnect endpoint and deallocates
4546 * endpoint context.
4547 *
4548 * This function should only be called once typically
4549 * during driver remove.
4550 *
4551 * @host - Pointer to sdcc host structure
4552 * @ep - Pointer to sps endpoint data structure
4553 *
4554 */
4555static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4556 struct msmsdcc_sps_ep_conn_data *ep)
4557{
4558 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4559 struct sps_connect *sps_config = &ep->config;
4560 struct sps_register_event *sps_event = &ep->event;
4561
4562 sps_event->xfer_done = NULL;
4563 sps_event->callback = NULL;
4564 sps_register_event(sps_pipe_handle, sps_event);
4565 sps_disconnect(sps_pipe_handle);
4566 dma_free_coherent(mmc_dev(host->mmc),
4567 sps_config->desc.size,
4568 sps_config->desc.base,
4569 sps_config->desc.phys_base);
4570 sps_free_endpoint(sps_pipe_handle);
4571}
4572
4573/**
4574 * Reset SDCC peripheral's SPS endpoint
4575 *
4576 * This function disconnects an endpoint.
4577 *
4578 * This function should be called for reseting
4579 * SPS endpoint when data transfer error is
4580 * encountered during data transfer. This
4581 * can be considered as soft reset to endpoint.
4582 *
4583 * This function should only be called if
4584 * msmsdcc_sps_init() is already called.
4585 *
4586 * @host - Pointer to sdcc host structure
4587 * @ep - Pointer to sps endpoint data structure
4588 *
4589 * @return - 0 if successful else negative value.
4590 */
4591static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4592 struct msmsdcc_sps_ep_conn_data *ep)
4593{
4594 int rc = 0;
4595 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4596
4597 rc = sps_disconnect(sps_pipe_handle);
4598 if (rc) {
4599 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4600 " rc=%d", mmc_hostname(host->mmc), __func__,
4601 (u32)sps_pipe_handle, rc);
4602 goto out;
4603 }
4604 out:
4605 return rc;
4606}
4607
4608/**
4609 * Restore SDCC peripheral's SPS endpoint
4610 *
4611 * This function connects an endpoint.
4612 *
4613 * This function should be called for restoring
4614 * SPS endpoint after data transfer error is
4615 * encountered during data transfer. This
4616 * can be considered as soft reset to endpoint.
4617 *
4618 * This function should only be called if
4619 * msmsdcc_sps_reset_ep() is called before.
4620 *
4621 * @host - Pointer to sdcc host structure
4622 * @ep - Pointer to sps endpoint data structure
4623 *
4624 * @return - 0 if successful else negative value.
4625 */
4626static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4627 struct msmsdcc_sps_ep_conn_data *ep)
4628{
4629 int rc = 0;
4630 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4631 struct sps_connect *sps_config = &ep->config;
4632 struct sps_register_event *sps_event = &ep->event;
4633
4634 /* Establish connection between peripheral and memory endpoint */
4635 rc = sps_connect(sps_pipe_handle, sps_config);
4636 if (rc) {
4637 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4638 " rc=%d", mmc_hostname(host->mmc), __func__,
4639 (u32)sps_pipe_handle, rc);
4640 goto out;
4641 }
4642
4643 /* Register callback event for EOT (End of transfer) event. */
4644 rc = sps_register_event(sps_pipe_handle, sps_event);
4645 if (rc) {
4646 pr_err("%s: %s: sps_register_event() failed!!!"
4647 " pipe_handle=0x%x, rc=%d",
4648 mmc_hostname(host->mmc), __func__,
4649 (u32)sps_pipe_handle, rc);
4650 goto reg_event_err;
4651 }
4652 goto out;
4653
4654reg_event_err:
4655 sps_disconnect(sps_pipe_handle);
4656out:
4657 return rc;
4658}
4659
4660/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004661 * Handle BAM device's global error condition
4662 *
4663 * This is an error handler for the SDCC bam device
4664 *
4665 * This function is registered as a callback with SPS-BAM
4666 * driver and will called in case there are an errors for
4667 * the SDCC BAM deivce. Any error conditions in the BAM
4668 * device are global and will be result in this function
4669 * being called once per device.
4670 *
4671 * This function will be called from the sps driver's
4672 * interrupt context.
4673 *
4674 * @sps_cb_case - indicates what error it is
4675 * @user - Pointer to sdcc host structure
4676 */
4677static void
4678msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4679{
4680 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4681 struct mmc_request *mrq;
4682 unsigned long flags;
4683 int32_t error = 0;
4684
4685 BUG_ON(!host);
4686 BUG_ON(!is_sps_mode(host));
4687
4688 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004689 /* Reset all endpoints along with resetting bam. */
4690 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004691
4692 pr_err("%s: BAM Global ERROR IRQ happened\n",
4693 mmc_hostname(host->mmc));
4694 error = EAGAIN;
4695 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4696 /**
4697 * This means that there was an AHB access error and
4698 * the address we are trying to read/write is something
4699 * we dont have priviliges to do so.
4700 */
4701 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4702 mmc_hostname(host->mmc));
4703 error = EACCES;
4704 } else {
4705 /**
4706 * This should not have happened ideally. If this happens
4707 * there is some seriously wrong.
4708 */
4709 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4710 mmc_hostname(host->mmc), (u32) sps_cb_case);
4711 error = EIO;
4712 }
4713
4714 spin_lock_irqsave(&host->lock, flags);
4715
4716 mrq = host->curr.mrq;
4717
4718 if (mrq && mrq->cmd) {
4719 msmsdcc_dump_sdcc_state(host);
4720
4721 if (!mrq->cmd->error)
4722 mrq->cmd->error = -error;
4723 if (host->curr.data) {
4724 if (mrq->data && !mrq->data->error)
4725 mrq->data->error = -error;
4726 host->curr.data_xfered = 0;
4727 if (host->sps.sg && is_sps_mode(host)) {
4728 /* Stop current SPS transfer */
4729 msmsdcc_sps_exit_curr_xfer(host);
4730 } else {
4731 /* this condition should not have happened */
4732 pr_err("%s: something is seriously wrong. "\
4733 "Funtion: %s, line: %d\n",
4734 mmc_hostname(host->mmc),
4735 __func__, __LINE__);
4736 }
4737 } else {
4738 /* this condition should not have happened */
4739 pr_err("%s: something is seriously wrong. Funtion: "\
4740 "%s, line: %d\n", mmc_hostname(host->mmc),
4741 __func__, __LINE__);
4742 }
4743 }
4744 spin_unlock_irqrestore(&host->lock, flags);
4745}
4746
4747/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004748 * Initialize SPS HW connected with SDCC core
4749 *
4750 * This function register BAM HW resources with
4751 * SPS driver and then initialize 2 SPS endpoints
4752 *
4753 * This function should only be called once typically
4754 * during driver probe.
4755 *
4756 * @host - Pointer to sdcc host structure
4757 *
4758 * @return - 0 if successful else negative value.
4759 *
4760 */
4761static int msmsdcc_sps_init(struct msmsdcc_host *host)
4762{
4763 int rc = 0;
4764 struct sps_bam_props bam = {0};
4765
4766 host->bam_base = ioremap(host->bam_memres->start,
4767 resource_size(host->bam_memres));
4768 if (!host->bam_base) {
4769 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4770 " size=0x%x", mmc_hostname(host->mmc),
4771 host->bam_memres->start,
4772 (host->bam_memres->end -
4773 host->bam_memres->start));
4774 rc = -ENOMEM;
4775 goto out;
4776 }
4777
4778 bam.phys_addr = host->bam_memres->start;
4779 bam.virt_addr = host->bam_base;
4780 /*
4781 * This event thresold value is only significant for BAM-to-BAM
4782 * transfer. It's ignored for BAM-to-System mode transfer.
4783 */
4784 bam.event_threshold = 0x10; /* Pipe event threshold */
4785 /*
4786 * This threshold controls when the BAM publish
4787 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304788 * SPS HW will be used for data transfer size even
4789 * less than SDCC FIFO size. So let's set BAM summing
4790 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004791 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304792 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004793 /* SPS driver wll handle the SDCC BAM IRQ */
4794 bam.irq = (u32)host->bam_irqres->start;
4795 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004796 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4797 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798
4799 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4800 (u32)bam.phys_addr);
4801 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4802 (u32)bam.virt_addr);
4803
4804 /* Register SDCC Peripheral BAM device to SPS driver */
4805 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4806 if (rc) {
4807 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4808 mmc_hostname(host->mmc), rc);
4809 goto reg_bam_err;
4810 }
4811 pr_info("%s: BAM device registered. bam_handle=0x%x",
4812 mmc_hostname(host->mmc), host->sps.bam_handle);
4813
4814 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4815 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4816
4817 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4818 SPS_PROD_PERIPHERAL);
4819 if (rc)
4820 goto sps_reset_err;
4821 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4822 SPS_CONS_PERIPHERAL);
4823 if (rc)
4824 goto cons_conn_err;
4825
4826 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4827 mmc_hostname(host->mmc),
4828 (unsigned long long)host->bam_memres->start,
4829 (unsigned int)host->bam_irqres->start);
4830 goto out;
4831
4832cons_conn_err:
4833 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4834sps_reset_err:
4835 sps_deregister_bam_device(host->sps.bam_handle);
4836reg_bam_err:
4837 iounmap(host->bam_base);
4838out:
4839 return rc;
4840}
4841
4842/**
4843 * De-initialize SPS HW connected with SDCC core
4844 *
4845 * This function deinitialize SPS endpoints and then
4846 * deregisters BAM resources from SPS driver.
4847 *
4848 * This function should only be called once typically
4849 * during driver remove.
4850 *
4851 * @host - Pointer to sdcc host structure
4852 *
4853 */
4854static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4855{
4856 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4857 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4858 sps_deregister_bam_device(host->sps.bam_handle);
4859 iounmap(host->bam_base);
4860}
4861#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4862
4863static ssize_t
4864show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4865{
4866 struct mmc_host *mmc = dev_get_drvdata(dev);
4867 struct msmsdcc_host *host = mmc_priv(mmc);
4868 int poll;
4869 unsigned long flags;
4870
4871 spin_lock_irqsave(&host->lock, flags);
4872 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4873 spin_unlock_irqrestore(&host->lock, flags);
4874
4875 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4876}
4877
4878static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304879store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004880 const char *buf, size_t count)
4881{
4882 struct mmc_host *mmc = dev_get_drvdata(dev);
4883 struct msmsdcc_host *host = mmc_priv(mmc);
4884 int value;
4885 unsigned long flags;
4886
4887 sscanf(buf, "%d", &value);
4888
4889 spin_lock_irqsave(&host->lock, flags);
4890 if (value) {
4891 mmc->caps |= MMC_CAP_NEEDS_POLL;
4892 mmc_detect_change(host->mmc, 0);
4893 } else {
4894 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4895 }
4896#ifdef CONFIG_HAS_EARLYSUSPEND
4897 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4898#endif
4899 spin_unlock_irqrestore(&host->lock, flags);
4900 return count;
4901}
4902
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304903static ssize_t
4904show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4905 char *buf)
4906{
4907 struct mmc_host *mmc = dev_get_drvdata(dev);
4908 struct msmsdcc_host *host = mmc_priv(mmc);
4909
4910 return snprintf(buf, PAGE_SIZE, "%u\n",
4911 host->msm_bus_vote.is_max_bw_needed);
4912}
4913
4914static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304915store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304916 const char *buf, size_t count)
4917{
4918 struct mmc_host *mmc = dev_get_drvdata(dev);
4919 struct msmsdcc_host *host = mmc_priv(mmc);
4920 uint32_t value;
4921 unsigned long flags;
4922
4923 if (!kstrtou32(buf, 0, &value)) {
4924 spin_lock_irqsave(&host->lock, flags);
4925 host->msm_bus_vote.is_max_bw_needed = !!value;
4926 spin_unlock_irqrestore(&host->lock, flags);
4927 }
4928
4929 return count;
4930}
4931
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304932static ssize_t
4933show_idle_timeout(struct device *dev, struct device_attribute *attr,
4934 char *buf)
4935{
4936 struct mmc_host *mmc = dev_get_drvdata(dev);
4937 struct msmsdcc_host *host = mmc_priv(mmc);
4938
4939 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05304940 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304941}
4942
4943static ssize_t
4944store_idle_timeout(struct device *dev, struct device_attribute *attr,
4945 const char *buf, size_t count)
4946{
4947 struct mmc_host *mmc = dev_get_drvdata(dev);
4948 struct msmsdcc_host *host = mmc_priv(mmc);
4949 unsigned int long flags;
4950 int timeout; /* in secs */
4951
4952 if (!kstrtou32(buf, 0, &timeout)
4953 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
4954 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05304955 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05304956 spin_unlock_irqrestore(&host->lock, flags);
4957 }
4958 return count;
4959}
4960
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05304961static inline void set_auto_cmd_setting(struct device *dev,
4962 const char *buf,
4963 bool is_cmd19)
4964{
4965 struct mmc_host *mmc = dev_get_drvdata(dev);
4966 struct msmsdcc_host *host = mmc_priv(mmc);
4967 unsigned int long flags;
4968 int temp;
4969
4970 if (!kstrtou32(buf, 0, &temp)) {
4971 spin_lock_irqsave(&host->lock, flags);
4972 if (is_cmd19)
4973 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05304974 else
4975 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05304976 spin_unlock_irqrestore(&host->lock, flags);
4977 }
4978}
4979
4980static ssize_t
4981show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
4982 char *buf)
4983{
4984 struct mmc_host *mmc = dev_get_drvdata(dev);
4985 struct msmsdcc_host *host = mmc_priv(mmc);
4986
4987 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
4988}
4989
4990static ssize_t
4991store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
4992 const char *buf, size_t count)
4993{
4994 set_auto_cmd_setting(dev, buf, true);
4995
4996 return count;
4997}
4998
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05304999static ssize_t
5000show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5001 char *buf)
5002{
5003 struct mmc_host *mmc = dev_get_drvdata(dev);
5004 struct msmsdcc_host *host = mmc_priv(mmc);
5005
5006 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5007}
5008
5009static ssize_t
5010store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5011 const char *buf, size_t count)
5012{
5013 set_auto_cmd_setting(dev, buf, false);
5014
5015 return count;
5016}
5017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005018#ifdef CONFIG_HAS_EARLYSUSPEND
5019static void msmsdcc_early_suspend(struct early_suspend *h)
5020{
5021 struct msmsdcc_host *host =
5022 container_of(h, struct msmsdcc_host, early_suspend);
5023 unsigned long flags;
5024
5025 spin_lock_irqsave(&host->lock, flags);
5026 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
5027 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5028 spin_unlock_irqrestore(&host->lock, flags);
5029};
5030static void msmsdcc_late_resume(struct early_suspend *h)
5031{
5032 struct msmsdcc_host *host =
5033 container_of(h, struct msmsdcc_host, early_suspend);
5034 unsigned long flags;
5035
5036 if (host->polling_enabled) {
5037 spin_lock_irqsave(&host->lock, flags);
5038 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
5039 mmc_detect_change(host->mmc, 0);
5040 spin_unlock_irqrestore(&host->lock, flags);
5041 }
5042};
5043#endif
5044
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305045static void msmsdcc_print_regs(const char *name, void __iomem *base,
5046 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305047{
5048 unsigned int i;
5049
5050 if (!base)
5051 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305052
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305053 pr_err("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305054 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305055 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305056 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305057 (u32)readl_relaxed(base + i*4),
5058 (u32)readl_relaxed(base + ((i+1)*4)),
5059 (u32)readl_relaxed(base + ((i+2)*4)),
5060 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305061 }
5062}
5063
5064static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5065{
5066 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305067 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305068 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305069 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305070 mmc_hostname(host->mmc),
5071 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305072 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305073 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305074 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5075
5076 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305077 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305078 msmsdcc_print_regs("SDCC-CORE", host->base,
5079 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305080 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5081 mmc_hostname(host->mmc),
5082 readl_relaxed(host->base + MCI_TEST_INPUT));
5083 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305084
5085 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305086 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305087 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305088 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305089 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305090 mmc_hostname(host->mmc), host->dma.busy,
5091 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305092 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305093 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305094 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5095 host->dml_memres->start,
5096 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305097 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305098 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305099 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305100
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305101 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305102 mmc_hostname(host->mmc), host->curr.xfer_size,
5103 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305104 }
5105
Krishna Konda3ca90f02012-08-29 16:29:21 -07005106 if (host->sps.reset_bam)
5107 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5108 mmc_hostname(host->mmc), host->sps.reset_bam);
5109
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305110 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305111 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5112 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5113 host->curr.got_dataend, host->prog_enable,
5114 host->curr.wait_for_auto_prog_done,
5115 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305116 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305117}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005119static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5120{
5121 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5122 struct mmc_request *mrq;
5123 unsigned long flags;
5124
5125 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005126 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005127 pr_info("%s: %s: dummy CMD52 timeout\n",
5128 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005129 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005130 }
5131
5132 mrq = host->curr.mrq;
5133
5134 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305135 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
5136 mrq->cmd->opcode);
5137 msmsdcc_dump_sdcc_state(host);
5138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005139 if (!mrq->cmd->error)
5140 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305141 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005142 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005143 if (mrq->data && !mrq->data->error)
5144 mrq->data->error = -ETIMEDOUT;
5145 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305146 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005147 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305148 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005149 /* Stop current SPS transfer */
5150 msmsdcc_sps_exit_curr_xfer(host);
5151 } else {
5152 msmsdcc_reset_and_restore(host);
5153 msmsdcc_stop_data(host);
5154 if (mrq->data && mrq->data->stop)
5155 msmsdcc_start_command(host,
5156 mrq->data->stop, 0);
5157 else
5158 msmsdcc_request_end(host, mrq);
5159 }
5160 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305161 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305162 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005163 msmsdcc_reset_and_restore(host);
5164 msmsdcc_request_end(host, mrq);
5165 }
5166 }
5167 spin_unlock_irqrestore(&host->lock, flags);
5168}
5169
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305170/*
5171 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5172 *
5173 * @dev: device node from which the property value is to be read.
5174 * @prop_name: name of the property to be searched.
5175 * @out_array: filled array returned to caller
5176 * @len: filled array size returned to caller
5177 * @size: expected size of the array
5178 *
5179 * If expected "size" doesn't match with "len" an error is returned. If
5180 * expected size is zero, the length of actual array is returned provided
5181 * return value is zero.
5182 *
5183 * RETURNS:
5184 * zero on success, negative error if failed.
5185 */
5186static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5187 u32 **out_array, int *len, int size)
5188{
5189 int ret = 0;
5190 u32 *array = NULL;
5191 struct device_node *np = dev->of_node;
5192
5193 if (of_get_property(np, prop_name, len)) {
5194 size_t sz;
5195 sz = *len = *len / sizeof(*array);
5196
5197 if (sz > 0 && !(size > 0 && (sz != size))) {
5198 array = devm_kzalloc(dev, sz * sizeof(*array),
5199 GFP_KERNEL);
5200 if (!array) {
5201 dev_err(dev, "%s: no memory\n", prop_name);
5202 ret = -ENOMEM;
5203 goto out;
5204 }
5205
5206 ret = of_property_read_u32_array(np, prop_name,
5207 array, sz);
5208 if (ret < 0) {
5209 dev_err(dev, "%s: error reading array %d\n",
5210 prop_name, ret);
5211 goto out;
5212 }
5213 } else {
5214 dev_err(dev, "%s invalid size\n", prop_name);
5215 ret = -EINVAL;
5216 goto out;
5217 }
5218 } else {
5219 dev_err(dev, "%s not specified\n", prop_name);
5220 ret = -EINVAL;
5221 goto out;
5222 }
5223 *out_array = array;
5224out:
5225 if (ret)
5226 *len = 0;
5227 return ret;
5228}
5229
5230static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5231 struct msm_mmc_pad_pull_data **pad_pull_data)
5232{
5233 int ret = 0, base = 0, len, i;
5234 u32 *tmp;
5235 struct msm_mmc_pad_pull_data *pull_data;
5236 struct msm_mmc_pad_pull *pull;
5237
5238 switch (id) {
5239 case 1:
5240 base = TLMM_PULL_SDC1_CLK;
5241 break;
5242 case 2:
5243 base = TLMM_PULL_SDC2_CLK;
5244 break;
5245 case 3:
5246 base = TLMM_PULL_SDC3_CLK;
5247 break;
5248 case 4:
5249 base = TLMM_PULL_SDC4_CLK;
5250 break;
5251 default:
5252 dev_err(dev, "%s: Invalid slot id\n", __func__);
5253 ret = -EINVAL;
5254 goto err;
5255 }
5256
5257 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5258 GFP_KERNEL);
5259 if (!pull_data) {
5260 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5261 ret = -ENOMEM;
5262 goto err;
5263 }
5264 pull_data->size = 3; /* array size for clk, cmd, data */
5265
5266 /* Allocate on, off configs for clk, cmd, data */
5267 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5268 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5269 if (!pull) {
5270 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5271 ret = -ENOMEM;
5272 goto err;
5273 }
5274 pull_data->on = pull;
5275 pull_data->off = pull + pull_data->size;
5276
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005277 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305278 &tmp, &len, pull_data->size);
5279 if (!ret) {
5280 for (i = 0; i < len; i++) {
5281 pull_data->on[i].no = base + i;
5282 pull_data->on[i].val = tmp[i];
5283 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5284 i, pull_data->on[i].val);
5285 }
5286 } else {
5287 goto err;
5288 }
5289
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005290 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305291 &tmp, &len, pull_data->size);
5292 if (!ret) {
5293 for (i = 0; i < len; i++) {
5294 pull_data->off[i].no = base + i;
5295 pull_data->off[i].val = tmp[i];
5296 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5297 i, pull_data->off[i].val);
5298 }
5299 } else {
5300 goto err;
5301 }
5302
5303 *pad_pull_data = pull_data;
5304err:
5305 return ret;
5306}
5307
5308static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5309 struct msm_mmc_pad_drv_data **pad_drv_data)
5310{
5311 int ret = 0, base = 0, len, i;
5312 u32 *tmp;
5313 struct msm_mmc_pad_drv_data *drv_data;
5314 struct msm_mmc_pad_drv *drv;
5315
5316 switch (id) {
5317 case 1:
5318 base = TLMM_HDRV_SDC1_CLK;
5319 break;
5320 case 2:
5321 base = TLMM_HDRV_SDC2_CLK;
5322 break;
5323 case 3:
5324 base = TLMM_HDRV_SDC3_CLK;
5325 break;
5326 case 4:
5327 base = TLMM_HDRV_SDC4_CLK;
5328 break;
5329 default:
5330 dev_err(dev, "%s: Invalid slot id\n", __func__);
5331 ret = -EINVAL;
5332 goto err;
5333 }
5334
5335 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5336 GFP_KERNEL);
5337 if (!drv_data) {
5338 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5339 ret = -ENOMEM;
5340 goto err;
5341 }
5342 drv_data->size = 3; /* array size for clk, cmd, data */
5343
5344 /* Allocate on, off configs for clk, cmd, data */
5345 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5346 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5347 if (!drv) {
5348 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5349 ret = -ENOMEM;
5350 goto err;
5351 }
5352 drv_data->on = drv;
5353 drv_data->off = drv + drv_data->size;
5354
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005355 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305356 &tmp, &len, drv_data->size);
5357 if (!ret) {
5358 for (i = 0; i < len; i++) {
5359 drv_data->on[i].no = base + i;
5360 drv_data->on[i].val = tmp[i];
5361 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5362 i, drv_data->on[i].val);
5363 }
5364 } else {
5365 goto err;
5366 }
5367
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005368 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305369 &tmp, &len, drv_data->size);
5370 if (!ret) {
5371 for (i = 0; i < len; i++) {
5372 drv_data->off[i].no = base + i;
5373 drv_data->off[i].val = tmp[i];
5374 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5375 i, drv_data->off[i].val);
5376 }
5377 } else {
5378 goto err;
5379 }
5380
5381 *pad_drv_data = drv_data;
5382err:
5383 return ret;
5384}
5385
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305386static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5387 struct mmc_platform_data *pdata)
5388{
5389 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5390 struct device_node *np = dev->of_node;
5391
5392 pdata->status_gpio = of_get_named_gpio_flags(np,
5393 "cd-gpios", 0, &flags);
5394 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005395 struct platform_device *pdev = container_of(dev,
5396 struct platform_device, dev);
5397 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305398 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5399 }
5400
5401 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5402 "wp-gpios", 0, &flags);
5403 if (gpio_is_valid(pdata->wpswitch_gpio))
5404 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5405}
5406
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305407static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5408 struct mmc_platform_data *pdata)
5409{
5410 int ret = 0, id = 0, cnt, i;
5411 struct msm_mmc_pin_data *pin_data;
5412 struct device_node *np = dev->of_node;
5413
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305414 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5415
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305416 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5417 if (!pin_data) {
5418 dev_err(dev, "No memory for pin_data\n");
5419 ret = -ENOMEM;
5420 goto err;
5421 }
5422
5423 cnt = of_gpio_count(np);
5424 if (cnt > 0) {
5425 pin_data->is_gpio = true;
5426
5427 pin_data->gpio_data = devm_kzalloc(dev,
5428 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5429 if (!pin_data->gpio_data) {
5430 dev_err(dev, "No memory for gpio_data\n");
5431 ret = -ENOMEM;
5432 goto err;
5433 }
5434 pin_data->gpio_data->size = cnt;
5435 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5436 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5437 if (!pin_data->gpio_data->gpio) {
5438 dev_err(dev, "No memory for gpio\n");
5439 ret = -ENOMEM;
5440 goto err;
5441 }
5442
5443 for (i = 0; i < cnt; i++) {
5444 const char *name = NULL;
5445 char result[32];
5446 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5447 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005448 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305449
5450 snprintf(result, 32, "%s-%s",
5451 dev_name(dev), name ? name : "?");
5452 pin_data->gpio_data->gpio[i].name = result;
5453 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5454 pin_data->gpio_data->gpio[i].name,
5455 pin_data->gpio_data->gpio[i].no);
5456 }
5457 } else {
5458 pin_data->pad_data = devm_kzalloc(dev,
5459 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5460 if (!pin_data->pad_data) {
5461 dev_err(dev, "No memory for pin_data->pad_data\n");
5462 ret = -ENOMEM;
5463 goto err;
5464 }
5465
5466 of_property_read_u32(np, "cell-index", &id);
5467
5468 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5469 &pin_data->pad_data->pull);
5470 if (ret)
5471 goto err;
5472 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5473 &pin_data->pad_data->drv);
5474 if (ret)
5475 goto err;
5476 }
5477
5478 pdata->pin_data = pin_data;
5479err:
5480 if (ret)
5481 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5482 return ret;
5483}
5484
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305485#define MAX_PROP_SIZE 32
5486static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5487 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5488{
5489 int len, ret = 0;
5490 const __be32 *prop;
5491 char prop_name[MAX_PROP_SIZE];
5492 struct msm_mmc_reg_data *vreg;
5493 struct device_node *np = dev->of_node;
5494
5495 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5496 if (of_parse_phandle(np, prop_name, 0)) {
5497 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5498 if (!vreg) {
5499 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5500 ret = -ENOMEM;
5501 goto err;
5502 }
5503
5504 vreg->name = vreg_name;
5505
5506 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005507 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305508 if (of_get_property(np, prop_name, NULL))
5509 vreg->always_on = true;
5510
5511 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005512 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305513 if (of_get_property(np, prop_name, NULL))
5514 vreg->lpm_sup = true;
5515
5516 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005517 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305518 prop = of_get_property(np, prop_name, &len);
5519 if (!prop || (len != (2 * sizeof(__be32)))) {
5520 dev_warn(dev, "%s %s property\n",
5521 prop ? "invalid format" : "no", prop_name);
5522 } else {
5523 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5524 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5525 }
5526
5527 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005528 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305529 prop = of_get_property(np, prop_name, &len);
5530 if (!prop || (len != (2 * sizeof(__be32)))) {
5531 dev_warn(dev, "%s %s property\n",
5532 prop ? "invalid format" : "no", prop_name);
5533 } else {
5534 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5535 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5536 }
5537
5538 *vreg_data = vreg;
5539 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5540 vreg->name, vreg->always_on ? "always_on," : "",
5541 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5542 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5543 }
5544
5545err:
5546 return ret;
5547}
5548
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305549static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5550{
5551 int i, ret;
5552 struct mmc_platform_data *pdata;
5553 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305554 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005555 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305556 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305557
5558 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5559 if (!pdata) {
5560 dev_err(dev, "could not allocate memory for platform data\n");
5561 goto err;
5562 }
5563
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005564 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305565 if (bus_width == 8) {
5566 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5567 } else if (bus_width == 4) {
5568 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5569 } else {
5570 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5571 pdata->mmc_bus_width = 0;
5572 }
5573
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005574 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305575 &sup_voltages, &sup_volt_len, 0);
5576 if (!ret) {
5577 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305578 u32 mask;
5579
5580 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5581 sup_voltages[i + 1]);
5582 if (!mask)
5583 dev_err(dev, "Invalide voltage range %d\n", i);
5584 pdata->ocr_mask |= mask;
5585 }
5586 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305587 }
5588
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005589 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305590 &clk_table, &clk_table_len, 0);
5591 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305592 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305593 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305594 }
5595
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305596 pdata->vreg_data = devm_kzalloc(dev,
5597 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5598 if (!pdata->vreg_data) {
5599 dev_err(dev, "could not allocate memory for vreg_data\n");
5600 goto err;
5601 }
5602
5603 if (msmsdcc_dt_parse_vreg_info(dev,
5604 &pdata->vreg_data->vdd_data, "vdd"))
5605 goto err;
5606
5607 if (msmsdcc_dt_parse_vreg_info(dev,
5608 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5609 goto err;
5610
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305611 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5612 goto err;
5613
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005614 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305615
5616 for (i = 0; i < len; i++) {
5617 const char *name = NULL;
5618
5619 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005620 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305621 if (!name)
5622 continue;
5623
5624 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5625 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5626 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5627 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5628 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5629 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5630 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5631 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5632 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5633 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5634 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5635 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5636 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5637 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5638 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5639 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5640 | MMC_CAP_UHS_DDR50;
5641 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5642 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5643 | MMC_CAP_UHS_DDR50;
5644 }
5645
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005646 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305647 if (current_limit == 800)
5648 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5649 else if (current_limit == 600)
5650 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5651 else if (current_limit == 400)
5652 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5653 else if (current_limit == 200)
5654 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5655
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005656 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305657 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005658 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305659 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005660 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305661 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305662 of_property_read_u32(np, "qcom,dat1-mpm-int",
5663 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305664
5665 return pdata;
5666err:
5667 return NULL;
5668}
5669
San Mehat9d2bd732009-09-22 16:44:22 -07005670static int
5671msmsdcc_probe(struct platform_device *pdev)
5672{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305673 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005674 struct msmsdcc_host *host;
5675 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005676 unsigned long flags;
5677 struct resource *core_irqres = NULL;
5678 struct resource *bam_irqres = NULL;
5679 struct resource *core_memres = NULL;
5680 struct resource *dml_memres = NULL;
5681 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005682 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005683 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305684 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005685
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305686 if (pdev->dev.of_node) {
5687 plat = msmsdcc_populate_pdata(&pdev->dev);
5688 of_property_read_u32((&pdev->dev)->of_node,
5689 "cell-index", &pdev->id);
5690 } else {
5691 plat = pdev->dev.platform_data;
5692 }
San Mehat9d2bd732009-09-22 16:44:22 -07005693
5694 /* must have platform data */
5695 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005696 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005697 ret = -EINVAL;
5698 goto out;
5699 }
5700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005701 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005702 return -EINVAL;
5703
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305704 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5705 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5706 return -EINVAL;
5707 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005708
San Mehat9d2bd732009-09-22 16:44:22 -07005709 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005710 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005711 return -ENXIO;
5712 }
5713
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305714 core_memres = platform_get_resource_byname(pdev,
5715 IORESOURCE_MEM, "core_mem");
5716 bam_memres = platform_get_resource_byname(pdev,
5717 IORESOURCE_MEM, "bam_mem");
5718 dml_memres = platform_get_resource_byname(pdev,
5719 IORESOURCE_MEM, "dml_mem");
5720 core_irqres = platform_get_resource_byname(pdev,
5721 IORESOURCE_IRQ, "core_irq");
5722 bam_irqres = platform_get_resource_byname(pdev,
5723 IORESOURCE_IRQ, "bam_irq");
5724 dmares = platform_get_resource_byname(pdev,
5725 IORESOURCE_DMA, "dma_chnl");
5726 dma_crci_res = platform_get_resource_byname(pdev,
5727 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005729 if (!core_irqres || !core_memres) {
5730 pr_err("%s: Invalid sdcc core resource\n", __func__);
5731 return -ENXIO;
5732 }
5733
5734 /*
5735 * Both BAM and DML memory resource should be preset.
5736 * BAM IRQ resource should also be present.
5737 */
5738 if ((bam_memres && !dml_memres) ||
5739 (!bam_memres && dml_memres) ||
5740 ((bam_memres && dml_memres) && !bam_irqres)) {
5741 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005742 return -ENXIO;
5743 }
5744
5745 /*
5746 * Setup our host structure
5747 */
San Mehat9d2bd732009-09-22 16:44:22 -07005748 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5749 if (!mmc) {
5750 ret = -ENOMEM;
5751 goto out;
5752 }
5753
5754 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305755 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005756 host->plat = plat;
5757 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005758 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305759
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305760 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305761 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005762 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305763 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005765 host->base = ioremap(core_memres->start,
5766 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005767 if (!host->base) {
5768 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305769 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005770 }
5771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005772 host->core_irqres = core_irqres;
5773 host->bam_irqres = bam_irqres;
5774 host->core_memres = core_memres;
5775 host->dml_memres = dml_memres;
5776 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005777 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005778 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005779 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305780 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005782#ifdef CONFIG_MMC_EMBEDDED_SDIO
5783 if (plat->embedded_sdio)
5784 mmc_set_embedded_sdio_data(mmc,
5785 &plat->embedded_sdio->cis,
5786 &plat->embedded_sdio->cccr,
5787 plat->embedded_sdio->funcs,
5788 plat->embedded_sdio->num_funcs);
5789#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005790
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305791 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5792 (unsigned long)host);
5793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005794 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5795 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305796 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005797 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305798 ret = msmsdcc_init_dma(host);
5799 if (ret)
5800 goto ioremap_free;
5801 } else {
5802 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005803 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305804 }
San Mehat9d2bd732009-09-22 16:44:22 -07005805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005806 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305807 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005808 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305809 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5810 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5811 /* Vote for max. clk rate for max. performance */
5812 ret = clk_set_rate(host->bus_clk, INT_MAX);
5813 if (ret)
5814 goto bus_clk_put;
5815 ret = clk_prepare_enable(host->bus_clk);
5816 if (ret)
5817 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005818 }
5819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005820 /*
5821 * Setup main peripheral bus clock
5822 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005823 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005824 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305825 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005826 if (ret)
5827 goto pclk_put;
5828
5829 host->pclk_rate = clk_get_rate(host->pclk);
5830 }
5831
5832 /*
5833 * Setup SDC MMC clock
5834 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005835 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005836 if (IS_ERR(host->clk)) {
5837 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005838 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005839 }
5840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005841 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05305842 if (ret) {
5843 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
5844 goto clk_put;
5845 }
5846
Asutosh Dasf5298c32012-04-03 14:51:47 +05305847 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07005848 if (ret)
5849 goto clk_put;
5850
San Mehat9d2bd732009-09-22 16:44:22 -07005851 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305852 if (!host->clk_rate)
5853 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305854
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305855 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05305856 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305857
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05305858 /*
5859 * Set the register write delay according to min. clock frequency
5860 * supported and update later when the host->clk_rate changes.
5861 */
5862 host->reg_write_delay =
5863 (1 + ((3 * USEC_PER_SEC) /
5864 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005865
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305866 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05305867 /* Apply Hard reset to SDCC to put it in power on default state */
5868 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005869
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005870#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305871 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005872 if (host->plat->cpu_dma_latency)
5873 host->cpu_dma_latency = host->plat->cpu_dma_latency;
5874 else
5875 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
5876 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305877 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
5878
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305879 ret = msmsdcc_msm_bus_register(host);
5880 if (ret)
5881 goto pm_qos_remove;
5882
5883 if (host->msm_bus_vote.client_handle)
5884 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
5885 msmsdcc_msm_bus_work);
5886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005887 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07005888 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005889 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07005890 goto clk_disable;
5891 }
5892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005893
5894 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305895 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005896 /* Initialize SPS */
5897 ret = msmsdcc_sps_init(host);
5898 if (ret)
5899 goto vreg_deinit;
5900 /* Initialize DML */
5901 ret = msmsdcc_dml_init(host);
5902 if (ret)
5903 goto sps_exit;
5904 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05305905 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07005906
San Mehat9d2bd732009-09-22 16:44:22 -07005907 /*
5908 * Setup MMC host structure
5909 */
5910 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005911 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
5912 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005913 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05305914 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
5915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005916 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
5917 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07005918 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305919 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05305920 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305921 /*
5922 * If we send the CMD23 before multi block write/read command
5923 * then we need not to send CMD12 at the end of the transfer.
5924 * If we don't send the CMD12 then only way to detect the PROG_DONE
5925 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5926 * controller. So let's enable the CMD23 for SDCC4 only.
5927 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305928 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305929 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07005930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005931 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305932 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005933 /*
5934 * XPC controls the maximum current in the default speed mode of SDXC
5935 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5936 * XPC=1 means 150mA (max.) and speed class is supported.
5937 */
5938 if (plat->xpc_cap)
5939 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5940 MMC_CAP_SET_XPC_180);
5941
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02005942 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02005943 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305944 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03005945 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03005946 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Maya Erezb7f382b2012-09-29 06:33:18 +02005947 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02005948 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Yaniv Gardi14098552012-06-04 10:56:03 +03005949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005950 if (plat->nonremovable)
5951 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005952 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005953
5954 if (plat->is_sdio_al_client)
5955 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005956
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305957 mmc->max_segs = msmsdcc_get_nr_sg(host);
5958 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5959 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005960
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305961 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005962 mmc->max_seg_size = mmc->max_req_size;
5963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005964 writel_relaxed(0, host->base + MMCIMASK0);
5965 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305966 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005968 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5969 mb();
5970 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005972 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5973 DRIVER_NAME " (cmd)", host);
5974 if (ret)
5975 goto dml_exit;
5976
5977 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5978 DRIVER_NAME " (pio)", host);
5979 if (ret)
5980 goto irq_free;
5981
5982 /*
5983 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5984 * IRQ is un-necessarily being monitored by MPM (Modem power
5985 * management block) during idle-power collapse. The MPM will be
5986 * configured to monitor the DATA1 GPIO line with level-low trigger
5987 * and thus depending on the GPIO status, it prevents TCXO shutdown
5988 * during idle-power collapse.
5989 */
5990 disable_irq(core_irqres->start);
5991 host->sdcc_irq_disabled = 1;
5992
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305993 if (!plat->sdiowakeup_irq) {
5994 /* Check if registered as IORESOURCE_IRQ */
5995 plat->sdiowakeup_irq =
5996 platform_get_irq_byname(pdev, "sdiowakeup_irq");
5997 if (plat->sdiowakeup_irq < 0)
5998 plat->sdiowakeup_irq = 0;
5999 }
6000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006001 if (plat->sdiowakeup_irq) {
6002 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6003 mmc_hostname(mmc));
6004 ret = request_irq(plat->sdiowakeup_irq,
6005 msmsdcc_platform_sdiowakeup_irq,
6006 IRQF_SHARED | IRQF_TRIGGER_LOW,
6007 DRIVER_NAME "sdiowakeup", host);
6008 if (ret) {
6009 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6010 plat->sdiowakeup_irq, ret);
6011 goto pio_irq_free;
6012 } else {
6013 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306014 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006015 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306016 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006017 }
6018 spin_unlock_irqrestore(&host->lock, flags);
6019 }
6020 }
6021
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306022 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006023 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6024 mmc_hostname(mmc));
6025 }
6026
6027 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6028 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006029 /*
6030 * Setup card detect change
6031 */
6032
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306033 if (!plat->status_gpio)
6034 plat->status_gpio = -ENOENT;
6035 if (!plat->wpswitch_gpio)
6036 plat->wpswitch_gpio = -ENOENT;
6037
6038 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306039 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006040 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306041 } else {
6042 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006043 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306044 }
Krishna Konda941604a2012-01-10 17:46:34 -08006045 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006046 }
San Mehat9d2bd732009-09-22 16:44:22 -07006047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006048 if (plat->status_irq) {
6049 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006050 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006051 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006052 DRIVER_NAME " (slot)",
6053 host);
6054 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006055 pr_err("Unable to get slot IRQ %d (%d)\n",
6056 plat->status_irq, ret);
6057 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006058 }
6059 } else if (plat->register_status_notify) {
6060 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6061 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006062 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006063 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006064
6065 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006066
6067 ret = pm_runtime_set_active(&(pdev)->dev);
6068 if (ret < 0)
6069 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6070 __func__, ret);
6071 /*
6072 * There is no notion of suspend/resume for SD/MMC/SDIO
6073 * cards. So host can be suspended/resumed with out
6074 * worrying about its children.
6075 */
6076 pm_suspend_ignore_children(&(pdev)->dev, true);
6077
6078 /*
6079 * MMC/SD/SDIO bus suspend/resume operations are defined
6080 * only for the slots that will be used for non-removable
6081 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6082 * defined. Otherwise, they simply become card removal and
6083 * insertion events during suspend and resume respectively.
6084 * Hence, enable run-time PM only for slots for which bus
6085 * suspend/resume operations are defined.
6086 */
6087#ifdef CONFIG_MMC_UNSAFE_RESUME
6088 /*
6089 * If this capability is set, MMC core will enable/disable host
6090 * for every claim/release operation on a host. We use this
6091 * notification to increment/decrement runtime pm usage count.
6092 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006093 pm_runtime_enable(&(pdev)->dev);
6094#else
6095 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006096 pm_runtime_enable(&(pdev)->dev);
6097 }
6098#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306099 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006100 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6101 (unsigned long)host);
6102
San Mehat9d2bd732009-09-22 16:44:22 -07006103 mmc_add_host(mmc);
6104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006105#ifdef CONFIG_HAS_EARLYSUSPEND
6106 host->early_suspend.suspend = msmsdcc_early_suspend;
6107 host->early_suspend.resume = msmsdcc_late_resume;
6108 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
6109 register_early_suspend(&host->early_suspend);
6110#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006111
Krishna Konda25786ec2011-07-25 16:21:36 -07006112 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
6113 " dmacrcri %d\n", mmc_hostname(mmc),
6114 (unsigned long long)core_memres->start,
6115 (unsigned int) core_irqres->start,
6116 (unsigned int) plat->status_irq, host->dma.channel,
6117 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006118
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306119 pr_info("%s: Controller capabilities: 0x%.8x\n",
6120 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006121 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6122 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6123 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6124 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6125 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6126 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6127 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6128 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6129 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6130 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6131 host->eject);
6132 pr_info("%s: Power save feature enable = %d\n",
6133 mmc_hostname(mmc), msmsdcc_pwrsave);
6134
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306135 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006136 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006137 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006138 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006139 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 mmc_hostname(mmc), host->dma.cmd_busaddr,
6141 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306142 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006143 pr_info("%s: SPS-BAM data transfer mode available\n",
6144 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006145 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006146 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006148#if defined(CONFIG_DEBUG_FS)
6149 msmsdcc_dbg_createhost(host);
6150#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306151
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306152 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6153 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6154 sysfs_attr_init(&host->max_bus_bw.attr);
6155 host->max_bus_bw.attr.name = "max_bus_bw";
6156 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6157 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306158 if (ret)
6159 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306160
6161 if (!plat->status_irq) {
6162 host->polling.show = show_polling;
6163 host->polling.store = store_polling;
6164 sysfs_attr_init(&host->polling.attr);
6165 host->polling.attr.name = "polling";
6166 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6167 ret = device_create_file(&pdev->dev, &host->polling);
6168 if (ret)
6169 goto remove_max_bus_bw_file;
6170 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306171 host->idle_timeout.show = show_idle_timeout;
6172 host->idle_timeout.store = store_idle_timeout;
6173 sysfs_attr_init(&host->idle_timeout.attr);
6174 host->idle_timeout.attr.name = "idle_timeout";
6175 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6176 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6177 if (ret)
6178 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306179
6180 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306181 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306182
6183 /* Sysfs entry for AUTO CMD19 control */
6184 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6185 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6186 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6187 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6188 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6189 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6190 if (ret)
6191 goto remove_idle_timeout_file;
6192
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306193 add_auto_cmd21_atrr:
6194 if (!is_auto_cmd21(host))
6195 goto exit;
6196
6197 /* Sysfs entry for AUTO CMD21 control */
6198 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6199 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6200 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6201 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6202 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6203 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6204 if (ret)
6205 goto remove_auto_cmd19_attr_file;
6206
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306207 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006208 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006209
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306210 remove_auto_cmd19_attr_file:
6211 if (is_auto_cmd19(host))
6212 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306213 remove_idle_timeout_file:
6214 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306215 remove_polling_file:
6216 if (!plat->status_irq)
6217 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306218 remove_max_bus_bw_file:
6219 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006220 platform_irq_free:
6221 del_timer_sync(&host->req_tout_timer);
6222 pm_runtime_disable(&(pdev)->dev);
6223 pm_runtime_set_suspended(&(pdev)->dev);
6224
6225 if (plat->status_irq)
6226 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306227 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006228 sdiowakeup_irq_free:
6229 wake_lock_destroy(&host->sdio_suspend_wlock);
6230 if (plat->sdiowakeup_irq)
6231 free_irq(plat->sdiowakeup_irq, host);
6232 pio_irq_free:
6233 if (plat->sdiowakeup_irq)
6234 wake_lock_destroy(&host->sdio_wlock);
6235 free_irq(core_irqres->start, host);
6236 irq_free:
6237 free_irq(core_irqres->start, host);
6238 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306239 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006240 msmsdcc_dml_exit(host);
6241 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306242 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006243 msmsdcc_sps_exit(host);
6244 vreg_deinit:
6245 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006246 clk_disable:
Krishna Konda7dd56c22012-11-08 17:52:32 -08006247 clk_disable_unprepare(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306248 msmsdcc_msm_bus_unregister(host);
6249 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006250 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306251 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006252 clk_put:
6253 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006254 pclk_disable:
6255 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306256 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006257 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006258 if (!IS_ERR(host->pclk))
6259 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306260 if (!IS_ERR_OR_NULL(host->bus_clk))
6261 clk_disable_unprepare(host->bus_clk);
6262 bus_clk_put:
6263 if (!IS_ERR_OR_NULL(host->bus_clk))
6264 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306265 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006266 if (host->dmares)
6267 dma_free_coherent(NULL,
6268 sizeof(struct msmsdcc_nc_dmadata),
6269 host->dma.nc, host->dma.nc_busaddr);
6270 }
6271 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306272 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006273 host_free:
6274 mmc_free_host(mmc);
6275 out:
6276 return ret;
6277}
6278
Pratibhasagar V713817b2012-09-07 11:28:30 +05306279#ifdef CONFIG_DEBUG_FS
6280static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6281{
6282 debugfs_remove_recursive(host->debugfs_host_dir);
6283 host->debugfs_host_dir = NULL;
6284}
6285#else
6286static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6287#endif
6288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006289static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006290{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006291 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6292 struct mmc_platform_data *plat;
6293 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006295 if (!mmc)
6296 return -ENXIO;
6297
6298 if (pm_runtime_suspended(&(pdev)->dev))
6299 pm_runtime_resume(&(pdev)->dev);
6300
6301 host = mmc_priv(mmc);
6302
6303 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6304 plat = host->plat;
6305
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306306 if (is_auto_cmd19(host))
6307 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306308 if (is_auto_cmd21(host))
6309 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306310 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006311 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306312 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306313 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006314
Pratibhasagar V713817b2012-09-07 11:28:30 +05306315 msmsdcc_remove_debugfs(host);
6316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006317 del_timer_sync(&host->req_tout_timer);
6318 tasklet_kill(&host->dma_tlet);
6319 tasklet_kill(&host->sps.tlet);
6320 mmc_remove_host(mmc);
6321
6322 if (plat->status_irq)
6323 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306324 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006325
6326 wake_lock_destroy(&host->sdio_suspend_wlock);
6327 if (plat->sdiowakeup_irq) {
6328 wake_lock_destroy(&host->sdio_wlock);
6329 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6330 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006331 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006332
6333 free_irq(host->core_irqres->start, host);
6334 free_irq(host->core_irqres->start, host);
6335
6336 clk_put(host->clk);
6337 if (!IS_ERR(host->pclk))
6338 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306339 if (!IS_ERR_OR_NULL(host->bus_clk))
6340 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006341
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006342 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306343 pm_qos_remove_request(&host->pm_qos_req_dma);
6344
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306345 if (host->msm_bus_vote.client_handle) {
6346 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6347 msmsdcc_msm_bus_unregister(host);
6348 }
6349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006350 msmsdcc_vreg_init(host, false);
6351
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306352 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006353 if (host->dmares)
6354 dma_free_coherent(NULL,
6355 sizeof(struct msmsdcc_nc_dmadata),
6356 host->dma.nc, host->dma.nc_busaddr);
6357 }
6358
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306359 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006360 msmsdcc_dml_exit(host);
6361 msmsdcc_sps_exit(host);
6362 }
6363
6364 iounmap(host->base);
6365 mmc_free_host(mmc);
6366
6367#ifdef CONFIG_HAS_EARLYSUSPEND
6368 unregister_early_suspend(&host->early_suspend);
6369#endif
6370 pm_runtime_disable(&(pdev)->dev);
6371 pm_runtime_set_suspended(&(pdev)->dev);
6372
6373 return 0;
6374}
6375
6376#ifdef CONFIG_MSM_SDIO_AL
6377int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6378{
6379 struct msmsdcc_host *host = mmc_priv(mmc);
6380 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306381 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006382
Asutosh Dasf5298c32012-04-03 14:51:47 +05306383 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006384 spin_lock_irqsave(&host->lock, flags);
6385 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6386 enable ? "En" : "Dis");
6387
6388 if (enable) {
6389 if (!host->sdcc_irq_disabled) {
6390 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306391 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006392 host->sdcc_irq_disabled = 1;
6393 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306394 rc = msmsdcc_setup_clocks(host, false);
6395 if (rc)
6396 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006397
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306398 if (host->plat->sdio_lpm_gpio_setup &&
6399 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006400 spin_unlock_irqrestore(&host->lock, flags);
6401 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6402 spin_lock_irqsave(&host->lock, flags);
6403 host->sdio_gpio_lpm = 1;
6404 }
6405
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306406 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006407 msmsdcc_enable_irq_wake(host);
6408 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306409 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006410 }
6411 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306412 rc = msmsdcc_setup_clocks(host, true);
6413 if (rc)
6414 goto out;
6415
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306416 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006417 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306418 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006419 msmsdcc_disable_irq_wake(host);
6420 }
6421
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306422 if (host->plat->sdio_lpm_gpio_setup &&
6423 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006424 spin_unlock_irqrestore(&host->lock, flags);
6425 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6426 spin_lock_irqsave(&host->lock, flags);
6427 host->sdio_gpio_lpm = 0;
6428 }
6429
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306430 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006431 writel_relaxed(host->mci_irqenable,
6432 host->base + MMCIMASK0);
6433 mb();
6434 enable_irq(host->core_irqres->start);
6435 host->sdcc_irq_disabled = 0;
6436 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006437 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306438out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006439 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306440 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306441 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006442}
6443#else
6444int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6445{
6446 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006447}
6448#endif
6449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006450#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306451#ifdef CONFIG_MMC_CLKGATE
6452static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6453{
6454 struct mmc_host *mmc = host->mmc;
6455 unsigned long flags;
6456
6457 mmc_host_clk_hold(mmc);
6458 spin_lock_irqsave(&mmc->clk_lock, flags);
6459 mmc->clk_old = mmc->ios.clock;
6460 mmc->ios.clock = 0;
6461 mmc->clk_gated = true;
6462 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6463 mmc_set_ios(mmc);
6464 mmc_host_clk_release(mmc);
6465}
6466
6467static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6468{
6469 struct mmc_host *mmc = host->mmc;
6470
6471 mmc_host_clk_hold(mmc);
6472 mmc->ios.clock = host->clk_rate;
6473 mmc_set_ios(mmc);
6474 mmc_host_clk_release(mmc);
6475}
6476#else
6477static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6478{
6479 struct mmc_host *mmc = host->mmc;
6480
6481 mmc->ios.clock = 0;
6482 mmc_set_ios(mmc);
6483}
6484
6485static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6486{
6487 struct mmc_host *mmc = host->mmc;
6488
6489 mmc->ios.clock = host->clk_rate;
6490 mmc_set_ios(mmc);
6491}
6492#endif
6493
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306494#if CONFIG_DEBUG_FS
6495static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
6496 const char *func)
6497{
6498 ktime_t diff;
6499
6500 if (host->print_pm_stats) {
6501 diff = ktime_sub(ktime_get(), start);
6502 pr_info("%s: %s: Completed in %llu usec\n", func,
6503 mmc_hostname(host->mmc), (u64)ktime_to_us(diff));
6504 }
6505}
6506#else
6507static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
6508 const char *func) {}
6509#endif
6510
San Mehat9d2bd732009-09-22 16:44:22 -07006511static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006512msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006513{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006514 struct mmc_host *mmc = dev_get_drvdata(dev);
6515 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006516 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306517 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306518 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006519
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306520 if (host->plat->is_sdio_al_client) {
6521 rc = 0;
6522 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006523 }
San Mehat9d2bd732009-09-22 16:44:22 -07006524
Sahitya Tummala7661a452011-07-18 13:28:35 +05306525 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006526 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006527 host->sdcc_suspending = 1;
6528 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006530 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006531 * MMC core thinks that host is disabled by now since
6532 * runtime suspend is scheduled after msmsdcc_disable()
6533 * is called. Thus, MMC core will try to enable the host
6534 * while suspending it. This results in a synchronous
6535 * runtime resume request while in runtime suspending
6536 * context and hence inorder to complete this resume
6537 * requet, it will wait for suspend to be complete,
6538 * but runtime suspend also can not proceed further
6539 * until the host is resumed. Thus, it leads to a hang.
6540 * Hence, increase the pm usage count before suspending
6541 * the host so that any resume requests after this will
6542 * simple become pm usage counter increment operations.
6543 */
6544 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306545 /* If there is pending detect work abort runtime suspend */
6546 if (unlikely(work_busy(&mmc->detect.work)))
6547 rc = -EAGAIN;
6548 else
6549 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006550 pm_runtime_put_noidle(dev);
6551
6552 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306553 spin_lock_irqsave(&host->lock, flags);
6554 host->sdcc_suspended = true;
6555 spin_unlock_irqrestore(&host->lock, flags);
6556 if (mmc->card && mmc_card_sdio(mmc->card) &&
6557 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006558 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306559 * If SDIO function driver doesn't want
6560 * to power off the card, atleast turn off
6561 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006562 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306563 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006564 }
6565 }
6566 host->sdcc_suspending = 0;
6567 mmc->suspend_task = NULL;
6568 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6569 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006570 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306571 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306572out:
6573 /* set bus bandwidth to 0 immediately */
6574 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306575 msmsdcc_print_pm_stats(host, start, __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006576 return rc;
6577}
6578
6579static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006580msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006581{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006582 struct mmc_host *mmc = dev_get_drvdata(dev);
6583 struct msmsdcc_host *host = mmc_priv(mmc);
6584 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306585 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006587 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306588 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006589
Sahitya Tummala7661a452011-07-18 13:28:35 +05306590 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006591 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306592 if (mmc->card && mmc_card_sdio(mmc->card) &&
6593 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306594 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306595 }
San Mehat9d2bd732009-09-22 16:44:22 -07006596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006597 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006599 /*
6600 * FIXME: Clearing of flags must be handled in clients
6601 * resume handler.
6602 */
6603 spin_lock_irqsave(&host->lock, flags);
6604 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306605 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006606 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006608 /*
6609 * After resuming the host wait for sometime so that
6610 * the SDIO work will be processed.
6611 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306612 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306613 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006614 host->plat->sdiowakeup_irq) &&
6615 wake_lock_active(&host->sdio_wlock))
6616 wake_lock_timeout(&host->sdio_wlock, 1);
6617 }
6618
6619 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006620 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306621 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306622 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306623out:
6624 msmsdcc_print_pm_stats(host, start, __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006625 return 0;
6626}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006627
6628static int msmsdcc_runtime_idle(struct device *dev)
6629{
6630 struct mmc_host *mmc = dev_get_drvdata(dev);
6631 struct msmsdcc_host *host = mmc_priv(mmc);
6632
6633 if (host->plat->is_sdio_al_client)
6634 return 0;
6635
6636 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306637 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006638
6639 return -EAGAIN;
6640}
6641
6642static int msmsdcc_pm_suspend(struct device *dev)
6643{
6644 struct mmc_host *mmc = dev_get_drvdata(dev);
6645 struct msmsdcc_host *host = mmc_priv(mmc);
6646 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306647 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006648
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306649 if (host->plat->is_sdio_al_client) {
6650 rc = 0;
6651 goto out;
6652 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306653 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006654 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306655 msmsdcc_disable_status_gpio(host);
6656 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006657
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006658 if (!pm_runtime_suspended(dev))
6659 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306660 out:
6661 msmsdcc_print_pm_stats(host, start, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006662 return rc;
6663}
6664
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306665static int msmsdcc_suspend_noirq(struct device *dev)
6666{
6667 struct mmc_host *mmc = dev_get_drvdata(dev);
6668 struct msmsdcc_host *host = mmc_priv(mmc);
6669 int rc = 0;
6670
6671 /*
6672 * After platform suspend there may be active request
6673 * which might have enabled clocks. For example, in SDIO
6674 * case, ksdioirq thread might have scheduled after sdcc
6675 * suspend but before system freeze. In that case abort
6676 * suspend and retry instead of keeping the clocks on
6677 * during suspend and not allowing TCXO.
6678 */
6679
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306680 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306681 pr_warn("%s: clocks are on after suspend, aborting system "
6682 "suspend\n", mmc_hostname(mmc));
6683 rc = -EAGAIN;
6684 }
6685
6686 return rc;
6687}
6688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006689static int msmsdcc_pm_resume(struct device *dev)
6690{
6691 struct mmc_host *mmc = dev_get_drvdata(dev);
6692 struct msmsdcc_host *host = mmc_priv(mmc);
6693 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306694 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006695
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306696 if (host->plat->is_sdio_al_client) {
6697 rc = 0;
6698 goto out;
6699 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006700 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306701 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306702 /*
6703 * As runtime PM is enabled before calling the device's platform resume
6704 * callback, we use the pm_runtime_suspended API to know if SDCC is
6705 * really runtime suspended or not and set the pending_resume flag only
6706 * if its not runtime suspended.
6707 */
6708 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006709 host->pending_resume = true;
6710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006711 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306712 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006713 msmsdcc_check_status((unsigned long)host);
6714 enable_irq(host->plat->status_irq);
6715 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306716out:
6717 msmsdcc_print_pm_stats(host, start, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006718 return rc;
6719}
6720
Daniel Walker08ecfde2010-06-23 12:32:20 -07006721#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006722static int msmsdcc_runtime_suspend(struct device *dev)
6723{
6724 return 0;
6725}
6726static int msmsdcc_runtime_idle(struct device *dev)
6727{
6728 return 0;
6729}
6730static int msmsdcc_pm_suspend(struct device *dev)
6731{
6732 return 0;
6733}
6734static int msmsdcc_pm_resume(struct device *dev)
6735{
6736 return 0;
6737}
6738static int msmsdcc_suspend_noirq(struct device *dev)
6739{
6740 return 0;
6741}
6742static int msmsdcc_runtime_resume(struct device *dev)
6743{
6744 return 0;
6745}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006746#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006748static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6749 .runtime_suspend = msmsdcc_runtime_suspend,
6750 .runtime_resume = msmsdcc_runtime_resume,
6751 .runtime_idle = msmsdcc_runtime_idle,
6752 .suspend = msmsdcc_pm_suspend,
6753 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306754 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006755};
6756
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306757static const struct of_device_id msmsdcc_dt_match[] = {
6758 {.compatible = "qcom,msm-sdcc"},
6759
6760};
6761MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6762
San Mehat9d2bd732009-09-22 16:44:22 -07006763static struct platform_driver msmsdcc_driver = {
6764 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006765 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006766 .driver = {
6767 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006768 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306769 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006770 },
6771};
6772
6773static int __init msmsdcc_init(void)
6774{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006775#if defined(CONFIG_DEBUG_FS)
6776 int ret = 0;
6777 ret = msmsdcc_dbg_init();
6778 if (ret) {
6779 pr_err("Failed to create debug fs dir \n");
6780 return ret;
6781 }
6782#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006783 return platform_driver_register(&msmsdcc_driver);
6784}
San Mehat9d2bd732009-09-22 16:44:22 -07006785
San Mehat9d2bd732009-09-22 16:44:22 -07006786static void __exit msmsdcc_exit(void)
6787{
6788 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006789
6790#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006791 debugfs_remove(debugfs_dir);
6792#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006793}
6794
6795module_init(msmsdcc_init);
6796module_exit(msmsdcc_exit);
6797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006798MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006799MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006800
6801#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05306802static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006803{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306804 struct msmsdcc_host *host = data;
6805
6806 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006807 return 0;
6808}
6809
Pratibhasagar V713817b2012-09-07 11:28:30 +05306810static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006811{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306812 struct msmsdcc_host *host = data;
6813 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006814
Pratibhasagar V713817b2012-09-07 11:28:30 +05306815 spin_lock_irqsave(&host->lock, flags);
6816 host->idle_tout = (u32)val * 1000;
6817 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006818
Pratibhasagar V713817b2012-09-07 11:28:30 +05306819 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006820}
6821
Pratibhasagar V713817b2012-09-07 11:28:30 +05306822DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
6823 msmsdcc_dbg_idle_tout_get,
6824 msmsdcc_dbg_idle_tout_set,
6825 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006826
Pratibhasagar V889d61c2012-09-09 19:51:14 +05306827static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
6828{
6829 struct msmsdcc_host *host = data;
6830
6831 *val = (u64) host->enforce_pio_mode;
6832 return 0;
6833}
6834
6835static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
6836{
6837 struct msmsdcc_host *host = data;
6838 unsigned long flags;
6839
6840 spin_lock_irqsave(&host->lock, flags);
6841 host->enforce_pio_mode = !!val;
6842 spin_unlock_irqrestore(&host->lock, flags);
6843
6844 return 0;
6845}
6846
6847DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
6848 msmsdcc_dbg_pio_mode_get,
6849 msmsdcc_dbg_pio_mode_set,
6850 "%llu\n");
6851
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306852static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
6853{
6854 struct msmsdcc_host *host = data;
6855
6856 *val = !!host->print_pm_stats;
6857 return 0;
6858}
6859
6860static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
6861{
6862 struct msmsdcc_host *host = data;
6863 unsigned long flags;
6864
6865 spin_lock_irqsave(&host->lock, flags);
6866 host->print_pm_stats = !!val;
6867 spin_unlock_irqrestore(&host->lock, flags);
6868
6869 return 0;
6870}
6871
6872DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
6873 msmsdcc_dbg_pm_stats_get,
6874 msmsdcc_dbg_pm_stats_set,
6875 "%llu\n");
6876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006877static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
6878{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306879 int err = 0;
6880
6881 if (!debugfs_dir)
6882 return;
6883
6884 host->debugfs_host_dir = debugfs_create_dir(
6885 mmc_hostname(host->mmc), debugfs_dir);
6886 if (IS_ERR(host->debugfs_host_dir)) {
6887 err = PTR_ERR(host->debugfs_host_dir);
6888 host->debugfs_host_dir = NULL;
6889 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
6890 mmc_hostname(host->mmc), err);
6891 return;
6892 }
6893
6894 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
6895 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
6896 &msmsdcc_dbg_idle_tout_ops);
6897
6898 if (IS_ERR(host->debugfs_idle_tout)) {
6899 err = PTR_ERR(host->debugfs_idle_tout);
6900 host->debugfs_idle_tout = NULL;
6901 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
6902 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006903 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05306904
6905 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
6906 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
6907 &msmsdcc_dbg_pio_mode_ops);
6908
6909 if (IS_ERR(host->debugfs_pio_mode)) {
6910 err = PTR_ERR(host->debugfs_pio_mode);
6911 host->debugfs_pio_mode = NULL;
6912 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
6913 mmc_hostname(host->mmc), err);
6914 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306915
6916 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
6917 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
6918 &msmsdcc_dbg_pm_stats_ops);
6919 if (IS_ERR(host->debugfs_pm_stats)) {
6920 err = PTR_ERR(host->debugfs_pm_stats);
6921 host->debugfs_pm_stats = NULL;
6922 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
6923 mmc_hostname(host->mmc), err);
6924 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006925}
6926
6927static int __init msmsdcc_dbg_init(void)
6928{
6929 int err;
6930
Pratibhasagar V713817b2012-09-07 11:28:30 +05306931 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006932 if (IS_ERR(debugfs_dir)) {
6933 err = PTR_ERR(debugfs_dir);
6934 debugfs_dir = NULL;
6935 return err;
6936 }
6937
6938 return 0;
6939}
6940#endif