blob: f3973ef54ff304692a40aa70cbb99913af2eadc3 [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.
Sujit Reddy Thumma1f2ae7c2013-01-10 09:33:57 +05306 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07007 *
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
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -0800128static int disable_slots;
129module_param(disable_slots, int, 0);
130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131#if IRQ_DEBUG == 1
132static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
133 "dattimeout", "txunderrun", "rxoverrun",
134 "cmdrespend", "cmdsent", "dataend", NULL,
135 "datablkend", "cmdactive", "txactive",
136 "rxactive", "txhalfempty", "rxhalffull",
137 "txfifofull", "rxfifofull", "txfifoempty",
138 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
139 "sdiointr", "progdone", "atacmdcompl",
140 "sdiointrope", "ccstimeout", NULL, NULL,
141 NULL, NULL, NULL };
142
143static void
144msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800145{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
149 for (i = 0; i < 32; i++) {
150 if (status & (1 << i))
151 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800154}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155#endif
San Mehat865c8062009-11-13 13:42:06 -0800156
San Mehat9d2bd732009-09-22 16:44:22 -0700157static void
158msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
159 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530160static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530161static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530162static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800163static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800164static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700165static int msmsdcc_runtime_resume(struct device *dev);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530166static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
167 u32 **out_array, int *len, int size);
Subhash Jadavani355df542012-10-09 19:06:49 +0530168static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode);
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530169static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
170 struct mmc_request *mrq);
171static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
172 struct mmc_request *mrq);
San Mehat9d2bd732009-09-22 16:44:22 -0700173
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530174static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530175{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530176 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530177
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530178 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530179 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530180 } else { /* DMA or PIO mode */
181 if (NR_SG > MAX_NR_SG_DMA_PIO)
182 ret = MAX_NR_SG_DMA_PIO;
183 }
184
185 return ret;
186}
187
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530188/* Prevent idle power collapse(pc) while operating in peripheral mode */
189static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
190{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700191 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530192 return;
193
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530194 if (vote)
195 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700196 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530197 else
198 pm_qos_update_request(&host->pm_qos_req_dma,
199 PM_QOS_DEFAULT_VALUE);
200}
201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
203static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
204 struct msmsdcc_sps_ep_conn_data *ep);
205static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep);
207#else
208static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
209 struct msmsdcc_sps_ep_conn_data *ep,
210 bool is_producer) { return 0; }
211static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
212 struct msmsdcc_sps_ep_conn_data *ep) { }
213static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
214 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530215{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 return 0;
217}
218static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
219 struct msmsdcc_sps_ep_conn_data *ep)
220{
221 return 0;
222}
223static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
224static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
225#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227/**
Krishna Konda3ca90f02012-08-29 16:29:21 -0700228 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530229 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700230 * This function resets SPS BAM and DML cores.
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530231 *
232 * This function should be called to recover from error
233 * conditions encountered during CMD/DATA tranfsers with card.
234 *
235 * @host - Pointer to driver's host structure
236 *
237 */
Krishna Konda3ca90f02012-08-29 16:29:21 -0700238static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530239{
240 int rc;
241
242 /* 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
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530265 memset(host->sps.prod.config.desc.base, 0x00,
266 host->sps.prod.config.desc.size);
267 memset(host->sps.cons.config.desc.base, 0x00,
268 host->sps.cons.config.desc.size);
269
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530270 /* Restore all BAM pipes connections */
271 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700272 if (rc) {
273 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530274 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700275 goto out;
276 }
277
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530278 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530279 if (rc) {
Krishna Konda3ca90f02012-08-29 16:29:21 -0700280 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530281 mmc_hostname(host->mmc), rc);
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530282 goto out;
283 }
284
285 /* Reset and init DML */
286 rc = msmsdcc_dml_init(host);
287 if (rc)
288 pr_err("%s: msmsdcc_dml_init error=%d\n",
289 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700290
291out:
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530292 if (!rc)
293 host->sps.reset_bam = false;
Krishna Konda3ca90f02012-08-29 16:29:21 -0700294 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530295}
296
297/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 * Apply soft reset
299 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700300 * This function applies soft reset to SDCC core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301 *
302 * This function should be called to recover from error
303 * conditions encountered with CMD/DATA tranfsers with card.
304 *
305 * Soft reset should only be used with SDCC controller v4.
306 *
307 * @host - Pointer to driver's host structure
308 *
309 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530310static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530313 * Reset controller state machines without resetting
314 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530316 if (is_sw_reset_save_config(host)) {
317 ktime_t start;
Krishna Kondabb97f922012-10-23 20:41:04 -0700318 uint32_t dll_config = 0;
319
320
321 if (is_sw_reset_save_config_broken(host))
322 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530323
324 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
325 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
326 msmsdcc_sync_reg_wr(host);
327
328 start = ktime_get();
329 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
330 /*
331 * SW reset can take upto 10HCLK + 15MCLK cycles.
332 * Calculating based on min clk rates (hclk = 27MHz,
333 * mclk = 400KHz) it comes to ~40us. Let's poll for
334 * max. 1ms for reset completion.
335 */
336 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
337 pr_err("%s: %s failed\n",
338 mmc_hostname(host->mmc), __func__);
339 BUG();
340 }
341 }
Krishna Kondabb97f922012-10-23 20:41:04 -0700342
343 if (is_sw_reset_save_config_broken(host)) {
344 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
345 mb();
346 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530347 } else {
348 writel_relaxed(0, host->base + MMCICOMMAND);
349 msmsdcc_sync_reg_wr(host);
350 writel_relaxed(0, host->base + MMCIDATACTRL);
351 msmsdcc_sync_reg_wr(host);
352 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530353}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530354
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530355static void msmsdcc_hard_reset(struct msmsdcc_host *host)
356{
357 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530358
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530359 /*
360 * Reset SDCC controller to power on default state.
361 * Don't issue a reset request to clock control block if
362 * SDCC controller itself can support hard reset.
363 */
364 if (is_sw_hard_reset(host)) {
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800365 u32 pwr;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530366
367 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
368 | MCI_SW_RST, host->base + MMCIPOWER);
369 msmsdcc_sync_reg_wr(host);
370
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800371 /*
372 * See comment in msmsdcc_soft_reset() on choosing 1ms
373 * poll timeout.
374 */
375 ret = readl_poll_timeout_noirq(host->base + MMCIPOWER,
376 pwr, !(pwr & MCI_SW_RST), 100, 10);
377
378 if (ret) {
379 pr_err("%s: %s failed (%d)\n",
380 mmc_hostname(host->mmc), __func__, ret);
381 BUG();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530382 }
383 } else {
384 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
385 if (ret)
386 pr_err("%s: Clock assert failed at %u Hz" \
387 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530388 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530389
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530390 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
391 if (ret)
392 pr_err("%s: Clock deassert failed at %u Hz" \
393 " with err %d\n", mmc_hostname(host->mmc),
394 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530395
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530396 mb();
397 /* Give some delay for clock reset to propogate to controller */
398 msmsdcc_delay(host);
399 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530400}
401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
403{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530404 if (is_soft_reset(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530405 msmsdcc_soft_reset(host);
406
407 pr_debug("%s: Applied soft reset to Controller\n",
408 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 } else {
410 /* Give Clock reset (hard reset) to controller */
411 u32 mci_clk = 0;
412 u32 mci_mask0 = 0;
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530413 u32 dll_config = 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);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530419 if (host->tuning_needed)
420 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530423 msmsdcc_hard_reset(host);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530424 pr_debug("%s: Applied hard reset to controller\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 mmc_hostname(host->mmc));
426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 /* Restore the contoller state */
428 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530429 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530431 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530433 if (host->tuning_needed)
434 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530435 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530437
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530438 if (is_sps_mode(host))
439 /*
440 * delay the SPS BAM reset in thread context as
441 * sps_connect/sps_disconnect APIs can be called
442 * only from non-atomic context.
443 */
444 host->sps.reset_bam = true;
445
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700446 if (host->dummy_52_needed)
447 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448}
449
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530450static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
451{
452 struct mmc_request *mrq = host->curr.mrq;
453
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530454 if (!mrq || !mrq->cmd || !mrq->data)
455 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530456
457 /*
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530458 * If we have not waited for the prog done for write transfer then
459 * perform the DPSM reset without polling for TXACTIVE.
460 * Otherwise, we poll here unnecessarily as TXACTIVE will not be
461 * deasserted until DAT0 (Busy line) goes high.
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530462 */
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530463 if (mrq->data->flags & MMC_DATA_WRITE) {
464 if (!msmsdcc_is_wait_for_prog_done(host, mrq)) {
465 if (is_wait_for_tx_rx_active(host) &&
466 !is_auto_prog_done(host))
467 pr_warning("%s: %s: AUTO_PROG_DONE capability is must\n",
468 mmc_hostname(host->mmc), __func__);
469 goto no_polling;
470 }
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530471 }
472
473 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
474 if (is_wait_for_tx_rx_active(host)) {
475 ktime_t start = ktime_get();
476
477 while (readl_relaxed(host->base + MMCISTATUS) &
478 (MCI_TXACTIVE | MCI_RXACTIVE)) {
479 /*
480 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
481 * cycles (~11us) after data transfer due to clock mux
482 * switching delays. Let's poll for 1ms and panic if
483 * still active.
484 */
485 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
486 pr_err("%s: %s still active\n",
487 mmc_hostname(host->mmc),
488 readl_relaxed(host->base + MMCISTATUS)
489 & MCI_TXACTIVE ? "TX" : "RX");
490 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530491 msmsdcc_reset_and_restore(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530492 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530493 }
494 }
495 }
496
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530497no_polling:
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530498 writel_relaxed(0, host->base + MMCIDATACTRL);
499 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530500out:
501 return;
502}
503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504static int
San Mehat9d2bd732009-09-22 16:44:22 -0700505msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
506{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 int retval = 0;
508
San Mehat9d2bd732009-09-22 16:44:22 -0700509 BUG_ON(host->curr.data);
510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700512
513 if (mrq->data)
514 mrq->data->bytes_xfered = host->curr.data_xfered;
515 if (mrq->cmd->error == -ETIMEDOUT)
516 mdelay(5);
517
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530518 msmsdcc_reset_dpsm(host);
519
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530520 /* Clear current request information as current request has ended */
521 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
522
San Mehat9d2bd732009-09-22 16:44:22 -0700523 /*
524 * Need to drop the host lock here; mmc_request_done may call
525 * back into the driver...
526 */
527 spin_unlock(&host->lock);
528 mmc_request_done(host->mmc, mrq);
529 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530
531 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700532}
533
534static void
535msmsdcc_stop_data(struct msmsdcc_host *host)
536{
San Mehat9d2bd732009-09-22 16:44:22 -0700537 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530538 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530539 host->curr.wait_for_auto_prog_done = false;
540 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700541}
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700544{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 return host->core_memres->start + MMCIFIFO;
546}
547
548static inline unsigned int msmsdcc_get_min_sup_clk_rate(
549 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530550
Subhash Jadavanidd432952012-03-28 11:25:56 +0530551static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552{
553 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530554 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530555 udelay(host->reg_write_delay);
556 else if (readl_relaxed(host->base + MCI_STATUS2) &
557 MCI_MCLK_REG_WR_ACTIVE) {
558 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530559
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530560 start = ktime_get();
561 while (readl_relaxed(host->base + MCI_STATUS2) &
562 MCI_MCLK_REG_WR_ACTIVE) {
563 diff = ktime_sub(ktime_get(), start);
564 /* poll for max. 1 ms */
565 if (ktime_to_us(diff) > 1000) {
566 pr_warning("%s: previous reg. write is"
567 " still active\n",
568 mmc_hostname(host->mmc));
569 break;
570 }
571 }
572 }
San Mehat9d2bd732009-09-22 16:44:22 -0700573}
574
Subhash Jadavanidd432952012-03-28 11:25:56 +0530575static inline void msmsdcc_delay(struct msmsdcc_host *host)
576{
577 udelay(host->reg_write_delay);
578
San Mehat9d2bd732009-09-22 16:44:22 -0700579}
580
San Mehat56a8b5b2009-11-21 12:29:46 -0800581static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
583{
584 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530586 /*
587 * As after sending the command, we don't write any of the
588 * controller registers and just wait for the
589 * CMD_RESPOND_END/CMD_SENT/Command failure notication
590 * from Controller.
591 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800593}
594
595static void
596msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
597{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
601 writel_relaxed((unsigned int)host->curr.xfer_size,
602 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530604 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800605
San Mehat6ac9ea62009-12-02 17:24:58 -0800606 if (host->cmd_cmd) {
607 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800609 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800610}
611
San Mehat9d2bd732009-09-22 16:44:22 -0700612static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530613msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700614{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530615 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700616 unsigned long flags;
617 struct mmc_request *mrq;
618
619 spin_lock_irqsave(&host->lock, flags);
620 mrq = host->curr.mrq;
621 BUG_ON(!mrq);
622
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530623 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700624 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700625 goto out;
626 }
627
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530628 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700629 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700631 } else {
632 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530633 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700634 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530635 mmc_hostname(host->mmc), host->dma.result);
636 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700637 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530638 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530639 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 host->dma.err.flush[0], host->dma.err.flush[1],
641 host->dma.err.flush[2], host->dma.err.flush[3],
642 host->dma.err.flush[4],
643 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530644 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700645 if (!mrq->data->error)
646 mrq->data->error = -EIO;
647 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530648 if (!mrq->data->host_cookie)
649 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
650 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 if (host->curr.user_pages) {
653 struct scatterlist *sg = host->dma.sg;
654 int i;
655
656 for (i = 0; i < host->dma.num_ents; i++, sg++)
657 flush_dcache_page(sg_page(sg));
658 }
San Mehat9d2bd732009-09-22 16:44:22 -0700659
San Mehat9d2bd732009-09-22 16:44:22 -0700660 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800661 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700662
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530663 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
664 (host->curr.wait_for_auto_prog_done &&
665 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700666 /*
667 * If we've already gotten our DATAEND / DATABLKEND
668 * for this request, then complete it through here.
669 */
San Mehat9d2bd732009-09-22 16:44:22 -0700670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700672 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673 host->curr.xfer_remain -= host->curr.xfer_size;
674 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700675 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700676 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700677 host->dummy_52_sent = 1;
678 msmsdcc_start_command(host, &dummy52cmd,
679 MCI_CPSM_PROGENA);
680 goto out;
681 }
682 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530683 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530684 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700685 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530686 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530688 /*
689 * Clear current request information as current
690 * request has ended
691 */
692 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700693 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694
San Mehat9d2bd732009-09-22 16:44:22 -0700695 mmc_request_done(host->mmc, mrq);
696 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530697 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
698 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700699 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530700 }
San Mehat9d2bd732009-09-22 16:44:22 -0700701 }
702
703out:
704 spin_unlock_irqrestore(&host->lock, flags);
705 return;
706}
707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
709/**
710 * Callback notification from SPS driver
711 *
712 * This callback function gets triggered called from
713 * SPS driver when requested SPS data transfer is
714 * completed.
715 *
716 * SPS driver invokes this callback in BAM irq context so
717 * SDCC driver schedule a tasklet for further processing
718 * this callback notification at later point of time in
719 * tasklet context and immediately returns control back
720 * to SPS driver.
721 *
722 * @nofity - Pointer to sps event notify sturcture
723 *
724 */
725static void
726msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
727{
728 struct msmsdcc_host *host =
729 (struct msmsdcc_host *)
730 ((struct sps_event_notify *)notify)->user;
731
732 host->sps.notify = *notify;
733 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
734 mmc_hostname(host->mmc), __func__, notify->event_id,
735 notify->data.transfer.iovec.addr,
736 notify->data.transfer.iovec.size,
737 notify->data.transfer.iovec.flags);
738 /* Schedule a tasklet for completing data transfer */
739 tasklet_schedule(&host->sps.tlet);
740}
741
742/**
743 * Tasklet handler for processing SPS callback event
744 *
745 * This function processing SPS event notification and
746 * checks if the SPS transfer is completed or not and
747 * then accordingly notifies status to MMC core layer.
748 *
749 * This function is called in tasklet context.
750 *
751 * @data - Pointer to sdcc driver data
752 *
753 */
754static void msmsdcc_sps_complete_tlet(unsigned long data)
755{
756 unsigned long flags;
757 int i, rc;
758 u32 data_xfered = 0;
759 struct mmc_request *mrq;
760 struct sps_iovec iovec;
761 struct sps_pipe *sps_pipe_handle;
762 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
763 struct sps_event_notify *notify = &host->sps.notify;
764
765 spin_lock_irqsave(&host->lock, flags);
766 if (host->sps.dir == DMA_FROM_DEVICE)
767 sps_pipe_handle = host->sps.prod.pipe_handle;
768 else
769 sps_pipe_handle = host->sps.cons.pipe_handle;
770 mrq = host->curr.mrq;
771
772 if (!mrq) {
773 spin_unlock_irqrestore(&host->lock, flags);
774 return;
775 }
776
777 pr_debug("%s: %s: sps event_id=%d\n",
778 mmc_hostname(host->mmc), __func__,
779 notify->event_id);
780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 /*
782 * Got End of transfer event!!! Check if all of the data
783 * has been transferred?
784 */
785 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
786 rc = sps_get_iovec(sps_pipe_handle, &iovec);
787 if (rc) {
788 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
789 mmc_hostname(host->mmc), __func__, rc, i);
790 break;
791 }
792 data_xfered += iovec.size;
793 }
794
795 if (data_xfered == host->curr.xfer_size) {
796 host->curr.data_xfered = host->curr.xfer_size;
797 host->curr.xfer_remain -= host->curr.xfer_size;
798 pr_debug("%s: Data xfer success. data_xfered=0x%x",
799 mmc_hostname(host->mmc),
800 host->curr.xfer_size);
801 } else {
802 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
803 " xfer_size=%d", mmc_hostname(host->mmc),
804 data_xfered, host->curr.xfer_size);
805 msmsdcc_reset_and_restore(host);
806 if (!mrq->data->error)
807 mrq->data->error = -EIO;
808 }
809
810 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530811 if (!mrq->data->host_cookie)
812 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
813 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 host->sps.sg = NULL;
815 host->sps.busy = 0;
816
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530817 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
818 (host->curr.wait_for_auto_prog_done &&
819 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820 /*
821 * If we've already gotten our DATAEND / DATABLKEND
822 * for this request, then complete it through here.
823 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824
825 if (!mrq->data->error) {
826 host->curr.data_xfered = host->curr.xfer_size;
827 host->curr.xfer_remain -= host->curr.xfer_size;
828 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700829 if (host->dummy_52_needed) {
830 mrq->data->bytes_xfered = host->curr.data_xfered;
831 host->dummy_52_sent = 1;
832 msmsdcc_start_command(host, &dummy52cmd,
833 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700834 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700835 return;
836 }
837 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530838 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530839 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700840 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530841 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530843 /*
844 * Clear current request information as current
845 * request has ended
846 */
847 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 spin_unlock_irqrestore(&host->lock, flags);
849
850 mmc_request_done(host->mmc, mrq);
851 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530852 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
853 || !mrq->sbc)) {
854 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 }
856 }
857 spin_unlock_irqrestore(&host->lock, flags);
858}
859
860/**
861 * Exit from current SPS data transfer
862 *
863 * This function exits from current SPS data transfer.
864 *
865 * This function should be called when error condition
866 * is encountered during data transfer.
867 *
868 * @host - Pointer to sdcc host structure
869 *
870 */
871static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
872{
873 struct mmc_request *mrq;
874
875 mrq = host->curr.mrq;
876 BUG_ON(!mrq);
877
878 msmsdcc_reset_and_restore(host);
879 if (!mrq->data->error)
880 mrq->data->error = -EIO;
881
882 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530883 if (!mrq->data->host_cookie)
884 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
885 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886
887 host->sps.sg = NULL;
888 host->sps.busy = 0;
889 if (host->curr.data)
890 msmsdcc_stop_data(host);
891
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530892 if (!mrq->data->stop || mrq->cmd->error ||
893 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530895 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
896 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 msmsdcc_start_command(host, mrq->data->stop, 0);
898
899}
900#else
901static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
902static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
903static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
904#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
905
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530906static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530908static void
909msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
910 unsigned int result,
911 struct msm_dmov_errdata *err)
912{
913 struct msmsdcc_dma_data *dma_data =
914 container_of(cmd, struct msmsdcc_dma_data, hdr);
915 struct msmsdcc_host *host = dma_data->host;
916
917 dma_data->result = result;
918 if (err)
919 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
920
921 tasklet_schedule(&host->dma_tlet);
922}
923
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530924static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
925 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700926{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530927 bool ret = true;
928 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700929
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530930 if (host->enforce_pio_mode) {
931 ret = false;
932 goto out;
933 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530934 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530935 /*
936 * BAM Mode: Fall back on PIO if size is less
937 * than or equal to SPS_MIN_XFER_SIZE bytes.
938 */
939 if (xfer_size <= SPS_MIN_XFER_SIZE)
940 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530941 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530942 /*
943 * ADM Mode: Fall back on PIO if size is less than FIFO size
944 * or not integer multiple of FIFO size
945 */
946 if (xfer_size % MCI_FIFOSIZE)
947 ret = false;
948 } else {
949 /* PIO Mode */
950 ret = false;
951 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530952 out:
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530953 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700954}
955
956static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
957{
958 struct msmsdcc_nc_dmadata *nc;
959 dmov_box *box;
960 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700961 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530962 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700963 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530964 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700965
Krishna Konda25786ec2011-07-25 16:21:36 -0700966 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700968
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530969 BUG_ON((host->pdev->id < 1) || (host->pdev->id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700970
971 host->dma.sg = data->sg;
972 host->dma.num_ents = data->sg_len;
973
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530974 /* Prevent memory corruption */
975 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800976
San Mehat9d2bd732009-09-22 16:44:22 -0700977 nc = host->dma.nc;
978
San Mehat9d2bd732009-09-22 16:44:22 -0700979 if (data->flags & MMC_DATA_READ)
980 host->dma.dir = DMA_FROM_DEVICE;
981 else
982 host->dma.dir = DMA_TO_DEVICE;
983
Asutosh Dasaccacd42012-03-08 14:33:17 +0530984 if (!data->host_cookie) {
985 n = msmsdcc_prep_xfer(host, data);
986 if (unlikely(n < 0)) {
987 host->dma.sg = NULL;
988 host->dma.num_ents = 0;
989 return -ENOMEM;
990 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800991 }
San Mehat9d2bd732009-09-22 16:44:22 -0700992
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530993 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
994 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700995 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530996 for (i = 0; i < host->dma.num_ents; i++) {
997 len = sg_dma_len(sg);
998 offset = 0;
999
1000 do {
1001 /* Check if we can do DMA */
1002 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
1003 err = -ENOTSUPP;
1004 goto unmap;
1005 }
1006
1007 box->cmd = CMD_MODE_BOX;
1008
1009 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
1010 len = MMC_MAX_DMA_BOX_LENGTH;
1011 len -= len % data->blksz;
1012 }
1013 rows = (len % MCI_FIFOSIZE) ?
1014 (len / MCI_FIFOSIZE) + 1 :
1015 (len / MCI_FIFOSIZE);
1016
1017 if (data->flags & MMC_DATA_READ) {
1018 box->src_row_addr = msmsdcc_fifo_addr(host);
1019 box->dst_row_addr = sg_dma_address(sg) + offset;
1020 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1021 (MCI_FIFOSIZE);
1022 box->row_offset = MCI_FIFOSIZE;
1023 box->num_rows = rows * ((1 << 16) + 1);
1024 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
1025 } else {
1026 box->src_row_addr = sg_dma_address(sg) + offset;
1027 box->dst_row_addr = msmsdcc_fifo_addr(host);
1028 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1029 (MCI_FIFOSIZE);
1030 box->row_offset = (MCI_FIFOSIZE << 16);
1031 box->num_rows = rows * ((1 << 16) + 1);
1032 box->cmd |= CMD_DST_CRCI(host->dma.crci);
1033 }
1034
1035 offset += len;
1036 len = sg_dma_len(sg) - offset;
1037 box++;
1038 box_cmd_cnt++;
1039 } while (len);
1040 sg++;
1041 }
1042 /* Mark last command */
1043 box--;
1044 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001045
1046 /* location of command block must be 64 bit aligned */
1047 BUG_ON(host->dma.cmd_busaddr & 0x07);
1048
1049 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1050 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1051 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1052 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1053
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301054 /* Flush all data to memory before starting dma */
1055 mb();
1056
1057unmap:
1058 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301059 if (!data->host_cookie)
1060 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1061 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301062 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1063 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001064 }
1065
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301066 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001067}
1068
Asutosh Dasaccacd42012-03-08 14:33:17 +05301069static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1070 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001071{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301072 int rc = 0;
1073 unsigned int dir;
1074
1075 /* Prevent memory corruption */
1076 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1077
1078 if (data->flags & MMC_DATA_READ)
1079 dir = DMA_FROM_DEVICE;
1080 else
1081 dir = DMA_TO_DEVICE;
1082
1083 /* Make sg buffers DMA ready */
1084 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1085 dir);
1086
1087 if (unlikely(rc != data->sg_len)) {
1088 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1089 mmc_hostname(host->mmc), rc);
1090 rc = -ENOMEM;
1091 goto dma_map_err;
1092 }
1093
1094 pr_debug("%s: %s: %s: sg_len=%d\n",
1095 mmc_hostname(host->mmc), __func__,
1096 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1097 data->sg_len);
1098
1099 goto out;
1100
1101dma_map_err:
1102 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1103 data->flags);
1104out:
1105 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001106}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1108/**
1109 * Submits data transfer request to SPS driver
1110 *
1111 * This function make sg (scatter gather) data buffers
1112 * DMA ready and then submits them to SPS driver for
1113 * transfer.
1114 *
1115 * @host - Pointer to sdcc host structure
1116 * @data - Pointer to mmc_data structure
1117 *
1118 * @return 0 if success else negative value
1119 */
1120static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301121 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001122{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123 int rc = 0;
1124 u32 flags;
1125 int i;
1126 u32 addr, len, data_cnt;
1127 struct scatterlist *sg = data->sg;
1128 struct sps_pipe *sps_pipe_handle;
1129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 host->sps.sg = data->sg;
1131 host->sps.num_ents = data->sg_len;
1132 host->sps.xfer_req_cnt = 0;
1133 if (data->flags & MMC_DATA_READ) {
1134 host->sps.dir = DMA_FROM_DEVICE;
1135 sps_pipe_handle = host->sps.prod.pipe_handle;
1136 } else {
1137 host->sps.dir = DMA_TO_DEVICE;
1138 sps_pipe_handle = host->sps.cons.pipe_handle;
1139 }
1140
Asutosh Dasaccacd42012-03-08 14:33:17 +05301141 if (!data->host_cookie) {
1142 rc = msmsdcc_prep_xfer(host, data);
1143 if (unlikely(rc < 0)) {
1144 host->dma.sg = NULL;
1145 host->dma.num_ents = 0;
1146 goto out;
1147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 }
1149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 for (i = 0; i < data->sg_len; i++) {
1151 /*
1152 * Check if this is the last buffer to transfer?
1153 * If yes then set the INT and EOT flags.
1154 */
1155 len = sg_dma_len(sg);
1156 addr = sg_dma_address(sg);
1157 flags = 0;
1158 while (len > 0) {
1159 if (len > SPS_MAX_DESC_SIZE) {
1160 data_cnt = SPS_MAX_DESC_SIZE;
1161 } else {
1162 data_cnt = len;
1163 if (i == data->sg_len - 1)
1164 flags = SPS_IOVEC_FLAG_INT |
1165 SPS_IOVEC_FLAG_EOT;
1166 }
1167 rc = sps_transfer_one(sps_pipe_handle, addr,
1168 data_cnt, host, flags);
1169 if (rc) {
1170 pr_err("%s: sps_transfer_one() error! rc=%d,"
1171 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1172 mmc_hostname(host->mmc), rc,
1173 (u32)sps_pipe_handle, (u32)sg, i);
1174 goto dma_map_err;
1175 }
1176 addr += data_cnt;
1177 len -= data_cnt;
1178 host->sps.xfer_req_cnt++;
1179 }
1180 sg++;
1181 }
1182 goto out;
1183
1184dma_map_err:
1185 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301186 if (!data->host_cookie)
1187 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1188 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189out:
1190 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001191}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192#else
1193static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1194 struct mmc_data *data) { return 0; }
1195#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001196
1197static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001198msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1199 struct mmc_command *cmd, u32 *c)
1200{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301201 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 cmd->opcode, cmd->arg, cmd->flags);
1203
San Mehat56a8b5b2009-11-21 12:29:46 -08001204 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1205
1206 if (cmd->flags & MMC_RSP_PRESENT) {
1207 if (cmd->flags & MMC_RSP_136)
1208 *c |= MCI_CPSM_LONGRSP;
1209 *c |= MCI_CPSM_RESPONSE;
1210 }
1211
1212 if (/*interrupt*/0)
1213 *c |= MCI_CPSM_INTERRUPT;
1214
Asutosh Das05049132012-05-09 12:38:15 +05301215 /* DAT_CMD bit should be set for all ADTC */
1216 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001217 *c |= MCI_CSPM_DATCMD;
1218
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301219 /* Check if AUTO CMD19/CMD21 is required or not? */
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301220 if (host->tuning_needed && (cmd->mrq->data &&
1221 (cmd->mrq->data->flags & MMC_DATA_READ)) &&
1222 (host->en_auto_cmd19 || host->en_auto_cmd21)) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301223 /*
1224 * For open ended block read operation (without CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301225 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1226 * the READ command.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301227 * For close ended block read operation (with CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301228 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1229 * CMD23.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301230 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301231 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1232 host->curr.mrq->cmd->opcode ==
1233 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301234 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301235 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301236 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1237 cmd->opcode == SD_IO_RW_EXTENDED))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301238 msmsdcc_enable_cdr_cm_sdc4_dll(host);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05301239 if (host->en_auto_cmd19 &&
1240 host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
1241 *c |= MCI_CSPM_AUTO_CMD19;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301242 else if (host->en_auto_cmd21 &&
1243 host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
1244 *c |= MCI_CSPM_AUTO_CMD21;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301245 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 }
1247
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301248 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1249 writel_relaxed((readl_relaxed(host->base +
1250 MCI_DLL_CONFIG) | MCI_CDR_EN),
1251 host->base + MCI_DLL_CONFIG);
1252 else
1253 /* Clear CDR_EN bit for non read operations */
1254 writel_relaxed((readl_relaxed(host->base +
1255 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1256 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301257
Subhash Jadavani56fd4512012-12-19 19:05:02 +05301258 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301259 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301261 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001262 if (cmd == cmd->mrq->stop)
1263 *c |= MCI_CSPM_MCIABORT;
1264
San Mehat56a8b5b2009-11-21 12:29:46 -08001265 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301266 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001268 }
1269 host->curr.cmd = cmd;
1270}
1271
1272static void
1273msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1274 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001275{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301276 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001277 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001279 unsigned int pio_irqmask = 0;
1280
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301281 BUG_ON(!data->sg);
1282 BUG_ON(!data->sg_len);
1283
San Mehat9d2bd732009-09-22 16:44:22 -07001284 host->curr.data = data;
1285 host->curr.xfer_size = data->blksz * data->blocks;
1286 host->curr.xfer_remain = host->curr.xfer_size;
1287 host->curr.data_xfered = 0;
1288 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301289 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001290
San Mehat9d2bd732009-09-22 16:44:22 -07001291 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1292
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301293 if (host->curr.wait_for_auto_prog_done)
1294 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001295
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301296 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301297 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301299 } else if (is_sps_mode(host)) {
Krishna Konda7a05d532012-08-19 11:16:39 -07001300 if (!msmsdcc_sps_start_xfer(host, data)) {
1301 /* Now kick start DML transfer */
1302 mb();
1303 msmsdcc_dml_start_xfer(host, data);
1304 datactrl |= MCI_DPSM_DMAENABLE;
1305 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 }
1307 }
1308 }
1309
1310 /* Is data transfer in PIO mode required? */
1311 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001312 if (data->flags & MMC_DATA_READ) {
1313 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1314 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1315 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1316 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1318 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001319
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001320 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001321 }
1322
1323 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301324 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301325 else if (host->curr.use_wr_data_pend)
1326 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001327
Subhash Jadavanicfa14072013-01-30 16:47:07 +05301328 if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
1329 clks = (unsigned long long)data->timeout_ns *
1330 (host->clk_rate / 2);
1331 else
1332 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
1333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001335 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301336 WARN(!timeout,
1337 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1338 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001339
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301340 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 /* Use ADM (Application Data Mover) HW for Data transfer */
1342 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001343 host->cmd_timeout = timeout;
1344 host->cmd_pio_irqmask = pio_irqmask;
1345 host->cmd_datactrl = datactrl;
1346 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1349 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001350 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001351
1352 if (cmd) {
1353 msmsdcc_start_command_deferred(host, cmd, &c);
1354 host->cmd_c = c;
1355 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1357 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1358 host->base + MMCIMASK0);
1359 mb();
1360 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001361 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1368 (~(MCI_IRQ_PIO))) | pio_irqmask,
1369 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001371
1372 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301373 /* Delay between data/command */
1374 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001375 /* Daisy-chain the command if requested */
1376 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301377 } else {
1378 /*
1379 * We don't need delay after writing to DATA_CTRL
1380 * register if we are not writing to CMD register
1381 * immediately after this. As we already have delay
1382 * before sending the command, we just need mb() here.
1383 */
1384 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001385 }
San Mehat9d2bd732009-09-22 16:44:22 -07001386 }
1387}
1388
1389static void
1390msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1391{
San Mehat56a8b5b2009-11-21 12:29:46 -08001392 msmsdcc_start_command_deferred(host, cmd, &c);
1393 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001394}
1395
1396static void
1397msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1398 unsigned int status)
1399{
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301400 if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
1401 u32 opcode = data->mrq->cmd->opcode;
1402
1403 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1404 || (opcode == MMC_BUS_TEST_R) ||
1405 (host->tuning_in_progress &&
1406 (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
1407 opcode == MMC_SEND_TUNING_BLOCK)))) {
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301408 /* Execute full tuning in case of CRC/timeout errors */
1409 host->saved_tuning_phase = INVALID_TUNING_PHASE;
1410
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301411 if (status & MCI_DATACRCFAIL) {
1412 pr_err("%s: Data CRC error\n",
1413 mmc_hostname(host->mmc));
1414 pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
1415 pr_err("%s: blksz %d, blocks %d\n", __func__,
1416 data->blksz, data->blocks);
1417 } else {
1418 pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
1419 mmc_hostname(host->mmc), opcode,
1420 (readl_relaxed(host->base
1421 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
1422 msmsdcc_dump_sdcc_state(host);
1423 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 }
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301425
1426 /*
1427 * CRC is optional for the bus test commands, not all
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 * cards respond back with CRC. However controller
1429 * waits for the CRC and times out. Hence ignore the
1430 * data timeouts during the Bustest.
1431 */
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301432 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1433 || (opcode == MMC_BUS_TEST_R))) {
1434 if (status & MCI_DATACRCFAIL)
1435 data->error = -EILSEQ;
1436 else
1437 data->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 }
Subhash Jadavani355df542012-10-09 19:06:49 +05301439 /* In case of DATA CRC/timeout error, execute tuning again */
1440 if (host->tuning_needed && !host->tuning_in_progress)
1441 host->tuning_done = false;
1442
San Mehat9d2bd732009-09-22 16:44:22 -07001443 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001444 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001445 data->error = -EIO;
1446 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001447 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001448 data->error = -EIO;
1449 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001450 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001452 data->error = -EIO;
1453 }
San Mehat9d2bd732009-09-22 16:44:22 -07001454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001456 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 host->dummy_52_needed = 0;
1458}
San Mehat9d2bd732009-09-22 16:44:22 -07001459
1460static int
1461msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1462{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001464 uint32_t *ptr = (uint32_t *) buffer;
1465 int count = 0;
1466
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301467 if (remain % 4)
1468 remain = ((remain >> 2) + 1) << 2;
1469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1471
1472 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001473 ptr++;
1474 count += sizeof(uint32_t);
1475
1476 remain -= sizeof(uint32_t);
1477 if (remain == 0)
1478 break;
1479 }
1480 return count;
1481}
1482
1483static int
1484msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001486{
1487 void __iomem *base = host->base;
1488 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 while (readl_relaxed(base + MMCISTATUS) &
1492 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1493 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001494
San Mehat9d2bd732009-09-22 16:44:22 -07001495 count = min(remain, maxcnt);
1496
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301497 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1498 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001499 ptr += count;
1500 remain -= count;
1501
1502 if (remain == 0)
1503 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 }
1505 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001506
1507 return ptr - buffer;
1508}
1509
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001510/*
1511 * Copy up to a word (4 bytes) between a scatterlist
1512 * and a temporary bounce buffer when the word lies across
1513 * two pages. The temporary buffer can then be read to/
1514 * written from the FIFO once.
1515 */
1516static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001517{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001518 struct msmsdcc_pio_data *pio = &host->pio;
1519 unsigned int bytes_avail;
1520
1521 if (host->curr.data->flags & MMC_DATA_READ)
1522 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1523 pio->bounce_buf_len);
1524 else
1525 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1526 pio->bounce_buf_len);
1527
1528 while (pio->bounce_buf_len != 4) {
1529 if (!sg_miter_next(&pio->sg_miter))
1530 break;
1531 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1532 4 - pio->bounce_buf_len);
1533 if (host->curr.data->flags & MMC_DATA_READ)
1534 memcpy(pio->sg_miter.addr,
1535 &pio->bounce_buf[pio->bounce_buf_len],
1536 bytes_avail);
1537 else
1538 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1539 pio->sg_miter.addr, bytes_avail);
1540
1541 pio->sg_miter.consumed = bytes_avail;
1542 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001543 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001544}
1545
1546/*
1547 * Use sg_miter_next to return as many 4-byte aligned
1548 * chunks as possible, using a temporary 4 byte buffer
1549 * for alignment if necessary
1550 */
1551static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1552{
1553 struct msmsdcc_pio_data *pio = &host->pio;
1554 unsigned int length, rlength;
1555 char *buffer;
1556
1557 if (!sg_miter_next(&pio->sg_miter))
1558 return 0;
1559
1560 buffer = pio->sg_miter.addr;
1561 length = pio->sg_miter.length;
1562
1563 if (length < host->curr.xfer_remain) {
1564 rlength = round_down(length, 4);
1565 if (rlength) {
1566 /*
1567 * We have a 4-byte aligned chunk.
1568 * The rounding will be reflected by
1569 * a call to msmsdcc_sg_consumed
1570 */
1571 length = rlength;
1572 goto sg_next_end;
1573 }
1574 /*
1575 * We have a length less than 4 bytes. Check to
1576 * see if more buffer is available, and combine
1577 * to make 4 bytes if possible.
1578 */
1579 pio->bounce_buf_len = length;
1580 memset(pio->bounce_buf, 0, 4);
1581
1582 /*
1583 * On a read, get 4 bytes from FIFO, and distribute
1584 * (4-bouce_buf_len) bytes into consecutive
1585 * sgl buffers when msmsdcc_sg_consumed is called
1586 */
1587 if (host->curr.data->flags & MMC_DATA_READ) {
1588 buffer = pio->bounce_buf;
1589 length = 4;
1590 goto sg_next_end;
1591 } else {
1592 _msmsdcc_sg_consume_word(host);
1593 buffer = pio->bounce_buf;
1594 length = pio->bounce_buf_len;
1595 }
1596 }
1597
1598sg_next_end:
1599 *buf = buffer;
1600 *len = length;
1601 return 1;
1602}
1603
1604/*
1605 * Update sg_miter.consumed based on how many bytes were
1606 * consumed. If the bounce buffer was used to read from FIFO,
1607 * redistribute into sgls.
1608 */
1609static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1610 unsigned int length)
1611{
1612 struct msmsdcc_pio_data *pio = &host->pio;
1613
1614 if (host->curr.data->flags & MMC_DATA_READ) {
1615 if (length > pio->sg_miter.consumed)
1616 /*
1617 * consumed 4 bytes, but sgl
1618 * describes < 4 bytes
1619 */
1620 _msmsdcc_sg_consume_word(host);
1621 else
1622 pio->sg_miter.consumed = length;
1623 } else
1624 if (length < pio->sg_miter.consumed)
1625 pio->sg_miter.consumed = length;
1626}
1627
1628static void msmsdcc_sg_start(struct msmsdcc_host *host)
1629{
1630 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1631
1632 host->pio.bounce_buf_len = 0;
1633
1634 if (host->curr.data->flags & MMC_DATA_READ)
1635 sg_miter_flags |= SG_MITER_TO_SG;
1636 else
1637 sg_miter_flags |= SG_MITER_FROM_SG;
1638
1639 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1640 host->curr.data->sg_len, sg_miter_flags);
1641}
1642
1643static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1644{
1645 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001646}
1647
San Mehat1cd22962010-02-03 12:59:29 -08001648static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001649msmsdcc_pio_irq(int irq, void *dev_id)
1650{
1651 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001653 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001654 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001655 unsigned int remain;
1656 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001657
Murali Palnati36448a42011-09-02 15:06:18 +05301658 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301659
Oluwafemi Adeyemi0bcb1332012-12-07 16:21:22 -08001660 if (!atomic_read(&host->clks_on)) {
1661 spin_unlock(&host->lock);
1662 return IRQ_NONE;
1663 }
1664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301668 (MCI_IRQ_PIO)) == 0) {
1669 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301670 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301671 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672#if IRQ_DEBUG
1673 msmsdcc_print_status(host, "irq1-r", status);
1674#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001675 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001676
1677 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001678 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1681 | MCI_RXDATAAVLBL)))
1682 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001683
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001684 if (!msmsdcc_sg_next(host, &buffer, &remain))
1685 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001686
San Mehat9d2bd732009-09-22 16:44:22 -07001687 len = 0;
1688 if (status & MCI_RXACTIVE)
1689 len = msmsdcc_pio_read(host, buffer, remain);
1690 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001692
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301693 /* len might have aligned to 32bits above */
1694 if (len > remain)
1695 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001696
San Mehat9d2bd732009-09-22 16:44:22 -07001697 host->curr.xfer_remain -= len;
1698 host->curr.data_xfered += len;
1699 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001700 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 if (remain) /* Done with this page? */
1703 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001706 } while (1);
1707
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001708 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001709 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1712 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1713 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1714 host->base + MMCIMASK0);
1715 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301716 /*
1717 * back to back write to MASK0 register don't need
1718 * synchronization delay.
1719 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1721 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1722 }
1723 mb();
1724 } else if (!host->curr.xfer_remain) {
1725 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1726 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1727 mb();
1728 }
San Mehat9d2bd732009-09-22 16:44:22 -07001729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001731
1732 return IRQ_HANDLED;
1733}
1734
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735static void
1736msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1737
1738static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1739 struct mmc_data *data)
1740{
1741 u32 loop_cnt = 0;
1742
1743 /*
1744 * For read commands with data less than fifo size, it is possible to
1745 * get DATAEND first and RXDATA_AVAIL might be set later because of
1746 * synchronization delay through the asynchronous RX FIFO. Thus, for
1747 * such cases, even after DATAEND interrupt is received software
1748 * should poll for RXDATA_AVAIL until the requested data is read out
1749 * of FIFO. This change is needed to get around this abnormal but
1750 * sometimes expected behavior of SDCC3 controller.
1751 *
1752 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1753 * after the data is loaded into RX FIFO. This would amount to less
1754 * than a microsecond and thus looping for 1000 times is good enough
1755 * for that delay.
1756 */
1757 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1758 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1759 spin_unlock(&host->lock);
1760 msmsdcc_pio_irq(1, host);
1761 spin_lock(&host->lock);
1762 }
1763 }
1764 if (loop_cnt == 1000) {
1765 pr_info("%s: Timed out while polling for Rx Data\n",
1766 mmc_hostname(host->mmc));
1767 data->error = -ETIMEDOUT;
1768 msmsdcc_reset_and_restore(host);
1769 }
1770}
1771
San Mehat9d2bd732009-09-22 16:44:22 -07001772static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1773{
1774 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001775
1776 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301777 if (mmc_resp_type(cmd))
1778 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1779 /*
1780 * Read rest of the response registers only if
1781 * long response is expected for this command
1782 */
1783 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1784 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1785 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1786 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1787 }
San Mehat9d2bd732009-09-22 16:44:22 -07001788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301790 pr_debug("%s: CMD%d: Command timeout\n",
1791 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001792 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301794 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301795 pr_err("%s: CMD%d: Command CRC error\n",
1796 mmc_hostname(host->mmc), cmd->opcode);
1797 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301798 /* Execute full tuning in case of CRC errors */
1799 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Subhash Jadavani355df542012-10-09 19:06:49 +05301800 if (host->tuning_needed)
1801 host->tuning_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001802 cmd->error = -EILSEQ;
1803 }
1804
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301805 if (!cmd->error) {
1806 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1807 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1808 mod_timer(&host->req_tout_timer, (jiffies +
1809 msecs_to_jiffies(host->curr.req_tout_ms)));
1810 }
1811 }
1812
San Mehat9d2bd732009-09-22 16:44:22 -07001813 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301815 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001816 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301818 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 /* Stop current SPS transfer */
1820 msmsdcc_sps_exit_curr_xfer(host);
1821 }
San Mehat9d2bd732009-09-22 16:44:22 -07001822 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301823 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001824 msmsdcc_stop_data(host);
1825 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301826 } else { /* host->data == NULL */
1827 if (!cmd->error && host->prog_enable) {
1828 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301830 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301832 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301833 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301834 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301835 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001836 if (host->dummy_52_needed)
1837 host->dummy_52_needed = 0;
1838 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301840 msmsdcc_request_end(host, cmd->mrq);
1841 }
1842 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301843 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301844 if (cmd == host->curr.mrq->sbc)
1845 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1846 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1847 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301848 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001849 }
1850}
1851
San Mehat9d2bd732009-09-22 16:44:22 -07001852static irqreturn_t
1853msmsdcc_irq(int irq, void *dev_id)
1854{
1855 struct msmsdcc_host *host = dev_id;
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301856 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001857 u32 status;
1858 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001860
1861 spin_lock(&host->lock);
1862
1863 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 struct mmc_command *cmd;
1865 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 if (timer) {
1868 timer = 0;
1869 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001870 }
San Mehat9d2bd732009-09-22 16:44:22 -07001871
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301872 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 pr_debug("%s: %s: SDIO async irq received\n",
1874 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301875
1876 /*
1877 * Only async interrupt can come when clocks are off,
1878 * disable further interrupts and enable them when
1879 * clocks are on.
1880 */
1881 if (!host->sdcc_irq_disabled) {
1882 disable_irq_nosync(irq);
1883 host->sdcc_irq_disabled = 1;
1884 }
1885
1886 /*
1887 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1888 * will take care of signaling sdio irq during
1889 * mmc_sdio_resume().
1890 */
Krishna Konda1963f432013-02-19 20:28:53 -08001891 if (host->sdcc_suspended &&
1892 (host->plat->mpm_sdiowakeup_int ||
1893 host->plat->sdiowakeup_irq)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301894 /*
1895 * This is a wakeup interrupt so hold wakelock
1896 * until SDCC resume is handled.
1897 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301899 } else {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301900 if (!mmc->card || (mmc->card &&
1901 !mmc_card_sdio(mmc->card))) {
1902 pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1903 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301904 ret = 1;
1905 break;
1906 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301907 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301908 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301909 spin_lock(&host->lock);
1910 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301911 ret = 1;
1912 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913 }
1914
1915 status = readl_relaxed(host->base + MMCISTATUS);
1916
1917 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1918 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001919 break;
1920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921#if IRQ_DEBUG
1922 msmsdcc_print_status(host, "irq0-r", status);
1923#endif
1924 status &= readl_relaxed(host->base + MMCIMASK0);
1925 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301926 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301927 if (host->clk_rate <=
1928 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301929 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930#if IRQ_DEBUG
1931 msmsdcc_print_status(host, "irq0-p", status);
1932#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934 if (status & MCI_SDIOINTROPE) {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301935 if (!mmc->card || (mmc->card &&
1936 !mmc_card_sdio(mmc->card))) {
1937 pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
1938 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301939 ret = 1;
1940 break;
1941 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 if (host->sdcc_suspending)
1943 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301944 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301946 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001947 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001948 data = host->curr.data;
1949
1950 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1952 MCI_CMDTIMEOUT)) {
1953 if (status & MCI_CMDTIMEOUT)
1954 pr_debug("%s: dummy CMD52 timeout\n",
1955 mmc_hostname(host->mmc));
1956 if (status & MCI_CMDCRCFAIL)
1957 pr_debug("%s: dummy CMD52 CRC failed\n",
1958 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001959 host->dummy_52_sent = 0;
1960 host->dummy_52_needed = 0;
1961 if (data) {
1962 msmsdcc_stop_data(host);
1963 msmsdcc_request_end(host, data->mrq);
1964 }
1965 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 spin_unlock(&host->lock);
1967 return IRQ_HANDLED;
1968 }
1969 break;
1970 }
1971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 /*
1973 * Check for proper command response
1974 */
1975 cmd = host->curr.cmd;
1976 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1977 MCI_CMDTIMEOUT | MCI_PROGDONE |
1978 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1979 msmsdcc_do_cmdirq(host, status);
1980 }
1981
Subhash Jadavani2d7980f2013-01-09 16:18:08 +05301982 if (data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 /* Check for data errors */
1984 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1985 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1986 msmsdcc_data_err(host, data, status);
1987 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301988 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001989 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301990 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 /* Stop current SPS transfer */
1992 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301993 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 msmsdcc_reset_and_restore(host);
1995 if (host->curr.data)
1996 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301997 if (!data->stop || (host->curr.mrq->sbc
1998 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 timer |=
2000 msmsdcc_request_end(host,
2001 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302002 else if ((host->curr.mrq->sbc
2003 && data->error) ||
2004 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 msmsdcc_start_command(host,
2006 data->stop,
2007 0);
2008 timer = 1;
2009 }
2010 }
2011 }
2012
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302013 /* Check for prog done */
2014 if (host->curr.wait_for_auto_prog_done &&
2015 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302016 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 /* Check for data done */
2019 if (!host->curr.got_dataend && (status & MCI_DATAEND))
2020 host->curr.got_dataend = 1;
2021
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302022 if (host->curr.got_dataend &&
2023 (!host->curr.wait_for_auto_prog_done ||
2024 (host->curr.wait_for_auto_prog_done &&
2025 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 /*
2027 * If DMA is still in progress, we complete
2028 * via the completion handler
2029 */
2030 if (!host->dma.busy && !host->sps.busy) {
2031 /*
2032 * There appears to be an issue in the
2033 * controller where if you request a
2034 * small block transfer (< fifo size),
2035 * you may get your DATAEND/DATABLKEND
2036 * irq without the PIO data irq.
2037 *
2038 * Check to see if theres still data
2039 * to be read, and simulate a PIO irq.
2040 */
2041 if (data->flags & MMC_DATA_READ)
2042 msmsdcc_wait_for_rxdata(host,
2043 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 if (!data->error) {
2045 host->curr.data_xfered =
2046 host->curr.xfer_size;
2047 host->curr.xfer_remain -=
2048 host->curr.xfer_size;
2049 }
2050
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002051 if (!host->dummy_52_needed) {
2052 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302053 if (!data->stop ||
2054 (host->curr.mrq->sbc
2055 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002056 msmsdcc_request_end(
2057 host,
2058 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302059 else if ((host->curr.mrq->sbc
2060 && data->error) ||
2061 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002062 msmsdcc_start_command(
2063 host,
2064 data->stop, 0);
2065 timer = 1;
2066 }
2067 } else {
2068 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002070 &dummy52cmd,
2071 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 }
2073 }
2074 }
2075 }
2076
San Mehat9d2bd732009-09-22 16:44:22 -07002077 ret = 1;
2078 } while (status);
2079
2080 spin_unlock(&host->lock);
2081
San Mehat9d2bd732009-09-22 16:44:22 -07002082 return IRQ_RETVAL(ret);
2083}
2084
2085static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302086msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2087 bool is_first_request)
2088{
2089 struct msmsdcc_host *host = mmc_priv(mmc);
2090 struct mmc_data *data = mrq->data;
2091 int rc = 0;
2092
2093 if (unlikely(!data)) {
2094 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2095 __func__);
2096 return;
2097 }
2098 if (unlikely(data->host_cookie)) {
2099 /* Very wrong */
2100 data->host_cookie = 0;
2101 pr_err("%s: %s Request reposted for prepare\n",
2102 mmc_hostname(mmc), __func__);
2103 return;
2104 }
2105
2106 if (!msmsdcc_is_dma_possible(host, data))
2107 return;
2108
2109 rc = msmsdcc_prep_xfer(host, data);
2110 if (unlikely(rc < 0)) {
2111 data->host_cookie = 0;
2112 return;
2113 }
2114
2115 data->host_cookie = 1;
2116}
2117
2118static void
2119msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2120{
2121 struct msmsdcc_host *host = mmc_priv(mmc);
2122 unsigned int dir;
2123 struct mmc_data *data = mrq->data;
2124
2125 if (unlikely(!data)) {
2126 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2127 __func__);
2128 return;
2129 }
2130 if (data->flags & MMC_DATA_READ)
2131 dir = DMA_FROM_DEVICE;
2132 else
2133 dir = DMA_TO_DEVICE;
2134
2135 if (data->host_cookie)
2136 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2137 data->sg_len, dir);
2138
2139 data->host_cookie = 0;
2140}
2141
2142static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2144{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302145 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302147 if ((mrq->data->flags & MMC_DATA_READ) ||
2148 host->curr.use_wr_data_pend)
2149 msmsdcc_start_data(host, mrq->data,
2150 mrq->sbc ? mrq->sbc : mrq->cmd,
2151 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302152 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302153 msmsdcc_start_command(host,
2154 mrq->sbc ? mrq->sbc : mrq->cmd,
2155 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 } else {
2157 msmsdcc_start_command(host, mrq->cmd, 0);
2158 }
2159}
2160
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302161/*
2162 * This function returns true if AUTO_PROG_DONE feature of host is
2163 * applicable for current request, returns "false" otherwise.
2164 *
2165 * NOTE: Caller should call this function only for data write operations.
2166 */
2167static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2168 struct mmc_request *mrq)
2169{
2170 /*
2171 * Auto-prog done will be enabled for following cases:
2172 * mrq->sbc | mrq->stop
2173 * _____________|________________
2174 * True | Don't care
2175 * False | False (CMD24, ACMD25 use case)
2176 */
2177 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2178 return true;
2179
2180 return false;
2181}
2182
2183/*
2184 * This function returns true if controller can wait for prog done
2185 * for current request, returns "false" otherwise.
2186 *
2187 * NOTE: Caller should call this function only for data write operations.
2188 */
2189static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2190 struct mmc_request *mrq)
2191{
2192 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2193 return true;
2194
2195 return false;
2196}
2197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198static void
San Mehat9d2bd732009-09-22 16:44:22 -07002199msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2200{
2201 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302202 unsigned long flags;
Krishna Konda3d47c822013-02-21 18:28:11 -08002203 unsigned int error = 0;
Krishna Konda3ca90f02012-08-29 16:29:21 -07002204 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 /*
2207 * Get the SDIO AL client out of LPM.
2208 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002209 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 if (host->plat->is_sdio_al_client)
2211 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002212
Krishna Konda3d47c822013-02-21 18:28:11 -08002213 /*
2214 * Don't start the request if SDCC is not in proper state to handle it
2215 * BAM state is checked below if applicable
2216 */
2217 if (!host->pwr || !atomic_read(&host->clks_on) ||
2218 host->sdcc_irq_disabled) {
2219 WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
2220 mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
2221 error = EIO;
2222 goto bad_state;
2223 }
2224
Krishna Konda3ca90f02012-08-29 16:29:21 -07002225 /* check if sps bam needs to be reset */
2226 if (is_sps_mode(host) && host->sps.reset_bam) {
2227 while (retries) {
2228 if (!msmsdcc_bam_dml_reset_and_restore(host))
2229 break;
2230 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2231 mmc_hostname(host->mmc), --retries);
2232 }
Krishna Konda3d47c822013-02-21 18:28:11 -08002233
2234 /* check if BAM reset succeeded or not */
2235 if (host->sps.reset_bam) {
2236 pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
2237 mmc_hostname(host->mmc), mrq->cmd->opcode);
2238 error = EAGAIN;
2239 goto bad_state;
2240 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302241 }
San Mehat9d2bd732009-09-22 16:44:22 -07002242
Subhash Jadavani355df542012-10-09 19:06:49 +05302243 /*
2244 * Check if DLL retuning is required? If yes, perform it here before
2245 * starting new request.
2246 */
2247 if (host->tuning_needed && !host->tuning_in_progress &&
2248 !host->tuning_done) {
2249 pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
2250 mmc_hostname(mmc), __func__, host->mmc->ios.timing);
2251 if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
2252 msmsdcc_execute_tuning(mmc,
2253 MMC_SEND_TUNING_BLOCK);
2254 else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
2255 msmsdcc_execute_tuning(mmc,
2256 MMC_SEND_TUNING_BLOCK_HS200);
2257 }
2258
San Mehat9d2bd732009-09-22 16:44:22 -07002259 if (host->eject) {
Krishna Konda3d47c822013-02-21 18:28:11 -08002260 error = ENOMEDIUM;
2261 goto card_ejected;
subhashjf181c292012-05-02 13:07:40 +05302262 }
2263
2264 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2265 " other request (CMD%d) is in progress\n",
2266 mmc_hostname(host->mmc), __func__,
2267 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2268
Krishna Konda3d47c822013-02-21 18:28:11 -08002269 spin_lock_irqsave(&host->lock, flags);
2270
subhashjf181c292012-05-02 13:07:40 +05302271 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302272 * Set timeout value to 10 secs (or more in case of buggy cards)
2273 */
2274 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302275 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302276 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302277 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302278 /*
2279 * Kick the software request timeout timer here with the timeout
2280 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302281 */
2282 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302283 (jiffies +
2284 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002285
San Mehat9d2bd732009-09-22 16:44:22 -07002286 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302287 if (mrq->sbc) {
2288 mrq->sbc->mrq = mrq;
2289 mrq->sbc->data = mrq->data;
2290 }
2291
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302292 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302293 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2294 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302295 } else {
2296 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2297 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 host->dummy_52_needed = 1;
2299 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302300
Subhash Jadavanif5277752011-10-12 16:47:52 +05302301 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
Subhash Jadavanicf58e6f2012-10-05 20:45:54 +05302302 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
2303 ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
2304 is_data_pend_for_cmd53(host)))
Subhash Jadavanif5277752011-10-12 16:47:52 +05302305 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002306 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302307
Subhash Jadavanif5277752011-10-12 16:47:52 +05302308 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002309 spin_unlock_irqrestore(&host->lock, flags);
Krishna Konda3d47c822013-02-21 18:28:11 -08002310 return;
2311
2312bad_state:
2313 msmsdcc_dump_sdcc_state(host);
2314card_ejected:
2315 mrq->cmd->error = -error;
2316 if (mrq->data) {
2317 mrq->data->error = -error;
2318 mrq->data->bytes_xfered = 0;
2319 }
2320 mmc_request_done(mmc, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002321}
2322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2324 int min_uV, int max_uV)
2325{
2326 int rc = 0;
2327
2328 if (vreg->set_voltage_sup) {
2329 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2330 if (rc) {
2331 pr_err("%s: regulator_set_voltage(%s) failed."
2332 " min_uV=%d, max_uV=%d, rc=%d\n",
2333 __func__, vreg->name, min_uV, max_uV, rc);
2334 }
2335 }
2336
2337 return rc;
2338}
2339
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302340static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2341{
2342 int rc = 0;
2343
2344 rc = regulator_get_voltage(vreg->reg);
2345 if (rc < 0)
2346 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2347 __func__, vreg->name, rc);
2348
2349 return rc;
2350}
2351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2353 int uA_load)
2354{
2355 int rc = 0;
2356
Krishna Kondafea60182011-11-01 16:01:34 -07002357 /* regulators that do not support regulator_set_voltage also
2358 do not support regulator_set_optimum_mode */
2359 if (vreg->set_voltage_sup) {
2360 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2361 if (rc < 0)
2362 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2363 "uA_load=%d) failed. rc=%d\n", __func__,
2364 vreg->name, uA_load, rc);
2365 else
2366 /* regulator_set_optimum_mode() can return non zero
2367 * value even for success case.
2368 */
2369 rc = 0;
2370 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371
2372 return rc;
2373}
2374
2375static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2376 struct device *dev)
2377{
2378 int rc = 0;
2379
2380 /* check if regulator is already initialized? */
2381 if (vreg->reg)
2382 goto out;
2383
2384 /* Get the regulator handle */
2385 vreg->reg = regulator_get(dev, vreg->name);
2386 if (IS_ERR(vreg->reg)) {
2387 rc = PTR_ERR(vreg->reg);
2388 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2389 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002390 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002392
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302393 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002394 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302395 /* sanity check */
2396 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2397 pr_err("%s: %s invalid constraints specified\n",
2398 __func__, vreg->name);
2399 rc = -EINVAL;
2400 }
2401 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403out:
2404 return rc;
2405}
2406
2407static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2408{
2409 if (vreg->reg)
2410 regulator_put(vreg->reg);
2411}
2412
2413/* This init function should be called only once for each SDCC slot */
2414static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2415{
2416 int rc = 0;
2417 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302418 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 struct device *dev = mmc_dev(host->mmc);
2420
2421 curr_slot = host->plat->vreg_data;
2422 if (!curr_slot)
2423 goto out;
2424
2425 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302426 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427
2428 if (is_init) {
2429 /*
2430 * Get the regulator handle from voltage regulator framework
2431 * and then try to set the voltage level for the regulator
2432 */
2433 if (curr_vdd_reg) {
2434 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2435 if (rc)
2436 goto out;
2437 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302438 if (curr_vdd_io_reg) {
2439 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440 if (rc)
2441 goto vdd_reg_deinit;
2442 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002443 rc = msmsdcc_vreg_reset(host);
2444 if (rc)
2445 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302446 host->pdev->id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 goto out;
2448 } else {
2449 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302450 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302452vdd_io_reg_deinit:
2453 if (curr_vdd_io_reg)
2454 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455vdd_reg_deinit:
2456 if (curr_vdd_reg)
2457 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2458out:
2459 return rc;
2460}
2461
2462static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2463{
2464 int rc = 0;
2465
Subhash Jadavanicc922692011-08-01 23:05:01 +05302466 /* Put regulator in HPM (high power mode) */
2467 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2468 if (rc < 0)
2469 goto out;
2470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 if (!vreg->is_enabled) {
2472 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302473 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2474 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 if (rc)
2476 goto out;
2477
2478 rc = regulator_enable(vreg->reg);
2479 if (rc) {
2480 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2481 __func__, vreg->name, rc);
2482 goto out;
2483 }
2484 vreg->is_enabled = true;
2485 }
2486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487out:
2488 return rc;
2489}
2490
Krishna Konda3c4142d2012-06-27 11:01:56 -07002491static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492{
2493 int rc = 0;
2494
2495 /* Never disable regulator marked as always_on */
2496 if (vreg->is_enabled && !vreg->always_on) {
2497 rc = regulator_disable(vreg->reg);
2498 if (rc) {
2499 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2500 __func__, vreg->name, rc);
2501 goto out;
2502 }
2503 vreg->is_enabled = false;
2504
2505 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2506 if (rc < 0)
2507 goto out;
2508
2509 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302510 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511 if (rc)
2512 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002513 } else if (vreg->is_enabled && vreg->always_on) {
2514 if (!is_init && vreg->lpm_sup) {
2515 /* Put always_on regulator in LPM (low power mode) */
2516 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2517 if (rc < 0)
2518 goto out;
2519 } else if (is_init && vreg->reset_at_init) {
2520 /**
2521 * The regulator might not actually be disabled if it
2522 * is shared and in use by other drivers.
2523 */
2524 rc = regulator_disable(vreg->reg);
2525 if (rc) {
2526 pr_err("%s: regulator_disable(%s) failed at " \
2527 "bootup. rc=%d\n", __func__,
2528 vreg->name, rc);
2529 goto out;
2530 }
2531 vreg->is_enabled = false;
2532 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002533 }
2534out:
2535 return rc;
2536}
2537
Krishna Konda3c4142d2012-06-27 11:01:56 -07002538static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2539 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540{
2541 int rc = 0, i;
2542 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302543 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544
2545 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302546 if (!curr_slot) {
Asutosh Dasd5902bf2012-10-03 18:28:20 +05302547 pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
2548 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302550 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551
Subhash Jadavani937c7502012-06-01 15:34:46 +05302552 vreg_table[0] = curr_slot->vdd_data;
2553 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554
2555 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2556 if (vreg_table[i]) {
2557 if (enable)
2558 rc = msmsdcc_vreg_enable(vreg_table[i]);
2559 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002560 rc = msmsdcc_vreg_disable(vreg_table[i],
2561 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562 if (rc)
2563 goto out;
2564 }
2565 }
2566out:
2567 return rc;
2568}
2569
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002570/*
2571 * Reset vreg by ensuring it is off during probe. A call
2572 * to enable vreg is needed to balance disable vreg
2573 */
2574static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2575{
2576 int rc;
2577
Krishna Konda3c4142d2012-06-27 11:01:56 -07002578 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002579 if (rc)
2580 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002581 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002582 return rc;
2583}
2584
Subhash Jadavani937c7502012-06-01 15:34:46 +05302585enum vdd_io_level {
2586 /* set vdd_io_data->low_vol_level */
2587 VDD_IO_LOW,
2588 /* set vdd_io_data->high_vol_level */
2589 VDD_IO_HIGH,
2590 /*
2591 * set whatever there in voltage_level (third argument) of
2592 * msmsdcc_set_vdd_io_vol() function.
2593 */
2594 VDD_IO_SET_LEVEL,
2595};
2596
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302597/*
2598 * This function returns the current VDD IO voltage level.
2599 * Returns negative value if it fails to read the voltage level
2600 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2601 * regulator were not defined for host.
2602 */
2603static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2604{
2605 int rc = 0;
2606
2607 if (host->plat->vreg_data) {
2608 struct msm_mmc_reg_data *io_reg =
2609 host->plat->vreg_data->vdd_io_data;
2610
2611 /*
2612 * If vdd_io is not defined, then we can consider that
2613 * IO voltage is same as VDD.
2614 */
2615 if (!io_reg)
2616 io_reg = host->plat->vreg_data->vdd_data;
2617
2618 if (io_reg && io_reg->is_enabled)
2619 rc = msmsdcc_vreg_get_voltage(io_reg);
2620 }
2621
2622 return rc;
2623}
2624
2625/*
2626 * This function updates the IO pad power switch bit in MCI_CLK register
2627 * based on currrent IO pad voltage level.
2628 * NOTE: This function assumes that host lock was not taken by caller.
2629 */
2630static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2631{
2632 int rc = 0;
2633 unsigned long flags;
2634
2635 if (!is_io_pad_pwr_switch(host))
2636 return;
2637
2638 rc = msmsdcc_get_vdd_io_vol(host);
2639
2640 spin_lock_irqsave(&host->lock, flags);
2641 /*
2642 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2643 * the SDCC instances support the dual voltage pads.
2644 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2645 * bit before using the pads in 1.8V mode.
2646 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2647 * IO_PAD_PWR_SWITCH bit is a don't care.
2648 * But we don't have an option to know (by reading some SDCC register)
2649 * that a particular SDCC instance supports dual voltage pads or not,
2650 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2651 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2652 * is anyway ignored.
2653 */
2654 if (rc > 0 && rc < 2700000)
2655 host->io_pad_pwr_switch = 1;
2656 else
2657 host->io_pad_pwr_switch = 0;
2658
2659 if (atomic_read(&host->clks_on)) {
2660 if (host->io_pad_pwr_switch)
2661 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2662 IO_PAD_PWR_SWITCH),
2663 host->base + MMCICLOCK);
2664 else
2665 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2666 ~IO_PAD_PWR_SWITCH),
2667 host->base + MMCICLOCK);
2668 msmsdcc_sync_reg_wr(host);
2669 }
2670 spin_unlock_irqrestore(&host->lock, flags);
2671}
2672
Subhash Jadavani937c7502012-06-01 15:34:46 +05302673static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2674 enum vdd_io_level level,
2675 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676{
2677 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302678 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002679
2680 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302681 struct msm_mmc_reg_data *vdd_io_reg =
2682 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683
Subhash Jadavani937c7502012-06-01 15:34:46 +05302684 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2685 switch (level) {
2686 case VDD_IO_LOW:
2687 set_level = vdd_io_reg->low_vol_level;
2688 break;
2689 case VDD_IO_HIGH:
2690 set_level = vdd_io_reg->high_vol_level;
2691 break;
2692 case VDD_IO_SET_LEVEL:
2693 set_level = voltage_level;
2694 break;
2695 default:
2696 pr_err("%s: %s: invalid argument level = %d",
2697 mmc_hostname(host->mmc), __func__,
2698 level);
2699 rc = -EINVAL;
2700 goto out;
2701 }
2702 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2703 set_level, set_level);
2704 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 }
2706
Subhash Jadavani937c7502012-06-01 15:34:46 +05302707out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302708 return rc;
2709}
2710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2712{
2713 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2714 return 1;
2715 return 0;
2716}
2717
Asutosh Dasf5298c32012-04-03 14:51:47 +05302718/*
2719 * Any function calling msmsdcc_setup_clocks must
2720 * acquire clk_mutex. May sleep.
2721 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302722static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302724 int rc = 0;
2725
2726 if (enable && !atomic_read(&host->clks_on)) {
2727 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2728 rc = clk_prepare_enable(host->bus_clk);
2729 if (rc) {
2730 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2731 mmc_hostname(host->mmc), __func__, rc);
2732 goto out;
2733 }
2734 }
2735 if (!IS_ERR(host->pclk)) {
2736 rc = clk_prepare_enable(host->pclk);
2737 if (rc) {
2738 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2739 mmc_hostname(host->mmc), __func__, rc);
2740 goto disable_bus;
2741 }
2742 }
2743 rc = clk_prepare_enable(host->clk);
2744 if (rc) {
2745 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2746 mmc_hostname(host->mmc), __func__, rc);
2747 goto disable_pclk;
2748 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302749 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302750 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302751 atomic_set(&host->clks_on, 1);
2752 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302753 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302754 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302755 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302757 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302758 if (!IS_ERR_OR_NULL(host->bus_clk))
2759 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302760 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302762 goto out;
2763
2764disable_pclk:
2765 if (!IS_ERR_OR_NULL(host->pclk))
2766 clk_disable_unprepare(host->pclk);
2767disable_bus:
2768 if (!IS_ERR_OR_NULL(host->bus_clk))
2769 clk_disable_unprepare(host->bus_clk);
2770out:
2771 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772}
2773
2774static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2775 unsigned int req_clk)
2776{
2777 unsigned int sel_clk = -1;
2778
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302779 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2780 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2781 goto out;
2782 }
2783
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2785 unsigned char cnt;
2786
2787 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2788 if (host->plat->sup_clk_table[cnt] > req_clk)
2789 break;
2790 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2791 sel_clk = host->plat->sup_clk_table[cnt];
2792 break;
2793 } else
2794 sel_clk = host->plat->sup_clk_table[cnt];
2795 }
2796 } else {
2797 if ((req_clk < host->plat->msmsdcc_fmax) &&
2798 (req_clk > host->plat->msmsdcc_fmid))
2799 sel_clk = host->plat->msmsdcc_fmid;
2800 else
2801 sel_clk = req_clk;
2802 }
2803
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302804out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 return sel_clk;
2806}
2807
2808static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2809 struct msmsdcc_host *host)
2810{
2811 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2812 return host->plat->sup_clk_table[0];
2813 else
2814 return host->plat->msmsdcc_fmin;
2815}
2816
2817static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2818 struct msmsdcc_host *host)
2819{
2820 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2821 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2822 else
2823 return host->plat->msmsdcc_fmax;
2824}
2825
2826static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302827{
2828 struct msm_mmc_gpio_data *curr;
2829 int i, rc = 0;
2830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302832 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302833 if (!gpio_is_valid(curr->gpio[i].no)) {
2834 rc = -EINVAL;
2835 pr_err("%s: Invalid gpio = %d\n",
2836 mmc_hostname(host->mmc), curr->gpio[i].no);
2837 goto free_gpios;
2838 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302839 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 if (curr->gpio[i].is_always_on &&
2841 curr->gpio[i].is_enabled)
2842 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302843 rc = gpio_request(curr->gpio[i].no,
2844 curr->gpio[i].name);
2845 if (rc) {
2846 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2847 mmc_hostname(host->mmc),
2848 curr->gpio[i].no,
2849 curr->gpio[i].name, rc);
2850 goto free_gpios;
2851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302853 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 if (curr->gpio[i].is_always_on)
2855 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302856 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002857 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302858 }
2859 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302861
2862free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302863 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302864 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865 curr->gpio[i].is_enabled = false;
2866 }
2867out:
2868 return rc;
2869}
2870
2871static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2872{
2873 struct msm_mmc_pad_data *curr;
2874 int i;
2875
2876 curr = host->plat->pin_data->pad_data;
2877 for (i = 0; i < curr->drv->size; i++) {
2878 if (enable)
2879 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2880 curr->drv->on[i].val);
2881 else
2882 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2883 curr->drv->off[i].val);
2884 }
2885
2886 for (i = 0; i < curr->pull->size; i++) {
2887 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002888 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 curr->pull->on[i].val);
2890 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002891 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 curr->pull->off[i].val);
2893 }
2894
2895 return 0;
2896}
2897
2898static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2899{
2900 int rc = 0;
2901
2902 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2903 return 0;
2904
2905 if (host->plat->pin_data->is_gpio)
2906 rc = msmsdcc_setup_gpio(host, enable);
2907 else
2908 rc = msmsdcc_setup_pad(host, enable);
2909
2910 if (!rc)
2911 host->plat->pin_data->cfg_sts = enable;
2912
2913 return rc;
2914}
2915
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302916static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2917 unsigned mode)
2918{
2919 int ret = 0;
2920 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2921
2922 if (!pin)
2923 return 0;
2924
2925 switch (mode) {
2926 case SDC_DAT1_DISABLE:
2927 ret = msm_mpm_enable_pin(pin, 0);
2928 break;
2929 case SDC_DAT1_ENABLE:
2930 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2931 ret = msm_mpm_enable_pin(pin, 1);
2932 break;
2933 case SDC_DAT1_ENWAKE:
2934 ret = msm_mpm_set_pin_wake(pin, 1);
2935 break;
2936 case SDC_DAT1_DISWAKE:
2937 ret = msm_mpm_set_pin_wake(pin, 0);
2938 break;
2939 default:
2940 ret = -EINVAL;
2941 break;
2942 }
2943
2944 return ret;
2945}
2946
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302947static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2948{
2949 u32 pwr = 0;
2950 int ret = 0;
2951 struct mmc_host *mmc = host->mmc;
2952
2953 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2954 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2955 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002956 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302957
2958 if (ret) {
2959 pr_err("%s: Failed to setup voltage regulators\n",
2960 mmc_hostname(host->mmc));
2961 goto out;
2962 }
2963
2964 switch (ios->power_mode) {
2965 case MMC_POWER_OFF:
2966 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302967 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302968 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302969 * If VDD IO rail is always on, set low voltage for VDD
2970 * IO rail when slot is not in use (like when card is not
2971 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302972 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302973 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302974 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302975 msmsdcc_setup_pins(host, false);
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05302976 /*
2977 * Reset the mask to prevent hitting any pending interrupts
2978 * after powering up the card again.
2979 */
2980 if (atomic_read(&host->clks_on)) {
2981 writel_relaxed(0, host->base + MMCIMASK0);
2982 mb();
2983 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302984 break;
2985 case MMC_POWER_UP:
2986 /* writing PWR_UP bit is redundant */
2987 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302988 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302989
Subhash Jadavani937c7502012-06-01 15:34:46 +05302990 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302991 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302992 msmsdcc_setup_pins(host, true);
2993 break;
2994 case MMC_POWER_ON:
2995 pwr = MCI_PWR_ON;
2996 break;
2997 }
2998
2999out:
3000 return pwr;
3001}
3002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
3004{
3005 unsigned int wakeup_irq;
3006
3007 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3008 host->plat->sdiowakeup_irq :
3009 host->core_irqres->start;
3010
3011 if (!host->irq_wake_enabled) {
3012 enable_irq_wake(wakeup_irq);
3013 host->irq_wake_enabled = true;
3014 }
3015}
3016
3017static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
3018{
3019 unsigned int wakeup_irq;
3020
3021 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3022 host->plat->sdiowakeup_irq :
3023 host->core_irqres->start;
3024
3025 if (host->irq_wake_enabled) {
3026 disable_irq_wake(wakeup_irq);
3027 host->irq_wake_enabled = false;
3028 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05303029}
3030
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303031/* Returns required bandwidth in Bytes per Sec */
3032static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
3033 struct mmc_ios *ios)
3034{
3035 unsigned int bw;
3036
3037 bw = host->clk_rate;
3038 /*
3039 * For DDR mode, SDCC controller clock will be at
3040 * the double rate than the actual clock that goes to card.
3041 */
3042 if (ios->bus_width == MMC_BUS_WIDTH_4)
3043 bw /= 2;
3044 else if (ios->bus_width == MMC_BUS_WIDTH_1)
3045 bw /= 8;
3046
3047 return bw;
3048}
3049
3050static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
3051 unsigned int bw)
3052{
3053 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
3054 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
3055 int i;
3056
3057 if (host->msm_bus_vote.is_max_bw_needed && bw)
3058 return host->msm_bus_vote.max_bw_vote;
3059
3060 for (i = 0; i < size; i++) {
3061 if (bw <= table[i])
3062 break;
3063 }
3064
3065 if (i && (i == size))
3066 i--;
3067
3068 return i;
3069}
3070
3071static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
3072{
3073 int rc = 0;
3074 struct msm_bus_scale_pdata *use_cases;
3075
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303076 if (host->pdev->dev.of_node) {
3077 struct msm_mmc_bus_voting_data *data;
3078 struct device *dev = &host->pdev->dev;
3079
3080 data = devm_kzalloc(dev,
3081 sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
3082 if (!data) {
3083 dev_err(&host->pdev->dev,
3084 "%s: failed to allocate memory\n", __func__);
3085 rc = -ENOMEM;
3086 goto out;
3087 }
3088
3089 rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
3090 &data->bw_vecs, &data->bw_vecs_size, 0);
3091 if (!rc) {
3092 data->use_cases = msm_bus_cl_get_pdata(host->pdev);
3093 host->plat->msm_bus_voting_data = data;
3094 }
3095 }
3096
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303097 if (host->plat->msm_bus_voting_data &&
3098 host->plat->msm_bus_voting_data->use_cases &&
3099 host->plat->msm_bus_voting_data->bw_vecs &&
3100 host->plat->msm_bus_voting_data->bw_vecs_size) {
3101 use_cases = host->plat->msm_bus_voting_data->use_cases;
3102 host->msm_bus_vote.client_handle =
3103 msm_bus_scale_register_client(use_cases);
3104 } else {
3105 return 0;
3106 }
3107
3108 if (!host->msm_bus_vote.client_handle) {
3109 pr_err("%s: msm_bus_scale_register_client() failed\n",
3110 mmc_hostname(host->mmc));
3111 rc = -EFAULT;
3112 } else {
3113 /* cache the vote index for minimum and maximum bandwidth */
3114 host->msm_bus_vote.min_bw_vote =
3115 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3116 host->msm_bus_vote.max_bw_vote =
3117 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3118 }
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303119out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303120 return rc;
3121}
3122
3123static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3124{
3125 if (host->msm_bus_vote.client_handle)
3126 msm_bus_scale_unregister_client(
3127 host->msm_bus_vote.client_handle);
3128}
3129
3130/*
3131 * This function must be called with host lock acquired.
3132 * Caller of this function should also ensure that msm bus client
3133 * handle is not null.
3134 */
3135static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3136 int vote,
3137 unsigned long flags)
3138{
3139 int rc = 0;
3140
3141 if (vote != host->msm_bus_vote.curr_vote) {
3142 spin_unlock_irqrestore(&host->lock, flags);
3143 rc = msm_bus_scale_client_update_request(
3144 host->msm_bus_vote.client_handle, vote);
3145 if (rc)
3146 pr_err("%s: msm_bus_scale_client_update_request() failed."
3147 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3148 mmc_hostname(host->mmc),
3149 host->msm_bus_vote.client_handle, vote, rc);
3150 spin_lock_irqsave(&host->lock, flags);
3151 if (!rc)
3152 host->msm_bus_vote.curr_vote = vote;
3153 }
3154
3155 return rc;
3156}
3157
3158/*
3159 * Internal work. Work to set 0 bandwidth for msm bus.
3160 */
3161static void msmsdcc_msm_bus_work(struct work_struct *work)
3162{
3163 struct msmsdcc_host *host = container_of(work,
3164 struct msmsdcc_host,
3165 msm_bus_vote.vote_work.work);
3166 unsigned long flags;
3167
3168 if (!host->msm_bus_vote.client_handle)
3169 return;
3170
3171 spin_lock_irqsave(&host->lock, flags);
3172 /* don't vote for 0 bandwidth if any request is in progress */
3173 if (!host->curr.mrq)
3174 msmsdcc_msm_bus_set_vote(host,
3175 host->msm_bus_vote.min_bw_vote, flags);
3176 else
3177 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3178 " bus voting to 0 bandwidth\n",
3179 mmc_hostname(host->mmc), __func__);
3180 spin_unlock_irqrestore(&host->lock, flags);
3181}
3182
3183/*
3184 * This function cancels any scheduled delayed work
3185 * and sets the bus vote based on ios argument.
3186 * If "ios" argument is NULL, bandwidth required is 0 else
3187 * calculate the bandwidth based on ios parameters.
3188 */
3189static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3190 struct msmsdcc_host *host,
3191 struct mmc_ios *ios)
3192{
3193 unsigned long flags;
3194 unsigned int bw;
3195 int vote;
3196
3197 if (!host->msm_bus_vote.client_handle)
3198 return;
3199
3200 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3201
3202 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3203 spin_lock_irqsave(&host->lock, flags);
3204 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3205 msmsdcc_msm_bus_set_vote(host, vote, flags);
3206 spin_unlock_irqrestore(&host->lock, flags);
3207}
3208
3209/* This function queues a work which will set the bandwidth requiement to 0 */
3210static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3211{
3212 unsigned long flags;
3213
3214 if (!host->msm_bus_vote.client_handle)
3215 return;
3216
3217 spin_lock_irqsave(&host->lock, flags);
3218 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3219 queue_delayed_work(system_nrt_wq,
3220 &host->msm_bus_vote.vote_work,
3221 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3222 spin_unlock_irqrestore(&host->lock, flags);
3223}
3224
San Mehat9d2bd732009-09-22 16:44:22 -07003225static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303226msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3227{
3228 struct mmc_host *mmc = host->mmc;
3229
3230 /*
3231 * SDIO_AL clients has different mechanism of handling LPM through
3232 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3233 * part of that. Here, we are interested only in clients like WLAN.
3234 */
3235 if (!(mmc->card && mmc_card_sdio(mmc->card))
3236 || host->plat->is_sdio_al_client)
3237 goto out;
3238
3239 if (!host->sdcc_suspended) {
3240 /*
3241 * When MSM is not in power collapse and we
3242 * are disabling clocks, enable bit 22 in MASK0
3243 * to handle asynchronous SDIO interrupts.
3244 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303245 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303246 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303247 mb();
3248 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303249 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303250 msmsdcc_sync_reg_wr(host);
3251 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303252 goto out;
3253 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3254 /*
3255 * Wakeup MSM only if SDIO function drivers set
3256 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3257 */
3258 goto out;
3259 }
3260
3261 if (enable_wakeup_irq) {
3262 if (!host->plat->sdiowakeup_irq) {
3263 /*
3264 * When there is no gpio line that can be configured
3265 * as wakeup interrupt handle it by configuring
3266 * asynchronous sdio interrupts and DAT1 line.
3267 */
3268 writel_relaxed(MCI_SDIOINTMASK,
3269 host->base + MMCIMASK0);
3270 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303271 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303272 /* configure sdcc core interrupt as wakeup interrupt */
3273 msmsdcc_enable_irq_wake(host);
3274 } else {
3275 /* Let gpio line handle wakeup interrupt */
3276 writel_relaxed(0, host->base + MMCIMASK0);
3277 mb();
3278 if (host->sdio_wakeupirq_disabled) {
3279 host->sdio_wakeupirq_disabled = 0;
3280 /* configure gpio line as wakeup interrupt */
3281 msmsdcc_enable_irq_wake(host);
3282 enable_irq(host->plat->sdiowakeup_irq);
3283 }
3284 }
3285 } else {
3286 if (!host->plat->sdiowakeup_irq) {
3287 /*
3288 * We may not have cleared bit 22 in the interrupt
3289 * handler as the clocks might be off at that time.
3290 */
3291 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303292 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303293 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303294 msmsdcc_disable_irq_wake(host);
3295 } else if (!host->sdio_wakeupirq_disabled) {
3296 disable_irq_nosync(host->plat->sdiowakeup_irq);
3297 msmsdcc_disable_irq_wake(host);
3298 host->sdio_wakeupirq_disabled = 1;
3299 }
3300 }
3301out:
3302 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003303}
3304
3305static void
3306msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3307{
3308 struct msmsdcc_host *host = mmc_priv(mmc);
3309 u32 clk = 0, pwr = 0;
3310 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003311 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003313
Sahitya Tummala7a892482011-01-18 11:22:49 +05303314
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303315 /*
3316 * Disable SDCC core interrupt until set_ios is completed.
3317 * This avoids any race conditions with interrupt raised
3318 * when turning on/off the clocks. One possible
3319 * scenario is SDIO operational interrupt while the clock
3320 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303321 * host->lock is being released intermittently below.
3322 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303323 */
3324
Asutosh Dasf5298c32012-04-03 14:51:47 +05303325 mutex_lock(&host->clk_mutex);
3326 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003327 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303328 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303329 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303330 host->sdcc_irq_disabled = 1;
3331 }
San Mehatd0719e52009-12-03 10:58:54 -08003332 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003333
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303334 /* Make sure sdcc core irq is synchronized */
3335 synchronize_irq(host->core_irqres->start);
3336
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303337 pwr = msmsdcc_setup_pwr(host, ios);
3338
3339 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003340 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303341 spin_unlock_irqrestore(&host->lock, flags);
3342 rc = msmsdcc_setup_clocks(host, true);
3343 if (rc)
3344 goto out;
3345 spin_lock_irqsave(&host->lock, flags);
3346 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3347 mb();
3348 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303350
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003351 /*
3352 * For DDR50 mode, controller needs clock rate to be
3353 * double than what is required on the SD card CLK pin.
Subhash Jadavani2877d912012-10-09 20:01:56 +05303354 *
3355 * Setting DDR timing mode in controller before setting the
3356 * clock rate will make sure that card don't see the double
3357 * clock rate even for very small duration. Some eMMC
3358 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303360 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2877d912012-10-09 20:01:56 +05303361 u32 clk;
3362
3363 clk = readl_relaxed(host->base + MMCICLOCK);
3364 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3365 clk |= (3 << 14); /* set DDR timing mode */
3366 writel_relaxed(clk, host->base + MMCICLOCK);
3367 msmsdcc_sync_reg_wr(host);
3368
Subhash Jadavani879856d2013-03-04 16:28:04 +05303369 clock = msmsdcc_get_sup_clk_rate(host, ios->clock * 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003370 }
3371
3372 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303373 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303375 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303377 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 mmc_hostname(mmc), clock);
3379 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303380 host->reg_write_delay =
3381 (1 + ((3 * USEC_PER_SEC) /
3382 (host->clk_rate ? host->clk_rate :
3383 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003384 }
3385 /*
3386 * give atleast 2 MCLK cycles delay for clocks
3387 * and SDCC core to stabilize
3388 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303389 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003391 clk |= MCI_CLK_ENABLE;
3392 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 if (ios->bus_width == MMC_BUS_WIDTH_8)
3394 clk |= MCI_CLK_WIDEBUS_8;
3395 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3396 clk |= MCI_CLK_WIDEBUS_4;
3397 else
3398 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 if (msmsdcc_is_pwrsave(host))
3401 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405 host->tuning_needed = 0;
3406 /*
3407 * Select the controller timing mode according
3408 * to current bus speed mode
3409 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303410 if (host->clk_rate > (100 * 1000 * 1000) &&
3411 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3412 ios->timing == MMC_TIMING_MMC_HS200)) {
3413 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414 clk |= (4 << 14);
3415 host->tuning_needed = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003416 } else {
Subhash Jadavani355df542012-10-09 19:06:49 +05303417 if (ios->timing == MMC_TIMING_UHS_DDR50)
3418 clk |= (3 << 14);
3419 else
3420 clk |= (2 << 14); /* feedback clock */
3421
3422 host->tuning_done = false;
3423 if (atomic_read(&host->clks_on)) {
3424 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3425 writel_relaxed((readl_relaxed(host->base +
3426 MCI_DLL_CONFIG) | MCI_DLL_RST),
3427 host->base + MCI_DLL_CONFIG);
3428
3429 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3430 writel_relaxed((readl_relaxed(host->base +
3431 MCI_DLL_CONFIG) | MCI_DLL_PDN),
3432 host->base + MCI_DLL_CONFIG);
3433 }
San Mehat9d2bd732009-09-22 16:44:22 -07003434 }
3435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3437 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 if (host->io_pad_pwr_switch)
3440 clk |= IO_PAD_PWR_SWITCH;
3441
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303442 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303443 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303444 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3445 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303446 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003447 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303448 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3449 host->pwr = pwr;
3450 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303451 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452 }
San Mehat9d2bd732009-09-22 16:44:22 -07003453 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003454
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303455 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303456 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303457 spin_unlock_irqrestore(&host->lock, flags);
3458 /*
3459 * May get a wake-up interrupt the instant we disable the
3460 * clocks. This would disable the wake-up interrupt.
3461 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303463 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303465
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303466 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303467 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303468 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303469
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303470 /* Let interrupts be disabled if the host is powered off */
3471 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3472 enable_irq(host->core_irqres->start);
3473 host->sdcc_irq_disabled = 0;
3474 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003475 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303476out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303477 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003478}
3479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003480int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3481{
3482 struct msmsdcc_host *host = mmc_priv(mmc);
3483 u32 clk;
3484
3485 clk = readl_relaxed(host->base + MMCICLOCK);
3486 pr_debug("Changing to pwr_save=%d", pwrsave);
3487 if (pwrsave && msmsdcc_is_pwrsave(host))
3488 clk |= MCI_CLK_PWRSAVE;
3489 else
3490 clk &= ~MCI_CLK_PWRSAVE;
3491 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303492 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493
3494 return 0;
3495}
3496
3497static int msmsdcc_get_ro(struct mmc_host *mmc)
3498{
3499 int status = -ENOSYS;
3500 struct msmsdcc_host *host = mmc_priv(mmc);
3501
3502 if (host->plat->wpswitch) {
3503 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303504 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 status = gpio_request(host->plat->wpswitch_gpio,
3506 "SD_WP_Switch");
3507 if (status) {
3508 pr_err("%s: %s: Failed to request GPIO %d\n",
3509 mmc_hostname(mmc), __func__,
3510 host->plat->wpswitch_gpio);
3511 } else {
3512 status = gpio_direction_input(
3513 host->plat->wpswitch_gpio);
3514 if (!status) {
3515 /*
3516 * Wait for atleast 300ms as debounce
3517 * time for GPIO input to stabilize.
3518 */
3519 msleep(300);
3520 status = gpio_get_value_cansleep(
3521 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303522 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003523 }
3524 gpio_free(host->plat->wpswitch_gpio);
3525 }
3526 }
3527
3528 if (status < 0)
3529 status = -ENOSYS;
3530 pr_debug("%s: Card read-only status %d\n", __func__, status);
3531
3532 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003533}
3534
3535static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3536{
3537 struct msmsdcc_host *host = mmc_priv(mmc);
3538 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303540 /*
3541 * We may come here with clocks turned off in that case don't
3542 * attempt to write into MASK0 register. While turning on the
3543 * clocks mci_irqenable will be written to MASK0 register.
3544 */
San Mehat9d2bd732009-09-22 16:44:22 -07003545
3546 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003547 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003548 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303549 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303550 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303552 mb();
3553 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 } else {
3555 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303556 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303557 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003558 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303559 mb();
3560 }
San Mehat9d2bd732009-09-22 16:44:22 -07003561 }
3562 spin_unlock_irqrestore(&host->lock, flags);
3563}
3564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303566static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003567{
subhashj245831e2012-04-30 18:46:17 +05303568 struct device *dev = mmc_dev(host->mmc);
3569
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303570 pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
Subhash Jadavani386ad802012-08-16 18:46:57 +05303571 mmc_hostname(host->mmc), host->sdcc_suspended,
3572 host->pending_resume, host->sdcc_suspending);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303573 pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
subhashj245831e2012-04-30 18:46:17 +05303574 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3575 " request_pending=%d, request=%d\n",
3576 mmc_hostname(host->mmc), dev->power.runtime_status,
3577 atomic_read(&dev->power.usage_count),
3578 dev->power.is_suspended, dev->power.disable_depth,
3579 dev->power.runtime_error, dev->power.request_pending,
3580 dev->power.request);
3581}
3582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003583static int msmsdcc_enable(struct mmc_host *mmc)
3584{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003585 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003587 struct msmsdcc_host *host = mmc_priv(mmc);
3588
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303589 msmsdcc_pm_qos_update_latency(host, 1);
3590
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003591 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303592 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593
Subhash Jadavani386ad802012-08-16 18:46:57 +05303594 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003595 host->pending_resume = false;
3596 pm_runtime_get_noresume(dev);
3597 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303598 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003599 }
3600
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303601 if (dev->power.runtime_status == RPM_SUSPENDING) {
3602 if (mmc->suspend_task == current) {
3603 pm_runtime_get_noresume(dev);
3604 goto out;
3605 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303606 } else if (dev->power.runtime_status == RPM_RESUMING) {
3607 pm_runtime_get_noresume(dev);
3608 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303609 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303611 rc = pm_runtime_get_sync(dev);
3612
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303613skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303614 if (rc < 0) {
Subhash Jadavani386ad802012-08-16 18:46:57 +05303615 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3616 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303617 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303618 return rc;
3619 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303620out:
3621 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303622 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003623}
3624
Steve Mucklef132c6c2012-06-06 18:30:57 -07003625static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003626{
3627 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303628 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303630 msmsdcc_pm_qos_update_latency(host, 0);
3631
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303632 if (mmc->card && mmc_card_sdio(mmc->card)) {
3633 rc = 0;
3634 goto out;
3635 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303636
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303637 if (host->plat->disable_runtime_pm)
3638 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639
3640 rc = pm_runtime_put_sync(mmc->parent);
3641
Subhash Jadavani386ad802012-08-16 18:46:57 +05303642 if (rc < 0) {
3643 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3644 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303645 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003646 return rc;
3647 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303648
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303649out:
3650 msmsdcc_msm_bus_queue_work(host);
3651 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652}
3653#else
subhashj245831e2012-04-30 18:46:17 +05303654static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3655
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303656static int msmsdcc_enable(struct mmc_host *mmc)
3657{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003658 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303659 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303660 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303661
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303662 msmsdcc_pm_qos_update_latency(host, 1);
3663
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303664 if (mmc->card && mmc_card_sdio(mmc->card)) {
3665 rc = 0;
3666 goto out;
3667 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003668
3669 if (host->sdcc_suspended && host->pending_resume) {
3670 host->pending_resume = false;
3671 rc = msmsdcc_runtime_resume(dev);
3672 goto out;
3673 }
3674
Asutosh Dasf5298c32012-04-03 14:51:47 +05303675 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303676 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303677 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303678
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003679out:
3680 if (rc < 0) {
3681 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3682 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303683 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003684 return rc;
3685 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303686 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303687 return 0;
3688}
3689
Steve Mucklef132c6c2012-06-06 18:30:57 -07003690static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303691{
3692 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303693 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303694
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303695 msmsdcc_pm_qos_update_latency(host, 0);
3696
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303697 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303698 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303699
Asutosh Dasf5298c32012-04-03 14:51:47 +05303700 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303701 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303702 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303703
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303704 if (rc) {
3705 msmsdcc_pm_qos_update_latency(host, 1);
3706 return rc;
3707 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303708out:
3709 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303710 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303711}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712#endif
3713
Subhash Jadavani937c7502012-06-01 15:34:46 +05303714static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3715 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716{
3717 struct msmsdcc_host *host = mmc_priv(mmc);
3718 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303719 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003720
Subhash Jadavani937c7502012-06-01 15:34:46 +05303721 switch (ios->signal_voltage) {
3722 case MMC_SIGNAL_VOLTAGE_330:
3723 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3724 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303725 if (!rc)
3726 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303727 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303728 case MMC_SIGNAL_VOLTAGE_180:
3729 break;
3730 case MMC_SIGNAL_VOLTAGE_120:
3731 /*
3732 * For eMMC cards, VDD_IO voltage range must be changed
3733 * only if it operates in HS200 SDR 1.2V mode or in
3734 * DDR 1.2V mode.
3735 */
3736 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303737 if (!rc)
3738 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003739 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303740 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003741 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303742 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 goto out;
3744 }
San Mehat9d2bd732009-09-22 16:44:22 -07003745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003746 /*
3747 * If we are here means voltage switch from high voltage to
3748 * low voltage is required
3749 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303750 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751
3752 /*
3753 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3754 * register until they become all zeros.
3755 */
3756 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303757 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003758 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3759 mmc_hostname(mmc), __func__);
3760 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003761 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762
3763 /* Stop SD CLK output. */
3764 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3765 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303766 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003767 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003768
3769 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303770 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3771 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003772 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303773 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303774 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303777 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778
3779 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3780 usleep_range(5000, 5500);
3781
3782 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303783 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003784 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3785 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303786 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787 spin_unlock_irqrestore(&host->lock, flags);
3788
3789 /*
3790 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3791 * don't become all ones within 1 ms then a Voltage Switch
3792 * sequence has failed and a power cycle to the card is required.
3793 * Otherwise Voltage Switch sequence is completed successfully.
3794 */
3795 usleep_range(1000, 1500);
3796
3797 spin_lock_irqsave(&host->lock, flags);
3798 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3799 != (0xF << 1)) {
3800 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3801 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303802 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 goto out_unlock;
3804 }
3805
3806out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303807 /* Enable PWRSAVE */
3808 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3809 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303810 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003811 spin_unlock_irqrestore(&host->lock, flags);
3812out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303813 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003814}
3815
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303816static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003817{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819
3820 /* Program the MCLK value to MCLK_FREQ bit field */
3821 if (host->clk_rate <= 112000000)
3822 mclk_freq = 0;
3823 else if (host->clk_rate <= 125000000)
3824 mclk_freq = 1;
3825 else if (host->clk_rate <= 137000000)
3826 mclk_freq = 2;
3827 else if (host->clk_rate <= 150000000)
3828 mclk_freq = 3;
3829 else if (host->clk_rate <= 162000000)
3830 mclk_freq = 4;
3831 else if (host->clk_rate <= 175000000)
3832 mclk_freq = 5;
3833 else if (host->clk_rate <= 187000000)
3834 mclk_freq = 6;
3835 else if (host->clk_rate <= 200000000)
3836 mclk_freq = 7;
3837
3838 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3839 & ~(7 << 24)) | (mclk_freq << 24)),
3840 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841}
3842
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303843/* Initialize the DLL (Programmable Delay Line ) */
3844static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003845{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303847 unsigned long flags;
3848 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303850 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003851 /*
3852 * Make sure that clock is always enabled when DLL
3853 * tuning is in progress. Keeping PWRSAVE ON may
3854 * turn off the clock. So let's disable the PWRSAVE
3855 * here and re-enable it once tuning is completed.
3856 */
3857 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3858 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303859 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303860
3861 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3862 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3863 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3864
3865 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3866 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3867 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3868
3869 msmsdcc_cm_sdc4_dll_set_freq(host);
3870
3871 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3872 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3873 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3874
3875 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3876 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3877 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3878
3879 /* Set DLL_EN bit to 1. */
3880 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3881 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3882
3883 /* Set CK_OUT_EN bit to 1. */
3884 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3885 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3886
3887 wait_cnt = 50;
3888 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3889 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3890 /* max. wait for 50us sec for LOCK bit to be set */
3891 if (--wait_cnt == 0) {
3892 pr_err("%s: %s: DLL failed to LOCK\n",
3893 mmc_hostname(host->mmc), __func__);
3894 rc = -ETIMEDOUT;
3895 goto out;
3896 }
3897 /* wait for 1us before polling again */
3898 udelay(1);
3899 }
3900
3901out:
3902 /* re-enable PWRSAVE */
3903 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3904 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303905 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303906 spin_unlock_irqrestore(&host->lock, flags);
3907
3908 return rc;
3909}
3910
3911static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3912 u8 poll)
3913{
3914 int rc = 0;
3915 u32 wait_cnt = 50;
3916 u8 ck_out_en = 0;
3917
3918 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3919 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3920 MCI_CK_OUT_EN);
3921
3922 while (ck_out_en != poll) {
3923 if (--wait_cnt == 0) {
3924 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3925 mmc_hostname(host->mmc), __func__, poll);
3926 rc = -ETIMEDOUT;
3927 goto out;
3928 }
3929 udelay(1);
3930
3931 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3932 MCI_CK_OUT_EN);
3933 }
3934out:
3935 return rc;
3936}
3937
3938/*
3939 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3940 * calibration sequence. This function should be called before
3941 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3942 * commands (CMD17/CMD18).
3943 *
3944 * This function gets called when host spinlock acquired.
3945 */
3946static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3947{
3948 int rc = 0;
3949 u32 config;
3950
3951 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3952 config |= MCI_CDR_EN;
3953 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3954 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3955
3956 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3957 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3958 if (rc)
3959 goto err_out;
3960
3961 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3962 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3963 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3964
3965 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3966 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3967 if (rc)
3968 goto err_out;
3969
3970 goto out;
3971
3972err_out:
3973 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3974out:
3975 return rc;
3976}
3977
3978static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3979 u8 phase)
3980{
3981 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303982 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3983 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3984 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303985 unsigned long flags;
3986 u32 config;
3987
3988 spin_lock_irqsave(&host->lock, flags);
3989
3990 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3991 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3992 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3993 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3994
3995 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3996 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3997 if (rc)
3998 goto err_out;
3999
4000 /*
4001 * Write the selected DLL clock output phase (0 ... 15)
4002 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
4003 */
4004 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
4005 & ~(0xF << 20))
4006 | (grey_coded_phase_table[phase] << 20)),
4007 host->base + MCI_DLL_CONFIG);
4008
4009 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4010 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4011 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4012
4013 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4014 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4015 if (rc)
4016 goto err_out;
4017
4018 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4019 config |= MCI_CDR_EN;
4020 config &= ~MCI_CDR_EXT_EN;
4021 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4022 goto out;
4023
4024err_out:
4025 pr_err("%s: %s: Failed to set DLL phase: %d\n",
4026 mmc_hostname(host->mmc), __func__, phase);
4027out:
4028 spin_unlock_irqrestore(&host->lock, flags);
4029 return rc;
4030}
4031
4032/*
4033 * Find out the greatest range of consecuitive selected
4034 * DLL clock output phases that can be used as sampling
4035 * setting for SD3.0 UHS-I card read operation (in SDR104
4036 * timing mode) or for eMMC4.5 card read operation (in HS200
4037 * timing mode).
4038 * Select the 3/4 of the range and configure the DLL with the
4039 * selected DLL clock output phase.
4040*/
Subhash Jadavani34187042012-03-02 10:59:49 +05304041static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304042 u8 *phase_table, u8 total_phases)
4043{
Subhash Jadavani6159c622012-03-15 19:05:55 +05304044 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05304045 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05304046 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
4047 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304048 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304049 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
4050 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304051
Subhash Jadavani6159c622012-03-15 19:05:55 +05304052 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304053 pr_err("%s: %s: invalid argument: total_phases=%d\n",
4054 mmc_hostname(host->mmc), __func__, total_phases);
4055 return -EINVAL;
4056 }
4057
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304058 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304059 ranges[row_index][col_index] = phase_table[cnt];
4060 phases_per_row[row_index] += 1;
4061 col_index++;
4062
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304063 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304064 continue;
4065 /* check if next phase in phase_table is consecutive or not */
4066 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
4067 row_index++;
4068 col_index = 0;
4069 }
4070 }
4071
Subhash Jadavani6159c622012-03-15 19:05:55 +05304072 if (row_index >= MAX_PHASES)
4073 return -EINVAL;
4074
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304075 /* Check if phase-0 is present in first valid window? */
4076 if (!ranges[0][0]) {
4077 phase_0_found = true;
4078 phase_0_raw_index = 0;
4079 /* Check if cycle exist between 2 valid windows */
4080 for (cnt = 1; cnt <= row_index; cnt++) {
4081 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05304082 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304083 if (ranges[cnt][i] == 15) {
4084 phase_15_found = true;
4085 phase_15_raw_index = cnt;
4086 break;
4087 }
4088 }
4089 }
4090 }
4091 }
4092
4093 /* If 2 valid windows form cycle then merge them as single window */
4094 if (phase_0_found && phase_15_found) {
4095 /* number of phases in raw where phase 0 is present */
4096 u8 phases_0 = phases_per_row[phase_0_raw_index];
4097 /* number of phases in raw where phase 15 is present */
4098 u8 phases_15 = phases_per_row[phase_15_raw_index];
4099
Subhash Jadavani6159c622012-03-15 19:05:55 +05304100 if (phases_0 + phases_15 >= MAX_PHASES)
4101 /*
4102 * If there are more than 1 phase windows then total
4103 * number of phases in both the windows should not be
4104 * more than or equal to MAX_PHASES.
4105 */
4106 return -EINVAL;
4107
4108 /* Merge 2 cyclic windows */
4109 i = phases_15;
4110 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304111 ranges[phase_15_raw_index][i] =
4112 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304113 if (++i >= MAX_PHASES)
4114 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304115 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304116
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304117 phases_per_row[phase_0_raw_index] = 0;
4118 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4119 }
4120
4121 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304122 if (phases_per_row[cnt] > curr_max) {
4123 curr_max = phases_per_row[cnt];
4124 selected_row_index = cnt;
4125 }
4126 }
4127
Subhash Jadavani6159c622012-03-15 19:05:55 +05304128 i = ((curr_max * 3) / 4);
4129 if (i)
4130 i--;
4131
Subhash Jadavani34187042012-03-02 10:59:49 +05304132 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304133
Subhash Jadavani6159c622012-03-15 19:05:55 +05304134 if (ret >= MAX_PHASES) {
4135 ret = -EINVAL;
4136 pr_err("%s: %s: invalid phase selected=%d\n",
4137 mmc_hostname(host->mmc), __func__, ret);
4138 }
4139
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304140 return ret;
4141}
4142
Girish K Sa3f41692012-02-29 12:00:09 +05304143static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304144{
4145 int rc = 0;
4146 struct msmsdcc_host *host = mmc_priv(mmc);
4147 unsigned long flags;
4148 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304149 const u32 *tuning_block_pattern = tuning_block_64;
4150 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304151 bool is_tuning_all_phases;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304152
4153 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4154
4155 /* Tuning is only required for SDR104 modes */
4156 if (!host->tuning_needed) {
4157 rc = 0;
4158 goto exit;
4159 }
4160
4161 spin_lock_irqsave(&host->lock, flags);
4162 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304163 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304164 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4165
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304166 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304167 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4168 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4169 tuning_block_pattern = tuning_block_128;
4170 size = sizeof(tuning_block_128);
4171 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304172 spin_unlock_irqrestore(&host->lock, flags);
4173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174 /* first of all reset the tuning block */
4175 rc = msmsdcc_init_cm_sdc4_dll(host);
4176 if (rc)
4177 goto out;
4178
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304179 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004180 if (!data_buf) {
4181 rc = -ENOMEM;
4182 goto out;
4183 }
4184
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304185 is_tuning_all_phases = !(host->mmc->card &&
4186 (host->saved_tuning_phase != INVALID_TUNING_PHASE));
4187retry:
4188 if (is_tuning_all_phases)
4189 phase = 0; /* start from phase 0 during init */
4190 else
4191 phase = (u8)host->saved_tuning_phase;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004192 do {
4193 struct mmc_command cmd = {0};
4194 struct mmc_data data = {0};
4195 struct mmc_request mrq = {
4196 .cmd = &cmd,
4197 .data = &data
4198 };
4199 struct scatterlist sg;
4200
4201 /* set the phase in delay line hw block */
4202 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4203 if (rc)
4204 goto kfree;
4205
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304206 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004207 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4208
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304209 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004210 data.blocks = 1;
4211 data.flags = MMC_DATA_READ;
4212 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4213
4214 data.sg = &sg;
4215 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304216 sg_init_one(&sg, data_buf, size);
4217 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004218 mmc_wait_for_req(mmc, &mrq);
4219
4220 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304221 !memcmp(data_buf, tuning_block_pattern, size)) {
4222 /* tuning is successful at this tuning point */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304223 if (!is_tuning_all_phases)
4224 goto kfree;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304226 pr_debug("%s: %s: found good phase = %d\n",
4227 mmc_hostname(mmc), __func__, phase);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304228 } else if (!is_tuning_all_phases) {
4229 pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
4230 mmc_hostname(mmc), (u32)phase);
4231 is_tuning_all_phases = true;
4232 goto retry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004233 }
4234 } while (++phase < 16);
4235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304237 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304238 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304239 if (rc < 0)
4240 goto kfree;
4241 else
4242 phase = (u8)rc;
4243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004244 /*
4245 * Finally set the selected phase in delay
4246 * line hw block.
4247 */
4248 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4249 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304250 goto kfree;
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304251 else
4252 host->saved_tuning_phase = phase;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304253 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4254 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 } else {
4256 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304257 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004258 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304259 msmsdcc_dump_sdcc_state(host);
4260 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004262
4263kfree:
4264 kfree(data_buf);
4265out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304266 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304267 host->tuning_in_progress = 0;
Subhash Jadavani355df542012-10-09 19:06:49 +05304268 if (!rc)
4269 host->tuning_done = true;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304270 spin_unlock_irqrestore(&host->lock, flags);
4271exit:
4272 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004274}
4275
Asutosh Dasebd7d092012-07-09 19:08:26 +05304276/*
4277 * Work around of the unavailability of a power_reset functionality in SD cards
4278 * by turning the OFF & back ON the regulators supplying the SD card.
4279 */
4280void msmsdcc_hw_reset(struct mmc_host *mmc)
4281{
4282 struct mmc_card *card = mmc->card;
4283 struct msmsdcc_host *host = mmc_priv(mmc);
4284 int rc;
4285
4286 /* Write-protection bits would be lost on a hardware reset in emmc */
4287 if (!card || !mmc_card_sd(card))
4288 return;
4289
Pratibhasagar V1aa03dc2012-11-29 12:48:17 +05304290 pr_debug("%s: Starting h/w reset\n", mmc_hostname(host->mmc));
4291
4292 if (host->plat->translate_vdd || host->plat->vreg_data) {
4293
4294 /* Disable the regulators */
4295 if (host->plat->translate_vdd)
4296 rc = host->plat->translate_vdd(mmc_dev(mmc), 0);
4297 else if (host->plat->vreg_data)
4298 rc = msmsdcc_setup_vreg(host, false, false);
4299
4300 if (rc) {
4301 pr_err("%s: Failed to disable voltage regulator\n",
4302 mmc_hostname(host->mmc));
4303 BUG_ON(rc);
4304 }
4305
4306 /* 10ms delay for supply to reach the desired voltage level */
4307 usleep_range(10000, 12000);
4308
4309 /* Enable the regulators */
4310 if (host->plat->translate_vdd)
4311 rc = host->plat->translate_vdd(mmc_dev(mmc), 1);
4312 else if (host->plat->vreg_data)
4313 rc = msmsdcc_setup_vreg(host, true, false);
4314
4315 if (rc) {
4316 pr_err("%s: Failed to enable voltage regulator\n",
4317 mmc_hostname(host->mmc));
4318 BUG_ON(rc);
4319 }
4320
4321 /* 10ms delay for supply to reach the desired voltage level */
4322 usleep_range(10000, 12000);
Asutosh Dasebd7d092012-07-09 19:08:26 +05304323 }
Asutosh Dasebd7d092012-07-09 19:08:26 +05304324}
4325
Subhash Jadavanid076af72013-02-17 23:36:03 +02004326/**
4327 * msmsdcc_stop_request - stops ongoing request
4328 * @mmc: MMC host, running the request
4329 *
4330 * Stops currently running request synchronously. All relevant request
4331 * information is cleared.
4332 */
4333int msmsdcc_stop_request(struct mmc_host *mmc)
4334{
4335 struct msmsdcc_host *host = mmc_priv(mmc);
4336 struct mmc_request *mrq;
4337 unsigned long flags;
4338 int rc = 0;
4339
4340 spin_lock_irqsave(&host->lock, flags);
4341 mrq = host->curr.mrq;
4342 if (mrq) {
4343 msmsdcc_reset_and_restore(host);
4344 /*
4345 * Note: We are just taking care of SPS. We may also
4346 * need to think about ADM (and PIO?) later if required.
4347 */
4348 if (host->sps.sg && is_sps_mode(host)) {
4349 if (!mrq->data->host_cookie)
4350 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
4351 host->sps.num_ents, host->sps.dir);
4352 host->sps.sg = NULL;
4353 host->sps.busy = 0;
4354 }
4355
4356 /*
4357 * Clear current request information as current
4358 * request has ended
4359 */
4360 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
4361 del_timer(&host->req_tout_timer);
4362 } else {
4363 rc = -EINVAL;
4364 }
4365 spin_unlock_irqrestore(&host->lock, flags);
4366
4367 return rc;
4368}
4369
4370/**
4371 * msmsdcc_get_xfer_remain - returns number of bytes passed on bus
4372 * @mmc: MMC host, running the request
4373 *
4374 * Returns the number of bytes passed for SPS transfer. 0 - for non-SPS
4375 * transfer.
4376 */
4377unsigned int msmsdcc_get_xfer_remain(struct mmc_host *mmc)
4378{
4379 struct msmsdcc_host *host = mmc_priv(mmc);
4380 u32 data_cnt = 0;
4381
4382 /* Currently, we don't support to stop the non-SPS transfer */
4383 if (host->sps.busy && atomic_read(&host->clks_on))
4384 data_cnt = readl_relaxed(host->base + MMCIDATACNT);
4385
4386 return data_cnt;
4387}
4388
San Mehat9d2bd732009-09-22 16:44:22 -07004389static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004390 .enable = msmsdcc_enable,
4391 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304392 .pre_req = msmsdcc_pre_req,
4393 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004394 .request = msmsdcc_request,
4395 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004396 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004397 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304398 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304399 .execute_tuning = msmsdcc_execute_tuning,
4400 .hw_reset = msmsdcc_hw_reset,
Subhash Jadavanid076af72013-02-17 23:36:03 +02004401 .stop_request = msmsdcc_stop_request,
4402 .get_xfer_remain = msmsdcc_get_xfer_remain,
San Mehat9d2bd732009-09-22 16:44:22 -07004403};
4404
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304405static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4406{
4407 unsigned int gpio_no = host->plat->status_gpio;
4408 int status;
4409
4410 if (!gpio_is_valid(gpio_no))
4411 return;
4412
4413 status = gpio_request(gpio_no, "SD_HW_Detect");
4414 if (status)
4415 pr_err("%s: %s: gpio_request(%d) failed\n",
4416 mmc_hostname(host->mmc), __func__, gpio_no);
4417}
4418
4419static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4420{
4421 if (gpio_is_valid(host->plat->status_gpio))
4422 gpio_free(host->plat->status_gpio);
4423}
4424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004425static unsigned int
4426msmsdcc_slot_status(struct msmsdcc_host *host)
4427{
4428 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304430 status = gpio_get_value_cansleep(host->plat->status_gpio);
4431 if (host->plat->is_status_gpio_active_low)
4432 status = !status;
4433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004434 return status;
4435}
4436
San Mehat9d2bd732009-09-22 16:44:22 -07004437static void
4438msmsdcc_check_status(unsigned long data)
4439{
4440 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4441 unsigned int status;
4442
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304443 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004444 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004445 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004446 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447 status = msmsdcc_slot_status(host);
4448
Krishna Konda941604a2012-01-10 17:46:34 -08004449 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004451 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004452 if (host->plat->status)
4453 pr_info("%s: Slot status change detected "
4454 "(%d -> %d)\n",
4455 mmc_hostname(host->mmc),
4456 host->oldstat, status);
4457 else if (host->plat->is_status_gpio_active_low)
4458 pr_info("%s: Slot status change detected "
4459 "(%d -> %d) and the card detect GPIO"
4460 " is ACTIVE_LOW\n",
4461 mmc_hostname(host->mmc),
4462 host->oldstat, status);
4463 else
4464 pr_info("%s: Slot status change detected "
4465 "(%d -> %d) and the card detect GPIO"
4466 " is ACTIVE_HIGH\n",
4467 mmc_hostname(host->mmc),
4468 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004469 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004470 }
4471 host->oldstat = status;
4472 } else {
4473 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004474 }
San Mehat9d2bd732009-09-22 16:44:22 -07004475}
4476
4477static irqreturn_t
4478msmsdcc_platform_status_irq(int irq, void *dev_id)
4479{
4480 struct msmsdcc_host *host = dev_id;
4481
Girish K Sa3c76eb2011-10-11 11:44:09 +05304482 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004483 msmsdcc_check_status((unsigned long) host);
4484 return IRQ_HANDLED;
4485}
4486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004487static irqreturn_t
4488msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4489{
4490 struct msmsdcc_host *host = dev_id;
4491
4492 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4493 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304494 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004495 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304496 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004497 wake_lock(&host->sdio_wlock);
4498 msmsdcc_disable_irq_wake(host);
4499 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304500 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004501 }
4502 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304504 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304505 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304506 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004507 }
4508 spin_unlock(&host->lock);
4509
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304510out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511 return IRQ_HANDLED;
4512}
4513
San Mehat9d2bd732009-09-22 16:44:22 -07004514static void
4515msmsdcc_status_notify_cb(int card_present, void *dev_id)
4516{
4517 struct msmsdcc_host *host = dev_id;
4518
Girish K Sa3c76eb2011-10-11 11:44:09 +05304519 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004520 card_present);
4521 msmsdcc_check_status((unsigned long) host);
4522}
4523
San Mehat9d2bd732009-09-22 16:44:22 -07004524static int
4525msmsdcc_init_dma(struct msmsdcc_host *host)
4526{
4527 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4528 host->dma.host = host;
4529 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004530 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004531
4532 if (!host->dmares)
4533 return -ENODEV;
4534
4535 host->dma.nc = dma_alloc_coherent(NULL,
4536 sizeof(struct msmsdcc_nc_dmadata),
4537 &host->dma.nc_busaddr,
4538 GFP_KERNEL);
4539 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004540 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004541 return -ENOMEM;
4542 }
4543 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4544 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4545 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4546 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4547 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004548 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004549
4550 return 0;
4551}
4552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4554/**
4555 * Allocate and Connect a SDCC peripheral's SPS endpoint
4556 *
4557 * This function allocates endpoint context and
4558 * connect it with memory endpoint by calling
4559 * appropriate SPS driver APIs.
4560 *
4561 * Also registers a SPS callback function with
4562 * SPS driver
4563 *
4564 * This function should only be called once typically
4565 * during driver probe.
4566 *
4567 * @host - Pointer to sdcc host structure
4568 * @ep - Pointer to sps endpoint data structure
4569 * @is_produce - 1 means Producer endpoint
4570 * 0 means Consumer endpoint
4571 *
4572 * @return - 0 if successful else negative value.
4573 *
4574 */
4575static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4576 struct msmsdcc_sps_ep_conn_data *ep,
4577 bool is_producer)
4578{
4579 int rc = 0;
4580 struct sps_pipe *sps_pipe_handle;
4581 struct sps_connect *sps_config = &ep->config;
4582 struct sps_register_event *sps_event = &ep->event;
4583
4584 /* Allocate endpoint context */
4585 sps_pipe_handle = sps_alloc_endpoint();
4586 if (!sps_pipe_handle) {
4587 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4588 mmc_hostname(host->mmc), is_producer);
4589 rc = -ENOMEM;
4590 goto out;
4591 }
4592
4593 /* Get default connection configuration for an endpoint */
4594 rc = sps_get_config(sps_pipe_handle, sps_config);
4595 if (rc) {
4596 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4597 " rc=%d", mmc_hostname(host->mmc),
4598 (u32)sps_pipe_handle, rc);
4599 goto get_config_err;
4600 }
4601
4602 /* Modify the default connection configuration */
4603 if (is_producer) {
4604 /*
4605 * For SDCC producer transfer, source should be
4606 * SDCC peripheral where as destination should
4607 * be system memory.
4608 */
4609 sps_config->source = host->sps.bam_handle;
4610 sps_config->destination = SPS_DEV_HANDLE_MEM;
4611 /* Producer pipe will handle this connection */
4612 sps_config->mode = SPS_MODE_SRC;
4613 sps_config->options =
4614 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4615 } else {
4616 /*
4617 * For SDCC consumer transfer, source should be
4618 * system memory where as destination should
4619 * SDCC peripheral
4620 */
4621 sps_config->source = SPS_DEV_HANDLE_MEM;
4622 sps_config->destination = host->sps.bam_handle;
4623 sps_config->mode = SPS_MODE_DEST;
4624 sps_config->options =
4625 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4626 }
4627
4628 /* Producer pipe index */
4629 sps_config->src_pipe_index = host->sps.src_pipe_index;
4630 /* Consumer pipe index */
4631 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4632 /*
4633 * This event thresold value is only significant for BAM-to-BAM
4634 * transfer. It's ignored for BAM-to-System mode transfer.
4635 */
4636 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304637
4638 /* Allocate maximum descriptor fifo size */
4639 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4640 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004641 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4642 sps_config->desc.size,
4643 &sps_config->desc.phys_base,
4644 GFP_KERNEL);
4645
Pratibhasagar V00b94332011-10-18 14:57:27 +05304646 if (!sps_config->desc.base) {
4647 rc = -ENOMEM;
4648 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4649 , mmc_hostname(host->mmc));
4650 goto get_config_err;
4651 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004652 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4653
4654 /* Establish connection between peripheral and memory endpoint */
4655 rc = sps_connect(sps_pipe_handle, sps_config);
4656 if (rc) {
4657 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4658 " rc=%d", mmc_hostname(host->mmc),
4659 (u32)sps_pipe_handle, rc);
4660 goto sps_connect_err;
4661 }
4662
4663 sps_event->mode = SPS_TRIGGER_CALLBACK;
4664 sps_event->options = SPS_O_EOT;
4665 sps_event->callback = msmsdcc_sps_complete_cb;
4666 sps_event->xfer_done = NULL;
4667 sps_event->user = (void *)host;
4668
4669 /* Register callback event for EOT (End of transfer) event. */
4670 rc = sps_register_event(sps_pipe_handle, sps_event);
4671 if (rc) {
4672 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4673 " rc=%d", mmc_hostname(host->mmc),
4674 (u32)sps_pipe_handle, rc);
4675 goto reg_event_err;
4676 }
4677 /* Now save the sps pipe handle */
4678 ep->pipe_handle = sps_pipe_handle;
4679 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4680 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4681 __func__, is_producer ? "READ" : "WRITE",
4682 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4683 goto out;
4684
4685reg_event_err:
4686 sps_disconnect(sps_pipe_handle);
4687sps_connect_err:
4688 dma_free_coherent(mmc_dev(host->mmc),
4689 sps_config->desc.size,
4690 sps_config->desc.base,
4691 sps_config->desc.phys_base);
4692get_config_err:
4693 sps_free_endpoint(sps_pipe_handle);
4694out:
4695 return rc;
4696}
4697
4698/**
4699 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4700 *
4701 * This function disconnect endpoint and deallocates
4702 * endpoint context.
4703 *
4704 * This function should only be called once typically
4705 * during driver remove.
4706 *
4707 * @host - Pointer to sdcc host structure
4708 * @ep - Pointer to sps endpoint data structure
4709 *
4710 */
4711static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4712 struct msmsdcc_sps_ep_conn_data *ep)
4713{
4714 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4715 struct sps_connect *sps_config = &ep->config;
4716 struct sps_register_event *sps_event = &ep->event;
4717
4718 sps_event->xfer_done = NULL;
4719 sps_event->callback = NULL;
4720 sps_register_event(sps_pipe_handle, sps_event);
4721 sps_disconnect(sps_pipe_handle);
4722 dma_free_coherent(mmc_dev(host->mmc),
4723 sps_config->desc.size,
4724 sps_config->desc.base,
4725 sps_config->desc.phys_base);
4726 sps_free_endpoint(sps_pipe_handle);
4727}
4728
4729/**
4730 * Reset SDCC peripheral's SPS endpoint
4731 *
4732 * This function disconnects an endpoint.
4733 *
4734 * This function should be called for reseting
4735 * SPS endpoint when data transfer error is
4736 * encountered during data transfer. This
4737 * can be considered as soft reset to endpoint.
4738 *
4739 * This function should only be called if
4740 * msmsdcc_sps_init() is already called.
4741 *
4742 * @host - Pointer to sdcc host structure
4743 * @ep - Pointer to sps endpoint data structure
4744 *
4745 * @return - 0 if successful else negative value.
4746 */
4747static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4748 struct msmsdcc_sps_ep_conn_data *ep)
4749{
4750 int rc = 0;
4751 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4752
4753 rc = sps_disconnect(sps_pipe_handle);
4754 if (rc) {
4755 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4756 " rc=%d", mmc_hostname(host->mmc), __func__,
4757 (u32)sps_pipe_handle, rc);
4758 goto out;
4759 }
4760 out:
4761 return rc;
4762}
4763
4764/**
4765 * Restore SDCC peripheral's SPS endpoint
4766 *
4767 * This function connects an endpoint.
4768 *
4769 * This function should be called for restoring
4770 * SPS endpoint after data transfer error is
4771 * encountered during data transfer. This
4772 * can be considered as soft reset to endpoint.
4773 *
4774 * This function should only be called if
4775 * msmsdcc_sps_reset_ep() is called before.
4776 *
4777 * @host - Pointer to sdcc host structure
4778 * @ep - Pointer to sps endpoint data structure
4779 *
4780 * @return - 0 if successful else negative value.
4781 */
4782static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4783 struct msmsdcc_sps_ep_conn_data *ep)
4784{
4785 int rc = 0;
4786 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4787 struct sps_connect *sps_config = &ep->config;
4788 struct sps_register_event *sps_event = &ep->event;
4789
4790 /* Establish connection between peripheral and memory endpoint */
4791 rc = sps_connect(sps_pipe_handle, sps_config);
4792 if (rc) {
4793 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4794 " rc=%d", mmc_hostname(host->mmc), __func__,
4795 (u32)sps_pipe_handle, rc);
4796 goto out;
4797 }
4798
4799 /* Register callback event for EOT (End of transfer) event. */
4800 rc = sps_register_event(sps_pipe_handle, sps_event);
4801 if (rc) {
4802 pr_err("%s: %s: sps_register_event() failed!!!"
4803 " pipe_handle=0x%x, rc=%d",
4804 mmc_hostname(host->mmc), __func__,
4805 (u32)sps_pipe_handle, rc);
4806 goto reg_event_err;
4807 }
4808 goto out;
4809
4810reg_event_err:
4811 sps_disconnect(sps_pipe_handle);
4812out:
4813 return rc;
4814}
4815
4816/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004817 * Handle BAM device's global error condition
4818 *
4819 * This is an error handler for the SDCC bam device
4820 *
4821 * This function is registered as a callback with SPS-BAM
4822 * driver and will called in case there are an errors for
4823 * the SDCC BAM deivce. Any error conditions in the BAM
4824 * device are global and will be result in this function
4825 * being called once per device.
4826 *
4827 * This function will be called from the sps driver's
4828 * interrupt context.
4829 *
4830 * @sps_cb_case - indicates what error it is
4831 * @user - Pointer to sdcc host structure
4832 */
4833static void
4834msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4835{
4836 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4837 struct mmc_request *mrq;
4838 unsigned long flags;
4839 int32_t error = 0;
4840
4841 BUG_ON(!host);
4842 BUG_ON(!is_sps_mode(host));
4843
4844 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004845 /* Reset all endpoints along with resetting bam. */
4846 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004847
4848 pr_err("%s: BAM Global ERROR IRQ happened\n",
4849 mmc_hostname(host->mmc));
4850 error = EAGAIN;
4851 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4852 /**
4853 * This means that there was an AHB access error and
4854 * the address we are trying to read/write is something
4855 * we dont have priviliges to do so.
4856 */
4857 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4858 mmc_hostname(host->mmc));
4859 error = EACCES;
4860 } else {
4861 /**
4862 * This should not have happened ideally. If this happens
4863 * there is some seriously wrong.
4864 */
4865 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4866 mmc_hostname(host->mmc), (u32) sps_cb_case);
4867 error = EIO;
4868 }
4869
4870 spin_lock_irqsave(&host->lock, flags);
4871
4872 mrq = host->curr.mrq;
4873
4874 if (mrq && mrq->cmd) {
4875 msmsdcc_dump_sdcc_state(host);
4876
4877 if (!mrq->cmd->error)
4878 mrq->cmd->error = -error;
4879 if (host->curr.data) {
4880 if (mrq->data && !mrq->data->error)
4881 mrq->data->error = -error;
4882 host->curr.data_xfered = 0;
4883 if (host->sps.sg && is_sps_mode(host)) {
4884 /* Stop current SPS transfer */
4885 msmsdcc_sps_exit_curr_xfer(host);
4886 } else {
4887 /* this condition should not have happened */
4888 pr_err("%s: something is seriously wrong. "\
4889 "Funtion: %s, line: %d\n",
4890 mmc_hostname(host->mmc),
4891 __func__, __LINE__);
4892 }
4893 } else {
4894 /* this condition should not have happened */
4895 pr_err("%s: something is seriously wrong. Funtion: "\
4896 "%s, line: %d\n", mmc_hostname(host->mmc),
4897 __func__, __LINE__);
4898 }
4899 }
4900 spin_unlock_irqrestore(&host->lock, flags);
4901}
4902
4903/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004904 * Initialize SPS HW connected with SDCC core
4905 *
4906 * This function register BAM HW resources with
4907 * SPS driver and then initialize 2 SPS endpoints
4908 *
4909 * This function should only be called once typically
4910 * during driver probe.
4911 *
4912 * @host - Pointer to sdcc host structure
4913 *
4914 * @return - 0 if successful else negative value.
4915 *
4916 */
4917static int msmsdcc_sps_init(struct msmsdcc_host *host)
4918{
4919 int rc = 0;
4920 struct sps_bam_props bam = {0};
4921
4922 host->bam_base = ioremap(host->bam_memres->start,
4923 resource_size(host->bam_memres));
4924 if (!host->bam_base) {
4925 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4926 " size=0x%x", mmc_hostname(host->mmc),
4927 host->bam_memres->start,
4928 (host->bam_memres->end -
4929 host->bam_memres->start));
4930 rc = -ENOMEM;
4931 goto out;
4932 }
4933
4934 bam.phys_addr = host->bam_memres->start;
4935 bam.virt_addr = host->bam_base;
4936 /*
4937 * This event thresold value is only significant for BAM-to-BAM
4938 * transfer. It's ignored for BAM-to-System mode transfer.
4939 */
4940 bam.event_threshold = 0x10; /* Pipe event threshold */
4941 /*
4942 * This threshold controls when the BAM publish
4943 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304944 * SPS HW will be used for data transfer size even
4945 * less than SDCC FIFO size. So let's set BAM summing
4946 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304948 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 /* SPS driver wll handle the SDCC BAM IRQ */
4950 bam.irq = (u32)host->bam_irqres->start;
4951 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004952 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4953 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004954
4955 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4956 (u32)bam.phys_addr);
4957 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4958 (u32)bam.virt_addr);
4959
4960 /* Register SDCC Peripheral BAM device to SPS driver */
4961 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4962 if (rc) {
4963 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4964 mmc_hostname(host->mmc), rc);
4965 goto reg_bam_err;
4966 }
4967 pr_info("%s: BAM device registered. bam_handle=0x%x",
4968 mmc_hostname(host->mmc), host->sps.bam_handle);
4969
4970 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4971 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4972
4973 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4974 SPS_PROD_PERIPHERAL);
4975 if (rc)
4976 goto sps_reset_err;
4977 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4978 SPS_CONS_PERIPHERAL);
4979 if (rc)
4980 goto cons_conn_err;
4981
4982 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4983 mmc_hostname(host->mmc),
4984 (unsigned long long)host->bam_memres->start,
4985 (unsigned int)host->bam_irqres->start);
4986 goto out;
4987
4988cons_conn_err:
4989 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4990sps_reset_err:
4991 sps_deregister_bam_device(host->sps.bam_handle);
4992reg_bam_err:
4993 iounmap(host->bam_base);
4994out:
4995 return rc;
4996}
4997
4998/**
4999 * De-initialize SPS HW connected with SDCC core
5000 *
5001 * This function deinitialize SPS endpoints and then
5002 * deregisters BAM resources from SPS driver.
5003 *
5004 * This function should only be called once typically
5005 * during driver remove.
5006 *
5007 * @host - Pointer to sdcc host structure
5008 *
5009 */
5010static void msmsdcc_sps_exit(struct msmsdcc_host *host)
5011{
5012 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
5013 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5014 sps_deregister_bam_device(host->sps.bam_handle);
5015 iounmap(host->bam_base);
5016}
5017#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
5018
5019static ssize_t
5020show_polling(struct device *dev, struct device_attribute *attr, char *buf)
5021{
5022 struct mmc_host *mmc = dev_get_drvdata(dev);
5023 struct msmsdcc_host *host = mmc_priv(mmc);
5024 int poll;
5025 unsigned long flags;
5026
5027 spin_lock_irqsave(&host->lock, flags);
5028 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
5029 spin_unlock_irqrestore(&host->lock, flags);
5030
5031 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
5032}
5033
5034static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305035store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005036 const char *buf, size_t count)
5037{
5038 struct mmc_host *mmc = dev_get_drvdata(dev);
5039 struct msmsdcc_host *host = mmc_priv(mmc);
5040 int value;
5041 unsigned long flags;
5042
5043 sscanf(buf, "%d", &value);
5044
5045 spin_lock_irqsave(&host->lock, flags);
5046 if (value) {
5047 mmc->caps |= MMC_CAP_NEEDS_POLL;
5048 mmc_detect_change(host->mmc, 0);
5049 } else {
5050 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005052 spin_unlock_irqrestore(&host->lock, flags);
5053 return count;
5054}
5055
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305056static ssize_t
5057show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
5058 char *buf)
5059{
5060 struct mmc_host *mmc = dev_get_drvdata(dev);
5061 struct msmsdcc_host *host = mmc_priv(mmc);
5062
5063 return snprintf(buf, PAGE_SIZE, "%u\n",
5064 host->msm_bus_vote.is_max_bw_needed);
5065}
5066
5067static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305068store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305069 const char *buf, size_t count)
5070{
5071 struct mmc_host *mmc = dev_get_drvdata(dev);
5072 struct msmsdcc_host *host = mmc_priv(mmc);
5073 uint32_t value;
5074 unsigned long flags;
5075
5076 if (!kstrtou32(buf, 0, &value)) {
5077 spin_lock_irqsave(&host->lock, flags);
5078 host->msm_bus_vote.is_max_bw_needed = !!value;
5079 spin_unlock_irqrestore(&host->lock, flags);
5080 }
5081
5082 return count;
5083}
5084
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305085static ssize_t
5086show_idle_timeout(struct device *dev, struct device_attribute *attr,
5087 char *buf)
5088{
5089 struct mmc_host *mmc = dev_get_drvdata(dev);
5090 struct msmsdcc_host *host = mmc_priv(mmc);
5091
5092 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05305093 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305094}
5095
5096static ssize_t
5097store_idle_timeout(struct device *dev, struct device_attribute *attr,
5098 const char *buf, size_t count)
5099{
5100 struct mmc_host *mmc = dev_get_drvdata(dev);
5101 struct msmsdcc_host *host = mmc_priv(mmc);
5102 unsigned int long flags;
5103 int timeout; /* in secs */
5104
5105 if (!kstrtou32(buf, 0, &timeout)
5106 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
5107 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05305108 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305109 spin_unlock_irqrestore(&host->lock, flags);
5110 }
5111 return count;
5112}
5113
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305114static inline void set_auto_cmd_setting(struct device *dev,
5115 const char *buf,
5116 bool is_cmd19)
5117{
5118 struct mmc_host *mmc = dev_get_drvdata(dev);
5119 struct msmsdcc_host *host = mmc_priv(mmc);
5120 unsigned int long flags;
5121 int temp;
5122
5123 if (!kstrtou32(buf, 0, &temp)) {
5124 spin_lock_irqsave(&host->lock, flags);
5125 if (is_cmd19)
5126 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305127 else
5128 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305129 spin_unlock_irqrestore(&host->lock, flags);
5130 }
5131}
5132
5133static ssize_t
5134show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5135 char *buf)
5136{
5137 struct mmc_host *mmc = dev_get_drvdata(dev);
5138 struct msmsdcc_host *host = mmc_priv(mmc);
5139
5140 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
5141}
5142
5143static ssize_t
5144store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5145 const char *buf, size_t count)
5146{
5147 set_auto_cmd_setting(dev, buf, true);
5148
5149 return count;
5150}
5151
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305152static ssize_t
5153show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5154 char *buf)
5155{
5156 struct mmc_host *mmc = dev_get_drvdata(dev);
5157 struct msmsdcc_host *host = mmc_priv(mmc);
5158
5159 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5160}
5161
5162static ssize_t
5163store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5164 const char *buf, size_t count)
5165{
5166 set_auto_cmd_setting(dev, buf, false);
5167
5168 return count;
5169}
5170
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305171static void msmsdcc_print_regs(const char *name, void __iomem *base,
5172 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305173{
5174 unsigned int i;
5175
5176 if (!base)
5177 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305178
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305179 pr_err("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305180 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305181 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305182 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305183 (u32)readl_relaxed(base + i*4),
5184 (u32)readl_relaxed(base + ((i+1)*4)),
5185 (u32)readl_relaxed(base + ((i+2)*4)),
5186 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305187 }
5188}
5189
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305190/*
5191 * This function prints the testbus debug output for all the
5192 * available SDCC controller test bus.
5193 *
5194 * Note: This function should only be called if the SDCC is clocked.
5195 */
5196static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
5197{
5198 int testbus_num;
5199
5200 if (!is_testbus_debug(host))
5201 return;
5202
5203 pr_err("== SDCC Test Bus Debug ==");
5204 for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
5205 writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
5206 | MCI_TESTBUS_ENA),
5207 host->base + MCI_TESTBUS_CONFIG);
5208 pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
5209 (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
5210 }
5211 /* Disable the test bus output */
5212 writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
5213}
5214
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305215static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5216{
5217 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305218 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305219 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305220 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305221 mmc_hostname(host->mmc),
5222 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305223 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305224 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305225 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5226
5227 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305228 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305229 msmsdcc_print_regs("SDCC-CORE", host->base,
5230 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305231 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5232 mmc_hostname(host->mmc),
5233 readl_relaxed(host->base + MCI_TEST_INPUT));
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305234 msmsdcc_print_testbus_info(host);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305235 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305236
5237 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305238 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305239 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305240 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305241 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305242 mmc_hostname(host->mmc), host->dma.busy,
5243 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305244 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305245 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305246 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5247 host->dml_memres->start,
5248 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305249 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305250 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305251 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305252
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305253 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305254 mmc_hostname(host->mmc), host->curr.xfer_size,
5255 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305256 }
5257
Krishna Konda3ca90f02012-08-29 16:29:21 -07005258 if (host->sps.reset_bam)
5259 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5260 mmc_hostname(host->mmc), host->sps.reset_bam);
5261
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305262 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305263 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5264 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5265 host->curr.got_dataend, host->prog_enable,
5266 host->curr.wait_for_auto_prog_done,
5267 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305268 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305269}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005271static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5272{
5273 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5274 struct mmc_request *mrq;
5275 unsigned long flags;
5276
5277 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005278 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005279 pr_info("%s: %s: dummy CMD52 timeout\n",
5280 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005281 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005282 }
5283
5284 mrq = host->curr.mrq;
5285
5286 if (mrq && mrq->cmd) {
Subhash Jadavani926a9cb2012-12-15 22:05:54 +05305287 if (!mrq->cmd->bkops_busy) {
5288 pr_info("%s: CMD%d: Request timeout\n",
5289 mmc_hostname(host->mmc), mrq->cmd->opcode);
5290 msmsdcc_dump_sdcc_state(host);
5291 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005293 if (!mrq->cmd->error)
5294 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305295 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005296 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005297 if (mrq->data && !mrq->data->error)
5298 mrq->data->error = -ETIMEDOUT;
5299 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305300 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005301 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305302 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005303 /* Stop current SPS transfer */
5304 msmsdcc_sps_exit_curr_xfer(host);
5305 } else {
5306 msmsdcc_reset_and_restore(host);
5307 msmsdcc_stop_data(host);
5308 if (mrq->data && mrq->data->stop)
5309 msmsdcc_start_command(host,
5310 mrq->data->stop, 0);
5311 else
5312 msmsdcc_request_end(host, mrq);
5313 }
5314 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305315 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305316 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005317 msmsdcc_reset_and_restore(host);
5318 msmsdcc_request_end(host, mrq);
5319 }
5320 }
5321 spin_unlock_irqrestore(&host->lock, flags);
5322}
5323
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305324/*
5325 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5326 *
5327 * @dev: device node from which the property value is to be read.
5328 * @prop_name: name of the property to be searched.
5329 * @out_array: filled array returned to caller
5330 * @len: filled array size returned to caller
5331 * @size: expected size of the array
5332 *
5333 * If expected "size" doesn't match with "len" an error is returned. If
5334 * expected size is zero, the length of actual array is returned provided
5335 * return value is zero.
5336 *
5337 * RETURNS:
5338 * zero on success, negative error if failed.
5339 */
5340static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5341 u32 **out_array, int *len, int size)
5342{
5343 int ret = 0;
5344 u32 *array = NULL;
5345 struct device_node *np = dev->of_node;
5346
5347 if (of_get_property(np, prop_name, len)) {
5348 size_t sz;
5349 sz = *len = *len / sizeof(*array);
5350
5351 if (sz > 0 && !(size > 0 && (sz != size))) {
5352 array = devm_kzalloc(dev, sz * sizeof(*array),
5353 GFP_KERNEL);
5354 if (!array) {
5355 dev_err(dev, "%s: no memory\n", prop_name);
5356 ret = -ENOMEM;
5357 goto out;
5358 }
5359
5360 ret = of_property_read_u32_array(np, prop_name,
5361 array, sz);
5362 if (ret < 0) {
5363 dev_err(dev, "%s: error reading array %d\n",
5364 prop_name, ret);
5365 goto out;
5366 }
5367 } else {
5368 dev_err(dev, "%s invalid size\n", prop_name);
5369 ret = -EINVAL;
5370 goto out;
5371 }
5372 } else {
5373 dev_err(dev, "%s not specified\n", prop_name);
5374 ret = -EINVAL;
5375 goto out;
5376 }
5377 *out_array = array;
5378out:
5379 if (ret)
5380 *len = 0;
5381 return ret;
5382}
5383
5384static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5385 struct msm_mmc_pad_pull_data **pad_pull_data)
5386{
5387 int ret = 0, base = 0, len, i;
5388 u32 *tmp;
5389 struct msm_mmc_pad_pull_data *pull_data;
5390 struct msm_mmc_pad_pull *pull;
5391
5392 switch (id) {
5393 case 1:
5394 base = TLMM_PULL_SDC1_CLK;
5395 break;
5396 case 2:
5397 base = TLMM_PULL_SDC2_CLK;
5398 break;
5399 case 3:
5400 base = TLMM_PULL_SDC3_CLK;
5401 break;
5402 case 4:
5403 base = TLMM_PULL_SDC4_CLK;
5404 break;
5405 default:
5406 dev_err(dev, "%s: Invalid slot id\n", __func__);
5407 ret = -EINVAL;
5408 goto err;
5409 }
5410
5411 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5412 GFP_KERNEL);
5413 if (!pull_data) {
5414 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5415 ret = -ENOMEM;
5416 goto err;
5417 }
5418 pull_data->size = 3; /* array size for clk, cmd, data */
5419
5420 /* Allocate on, off configs for clk, cmd, data */
5421 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5422 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5423 if (!pull) {
5424 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5425 ret = -ENOMEM;
5426 goto err;
5427 }
5428 pull_data->on = pull;
5429 pull_data->off = pull + pull_data->size;
5430
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005431 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305432 &tmp, &len, pull_data->size);
5433 if (!ret) {
5434 for (i = 0; i < len; i++) {
5435 pull_data->on[i].no = base + i;
5436 pull_data->on[i].val = tmp[i];
5437 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5438 i, pull_data->on[i].val);
5439 }
5440 } else {
5441 goto err;
5442 }
5443
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005444 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305445 &tmp, &len, pull_data->size);
5446 if (!ret) {
5447 for (i = 0; i < len; i++) {
5448 pull_data->off[i].no = base + i;
5449 pull_data->off[i].val = tmp[i];
5450 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5451 i, pull_data->off[i].val);
5452 }
5453 } else {
5454 goto err;
5455 }
5456
5457 *pad_pull_data = pull_data;
5458err:
5459 return ret;
5460}
5461
5462static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5463 struct msm_mmc_pad_drv_data **pad_drv_data)
5464{
5465 int ret = 0, base = 0, len, i;
5466 u32 *tmp;
5467 struct msm_mmc_pad_drv_data *drv_data;
5468 struct msm_mmc_pad_drv *drv;
5469
5470 switch (id) {
5471 case 1:
5472 base = TLMM_HDRV_SDC1_CLK;
5473 break;
5474 case 2:
5475 base = TLMM_HDRV_SDC2_CLK;
5476 break;
5477 case 3:
5478 base = TLMM_HDRV_SDC3_CLK;
5479 break;
5480 case 4:
5481 base = TLMM_HDRV_SDC4_CLK;
5482 break;
5483 default:
5484 dev_err(dev, "%s: Invalid slot id\n", __func__);
5485 ret = -EINVAL;
5486 goto err;
5487 }
5488
5489 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5490 GFP_KERNEL);
5491 if (!drv_data) {
5492 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5493 ret = -ENOMEM;
5494 goto err;
5495 }
5496 drv_data->size = 3; /* array size for clk, cmd, data */
5497
5498 /* Allocate on, off configs for clk, cmd, data */
5499 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5500 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5501 if (!drv) {
5502 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5503 ret = -ENOMEM;
5504 goto err;
5505 }
5506 drv_data->on = drv;
5507 drv_data->off = drv + drv_data->size;
5508
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005509 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305510 &tmp, &len, drv_data->size);
5511 if (!ret) {
5512 for (i = 0; i < len; i++) {
5513 drv_data->on[i].no = base + i;
5514 drv_data->on[i].val = tmp[i];
5515 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5516 i, drv_data->on[i].val);
5517 }
5518 } else {
5519 goto err;
5520 }
5521
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005522 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305523 &tmp, &len, drv_data->size);
5524 if (!ret) {
5525 for (i = 0; i < len; i++) {
5526 drv_data->off[i].no = base + i;
5527 drv_data->off[i].val = tmp[i];
5528 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5529 i, drv_data->off[i].val);
5530 }
5531 } else {
5532 goto err;
5533 }
5534
5535 *pad_drv_data = drv_data;
5536err:
5537 return ret;
5538}
5539
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305540static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5541 struct mmc_platform_data *pdata)
5542{
5543 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5544 struct device_node *np = dev->of_node;
5545
5546 pdata->status_gpio = of_get_named_gpio_flags(np,
5547 "cd-gpios", 0, &flags);
5548 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005549 struct platform_device *pdev = container_of(dev,
5550 struct platform_device, dev);
5551 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305552 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5553 }
5554
5555 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5556 "wp-gpios", 0, &flags);
5557 if (gpio_is_valid(pdata->wpswitch_gpio))
5558 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5559}
5560
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305561static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5562 struct mmc_platform_data *pdata)
5563{
5564 int ret = 0, id = 0, cnt, i;
5565 struct msm_mmc_pin_data *pin_data;
5566 struct device_node *np = dev->of_node;
5567
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305568 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5569
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305570 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5571 if (!pin_data) {
5572 dev_err(dev, "No memory for pin_data\n");
5573 ret = -ENOMEM;
5574 goto err;
5575 }
5576
5577 cnt = of_gpio_count(np);
5578 if (cnt > 0) {
5579 pin_data->is_gpio = true;
5580
5581 pin_data->gpio_data = devm_kzalloc(dev,
5582 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5583 if (!pin_data->gpio_data) {
5584 dev_err(dev, "No memory for gpio_data\n");
5585 ret = -ENOMEM;
5586 goto err;
5587 }
5588 pin_data->gpio_data->size = cnt;
5589 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5590 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5591 if (!pin_data->gpio_data->gpio) {
5592 dev_err(dev, "No memory for gpio\n");
5593 ret = -ENOMEM;
5594 goto err;
5595 }
5596
5597 for (i = 0; i < cnt; i++) {
5598 const char *name = NULL;
5599 char result[32];
5600 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5601 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005602 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305603
5604 snprintf(result, 32, "%s-%s",
5605 dev_name(dev), name ? name : "?");
5606 pin_data->gpio_data->gpio[i].name = result;
5607 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5608 pin_data->gpio_data->gpio[i].name,
5609 pin_data->gpio_data->gpio[i].no);
5610 }
5611 } else {
5612 pin_data->pad_data = devm_kzalloc(dev,
5613 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5614 if (!pin_data->pad_data) {
5615 dev_err(dev, "No memory for pin_data->pad_data\n");
5616 ret = -ENOMEM;
5617 goto err;
5618 }
5619
5620 of_property_read_u32(np, "cell-index", &id);
5621
5622 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5623 &pin_data->pad_data->pull);
5624 if (ret)
5625 goto err;
5626 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5627 &pin_data->pad_data->drv);
5628 if (ret)
5629 goto err;
5630 }
5631
5632 pdata->pin_data = pin_data;
5633err:
5634 if (ret)
5635 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5636 return ret;
5637}
5638
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305639#define MAX_PROP_SIZE 32
5640static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5641 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5642{
5643 int len, ret = 0;
5644 const __be32 *prop;
5645 char prop_name[MAX_PROP_SIZE];
5646 struct msm_mmc_reg_data *vreg;
5647 struct device_node *np = dev->of_node;
5648
5649 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5650 if (of_parse_phandle(np, prop_name, 0)) {
5651 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5652 if (!vreg) {
5653 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5654 ret = -ENOMEM;
5655 goto err;
5656 }
5657
5658 vreg->name = vreg_name;
5659
5660 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005661 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305662 if (of_get_property(np, prop_name, NULL))
5663 vreg->always_on = true;
5664
5665 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005666 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305667 if (of_get_property(np, prop_name, NULL))
5668 vreg->lpm_sup = true;
5669
5670 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005671 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305672 prop = of_get_property(np, prop_name, &len);
5673 if (!prop || (len != (2 * sizeof(__be32)))) {
5674 dev_warn(dev, "%s %s property\n",
5675 prop ? "invalid format" : "no", prop_name);
5676 } else {
5677 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5678 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5679 }
5680
5681 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005682 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305683 prop = of_get_property(np, prop_name, &len);
5684 if (!prop || (len != (2 * sizeof(__be32)))) {
5685 dev_warn(dev, "%s %s property\n",
5686 prop ? "invalid format" : "no", prop_name);
5687 } else {
5688 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5689 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5690 }
5691
5692 *vreg_data = vreg;
5693 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5694 vreg->name, vreg->always_on ? "always_on," : "",
5695 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5696 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5697 }
5698
5699err:
5700 return ret;
5701}
5702
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305703static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5704{
5705 int i, ret;
5706 struct mmc_platform_data *pdata;
5707 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305708 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005709 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305710 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305711
5712 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5713 if (!pdata) {
5714 dev_err(dev, "could not allocate memory for platform data\n");
5715 goto err;
5716 }
5717
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005718 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305719 if (bus_width == 8) {
5720 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5721 } else if (bus_width == 4) {
5722 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5723 } else {
5724 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5725 pdata->mmc_bus_width = 0;
5726 }
5727
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005728 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305729 &sup_voltages, &sup_volt_len, 0);
5730 if (!ret) {
5731 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305732 u32 mask;
5733
5734 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5735 sup_voltages[i + 1]);
5736 if (!mask)
5737 dev_err(dev, "Invalide voltage range %d\n", i);
5738 pdata->ocr_mask |= mask;
5739 }
5740 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305741 }
5742
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005743 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305744 &clk_table, &clk_table_len, 0);
5745 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305746 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305747 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305748 }
5749
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305750 pdata->vreg_data = devm_kzalloc(dev,
5751 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5752 if (!pdata->vreg_data) {
5753 dev_err(dev, "could not allocate memory for vreg_data\n");
5754 goto err;
5755 }
5756
5757 if (msmsdcc_dt_parse_vreg_info(dev,
5758 &pdata->vreg_data->vdd_data, "vdd"))
5759 goto err;
5760
5761 if (msmsdcc_dt_parse_vreg_info(dev,
5762 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5763 goto err;
5764
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305765 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5766 goto err;
5767
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005768 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305769
5770 for (i = 0; i < len; i++) {
5771 const char *name = NULL;
5772
5773 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005774 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305775 if (!name)
5776 continue;
5777
5778 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5779 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5780 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5781 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5782 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5783 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5784 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5785 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5786 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5787 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5788 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5789 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5790 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5791 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5792 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5793 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5794 | MMC_CAP_UHS_DDR50;
5795 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5796 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5797 | MMC_CAP_UHS_DDR50;
5798 }
5799
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005800 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305801 if (current_limit == 800)
5802 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5803 else if (current_limit == 600)
5804 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5805 else if (current_limit == 400)
5806 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5807 else if (current_limit == 200)
5808 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5809
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005810 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305811 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005812 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305813 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005814 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305815 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305816 of_property_read_u32(np, "qcom,dat1-mpm-int",
5817 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305818
5819 return pdata;
5820err:
5821 return NULL;
5822}
5823
San Mehat9d2bd732009-09-22 16:44:22 -07005824static int
5825msmsdcc_probe(struct platform_device *pdev)
5826{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305827 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005828 struct msmsdcc_host *host;
5829 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005830 unsigned long flags;
5831 struct resource *core_irqres = NULL;
5832 struct resource *bam_irqres = NULL;
5833 struct resource *core_memres = NULL;
5834 struct resource *dml_memres = NULL;
5835 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005836 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005837 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305838 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005839
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305840 if (pdev->dev.of_node) {
5841 plat = msmsdcc_populate_pdata(&pdev->dev);
5842 of_property_read_u32((&pdev->dev)->of_node,
5843 "cell-index", &pdev->id);
5844 } else {
5845 plat = pdev->dev.platform_data;
5846 }
San Mehat9d2bd732009-09-22 16:44:22 -07005847
5848 /* must have platform data */
5849 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005850 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005851 ret = -EINVAL;
5852 goto out;
5853 }
5854
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -08005855 if (disable_slots & (1 << (pdev->id - 1))) {
5856 pr_info("%s: Slot %d disabled\n", __func__, pdev->id);
5857 return -ENODEV;
5858 }
5859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005860 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005861 return -EINVAL;
5862
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305863 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5864 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5865 return -EINVAL;
5866 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005867
San Mehat9d2bd732009-09-22 16:44:22 -07005868 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005869 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005870 return -ENXIO;
5871 }
5872
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305873 core_memres = platform_get_resource_byname(pdev,
5874 IORESOURCE_MEM, "core_mem");
5875 bam_memres = platform_get_resource_byname(pdev,
5876 IORESOURCE_MEM, "bam_mem");
5877 dml_memres = platform_get_resource_byname(pdev,
5878 IORESOURCE_MEM, "dml_mem");
5879 core_irqres = platform_get_resource_byname(pdev,
5880 IORESOURCE_IRQ, "core_irq");
5881 bam_irqres = platform_get_resource_byname(pdev,
5882 IORESOURCE_IRQ, "bam_irq");
5883 dmares = platform_get_resource_byname(pdev,
5884 IORESOURCE_DMA, "dma_chnl");
5885 dma_crci_res = platform_get_resource_byname(pdev,
5886 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005888 if (!core_irqres || !core_memres) {
5889 pr_err("%s: Invalid sdcc core resource\n", __func__);
5890 return -ENXIO;
5891 }
5892
5893 /*
5894 * Both BAM and DML memory resource should be preset.
5895 * BAM IRQ resource should also be present.
5896 */
5897 if ((bam_memres && !dml_memres) ||
5898 (!bam_memres && dml_memres) ||
5899 ((bam_memres && dml_memres) && !bam_irqres)) {
5900 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005901 return -ENXIO;
5902 }
5903
5904 /*
5905 * Setup our host structure
5906 */
San Mehat9d2bd732009-09-22 16:44:22 -07005907 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5908 if (!mmc) {
5909 ret = -ENOMEM;
5910 goto out;
5911 }
5912
5913 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305914 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005915 host->plat = plat;
5916 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005917 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305918
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305919 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305920 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005921 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305922 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005924 host->base = ioremap(core_memres->start,
5925 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005926 if (!host->base) {
5927 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305928 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005929 }
5930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005931 host->core_irqres = core_irqres;
5932 host->bam_irqres = bam_irqres;
5933 host->core_memres = core_memres;
5934 host->dml_memres = dml_memres;
5935 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005936 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005937 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005938 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305939 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005941#ifdef CONFIG_MMC_EMBEDDED_SDIO
5942 if (plat->embedded_sdio)
5943 mmc_set_embedded_sdio_data(mmc,
5944 &plat->embedded_sdio->cis,
5945 &plat->embedded_sdio->cccr,
5946 plat->embedded_sdio->funcs,
5947 plat->embedded_sdio->num_funcs);
5948#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005949
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305950 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5951 (unsigned long)host);
5952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005953 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5954 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305955 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005956 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305957 ret = msmsdcc_init_dma(host);
5958 if (ret)
5959 goto ioremap_free;
5960 } else {
5961 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005962 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305963 }
San Mehat9d2bd732009-09-22 16:44:22 -07005964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005965 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305966 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005967 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305968 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5969 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5970 /* Vote for max. clk rate for max. performance */
5971 ret = clk_set_rate(host->bus_clk, INT_MAX);
5972 if (ret)
5973 goto bus_clk_put;
5974 ret = clk_prepare_enable(host->bus_clk);
5975 if (ret)
5976 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005977 }
5978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005979 /*
5980 * Setup main peripheral bus clock
5981 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005982 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005983 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305984 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005985 if (ret)
5986 goto pclk_put;
5987
5988 host->pclk_rate = clk_get_rate(host->pclk);
5989 }
5990
5991 /*
5992 * Setup SDC MMC clock
5993 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005994 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07005995 if (IS_ERR(host->clk)) {
5996 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005997 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07005998 }
5999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006000 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05306001 if (ret) {
6002 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
6003 goto clk_put;
6004 }
6005
Asutosh Dasf5298c32012-04-03 14:51:47 +05306006 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006007 if (ret)
6008 goto clk_put;
6009
San Mehat9d2bd732009-09-22 16:44:22 -07006010 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306011 if (!host->clk_rate)
6012 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05306013
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306014 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05306015 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306016
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306017 /*
6018 * Set the register write delay according to min. clock frequency
6019 * supported and update later when the host->clk_rate changes.
6020 */
6021 host->reg_write_delay =
6022 (1 + ((3 * USEC_PER_SEC) /
6023 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006024
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306025 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05306026 /* Apply Hard reset to SDCC to put it in power on default state */
6027 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006028
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006029#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306030 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006031 if (host->plat->cpu_dma_latency)
6032 host->cpu_dma_latency = host->plat->cpu_dma_latency;
6033 else
6034 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
6035 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306036 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
6037
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306038 ret = msmsdcc_msm_bus_register(host);
6039 if (ret)
6040 goto pm_qos_remove;
6041
6042 if (host->msm_bus_vote.client_handle)
6043 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
6044 msmsdcc_msm_bus_work);
6045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006046 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07006047 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006048 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07006049 goto clk_disable;
6050 }
6051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006052
6053 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306054 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006055 /* Initialize SPS */
6056 ret = msmsdcc_sps_init(host);
6057 if (ret)
6058 goto vreg_deinit;
6059 /* Initialize DML */
6060 ret = msmsdcc_dml_init(host);
6061 if (ret)
6062 goto sps_exit;
6063 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05306064 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07006065
San Mehat9d2bd732009-09-22 16:44:22 -07006066 /*
6067 * Setup MMC host structure
6068 */
6069 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006070 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
6071 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006072 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05306073 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
6074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006075 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
6076 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07006077 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05306078 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05306079 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306080 /*
6081 * If we send the CMD23 before multi block write/read command
6082 * then we need not to send CMD12 at the end of the transfer.
6083 * If we don't send the CMD12 then only way to detect the PROG_DONE
6084 * status is to use the AUTO_PROG_DONE status provided by SDCC4
6085 * controller. So let's enable the CMD23 for SDCC4 only.
6086 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306087 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306088 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07006089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006090 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05306091 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006092 /*
6093 * XPC controls the maximum current in the default speed mode of SDXC
6094 * card. XPC=0 means 100mA (max.) but speed class is not supported.
6095 * XPC=1 means 150mA (max.) and speed class is supported.
6096 */
6097 if (plat->xpc_cap)
6098 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
6099 MMC_CAP_SET_XPC_180);
6100
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02006101 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02006102 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05306103 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03006104 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03006105 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02006106 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Konstantin Dorfmana2c84222013-03-12 15:33:53 +02006107 mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
Yaniv Gardi14098552012-06-04 10:56:03 +03006108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006109 if (plat->nonremovable)
6110 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006111 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006112
6113 if (plat->is_sdio_al_client)
6114 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07006115
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306116 mmc->max_segs = msmsdcc_get_nr_sg(host);
6117 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
6118 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07006119
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306120 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07006121 mmc->max_seg_size = mmc->max_req_size;
6122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006123 writel_relaxed(0, host->base + MMCIMASK0);
6124 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05306125 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006127 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
6128 mb();
6129 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07006130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006131 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
6132 DRIVER_NAME " (cmd)", host);
6133 if (ret)
6134 goto dml_exit;
6135
6136 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
6137 DRIVER_NAME " (pio)", host);
6138 if (ret)
6139 goto irq_free;
6140
6141 /*
6142 * Enable SDCC IRQ only when host is powered on. Otherwise, this
6143 * IRQ is un-necessarily being monitored by MPM (Modem power
6144 * management block) during idle-power collapse. The MPM will be
6145 * configured to monitor the DATA1 GPIO line with level-low trigger
6146 * and thus depending on the GPIO status, it prevents TCXO shutdown
6147 * during idle-power collapse.
6148 */
6149 disable_irq(core_irqres->start);
6150 host->sdcc_irq_disabled = 1;
6151
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05306152 if (!plat->sdiowakeup_irq) {
6153 /* Check if registered as IORESOURCE_IRQ */
6154 plat->sdiowakeup_irq =
6155 platform_get_irq_byname(pdev, "sdiowakeup_irq");
6156 if (plat->sdiowakeup_irq < 0)
6157 plat->sdiowakeup_irq = 0;
6158 }
6159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006160 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161 ret = request_irq(plat->sdiowakeup_irq,
6162 msmsdcc_platform_sdiowakeup_irq,
6163 IRQF_SHARED | IRQF_TRIGGER_LOW,
6164 DRIVER_NAME "sdiowakeup", host);
6165 if (ret) {
6166 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6167 plat->sdiowakeup_irq, ret);
6168 goto pio_irq_free;
6169 } else {
6170 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306171 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006172 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306173 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006174 }
6175 spin_unlock_irqrestore(&host->lock, flags);
6176 }
6177 }
6178
Krishna Konda1963f432013-02-19 20:28:53 -08006179 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006180 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6181 mmc_hostname(mmc));
6182 }
6183
6184 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6185 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006186 /*
6187 * Setup card detect change
6188 */
6189
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306190 if (!plat->status_gpio)
6191 plat->status_gpio = -ENOENT;
6192 if (!plat->wpswitch_gpio)
6193 plat->wpswitch_gpio = -ENOENT;
6194
6195 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306196 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006197 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306198 } else {
6199 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006200 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306201 }
Krishna Konda941604a2012-01-10 17:46:34 -08006202 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006203 }
San Mehat9d2bd732009-09-22 16:44:22 -07006204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006205 if (plat->status_irq) {
6206 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006207 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006208 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006209 DRIVER_NAME " (slot)",
6210 host);
6211 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006212 pr_err("Unable to get slot IRQ %d (%d)\n",
6213 plat->status_irq, ret);
6214 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006215 }
6216 } else if (plat->register_status_notify) {
6217 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6218 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006219 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006220 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006221
6222 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006223
6224 ret = pm_runtime_set_active(&(pdev)->dev);
6225 if (ret < 0)
6226 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6227 __func__, ret);
6228 /*
6229 * There is no notion of suspend/resume for SD/MMC/SDIO
6230 * cards. So host can be suspended/resumed with out
6231 * worrying about its children.
6232 */
6233 pm_suspend_ignore_children(&(pdev)->dev, true);
6234
6235 /*
6236 * MMC/SD/SDIO bus suspend/resume operations are defined
6237 * only for the slots that will be used for non-removable
6238 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6239 * defined. Otherwise, they simply become card removal and
6240 * insertion events during suspend and resume respectively.
6241 * Hence, enable run-time PM only for slots for which bus
6242 * suspend/resume operations are defined.
6243 */
6244#ifdef CONFIG_MMC_UNSAFE_RESUME
6245 /*
6246 * If this capability is set, MMC core will enable/disable host
6247 * for every claim/release operation on a host. We use this
6248 * notification to increment/decrement runtime pm usage count.
6249 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006250 pm_runtime_enable(&(pdev)->dev);
6251#else
6252 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006253 pm_runtime_enable(&(pdev)->dev);
6254 }
6255#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306256 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006257 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6258 (unsigned long)host);
6259
San Mehat9d2bd732009-09-22 16:44:22 -07006260 mmc_add_host(mmc);
6261
Sujit Reddy Thumma97a35d22012-10-31 22:45:45 +05306262 mmc->clk_scaling.up_threshold = 35;
6263 mmc->clk_scaling.down_threshold = 5;
6264 mmc->clk_scaling.polling_delay_ms = 100;
6265 mmc->caps2 |= MMC_CAP2_CLK_SCALE;
6266
Krishna Konda25786ec2011-07-25 16:21:36 -07006267 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
6268 " dmacrcri %d\n", mmc_hostname(mmc),
6269 (unsigned long long)core_memres->start,
6270 (unsigned int) core_irqres->start,
6271 (unsigned int) plat->status_irq, host->dma.channel,
6272 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006273
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306274 pr_info("%s: Controller capabilities: 0x%.8x\n",
6275 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006276 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6277 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6278 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6279 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6280 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6281 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6282 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6283 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6284 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6285 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6286 host->eject);
6287 pr_info("%s: Power save feature enable = %d\n",
6288 mmc_hostname(mmc), msmsdcc_pwrsave);
6289
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306290 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006291 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006292 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006293 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006294 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006295 mmc_hostname(mmc), host->dma.cmd_busaddr,
6296 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306297 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006298 pr_info("%s: SPS-BAM data transfer mode available\n",
6299 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006300 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006301 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006303#if defined(CONFIG_DEBUG_FS)
6304 msmsdcc_dbg_createhost(host);
6305#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306306
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306307 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6308 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6309 sysfs_attr_init(&host->max_bus_bw.attr);
6310 host->max_bus_bw.attr.name = "max_bus_bw";
6311 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6312 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306313 if (ret)
6314 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306315
6316 if (!plat->status_irq) {
6317 host->polling.show = show_polling;
6318 host->polling.store = store_polling;
6319 sysfs_attr_init(&host->polling.attr);
6320 host->polling.attr.name = "polling";
6321 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6322 ret = device_create_file(&pdev->dev, &host->polling);
6323 if (ret)
6324 goto remove_max_bus_bw_file;
6325 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306326 host->idle_timeout.show = show_idle_timeout;
6327 host->idle_timeout.store = store_idle_timeout;
6328 sysfs_attr_init(&host->idle_timeout.attr);
6329 host->idle_timeout.attr.name = "idle_timeout";
6330 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6331 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6332 if (ret)
6333 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306334
6335 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306336 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306337
6338 /* Sysfs entry for AUTO CMD19 control */
6339 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6340 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6341 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6342 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6343 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6344 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6345 if (ret)
6346 goto remove_idle_timeout_file;
6347
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306348 add_auto_cmd21_atrr:
6349 if (!is_auto_cmd21(host))
6350 goto exit;
6351
6352 /* Sysfs entry for AUTO CMD21 control */
6353 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6354 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6355 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6356 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6357 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6358 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6359 if (ret)
6360 goto remove_auto_cmd19_attr_file;
6361
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306362 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006363 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006364
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306365 remove_auto_cmd19_attr_file:
6366 if (is_auto_cmd19(host))
6367 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306368 remove_idle_timeout_file:
6369 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306370 remove_polling_file:
6371 if (!plat->status_irq)
6372 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306373 remove_max_bus_bw_file:
6374 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006375 platform_irq_free:
6376 del_timer_sync(&host->req_tout_timer);
6377 pm_runtime_disable(&(pdev)->dev);
6378 pm_runtime_set_suspended(&(pdev)->dev);
6379
6380 if (plat->status_irq)
6381 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306382 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006383 sdiowakeup_irq_free:
Krishna Konda1963f432013-02-19 20:28:53 -08006384 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6385 wake_lock_destroy(&host->sdio_wlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006386 wake_lock_destroy(&host->sdio_suspend_wlock);
6387 if (plat->sdiowakeup_irq)
6388 free_irq(plat->sdiowakeup_irq, host);
6389 pio_irq_free:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006390 free_irq(core_irqres->start, host);
6391 irq_free:
6392 free_irq(core_irqres->start, host);
6393 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306394 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006395 msmsdcc_dml_exit(host);
6396 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306397 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006398 msmsdcc_sps_exit(host);
6399 vreg_deinit:
6400 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006401 clk_disable:
Krishna Konda7dd56c22012-11-08 17:52:32 -08006402 clk_disable_unprepare(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306403 msmsdcc_msm_bus_unregister(host);
6404 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006405 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306406 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006407 clk_put:
6408 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006409 pclk_disable:
6410 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306411 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006412 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006413 if (!IS_ERR(host->pclk))
6414 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306415 if (!IS_ERR_OR_NULL(host->bus_clk))
6416 clk_disable_unprepare(host->bus_clk);
6417 bus_clk_put:
6418 if (!IS_ERR_OR_NULL(host->bus_clk))
6419 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306420 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006421 if (host->dmares)
6422 dma_free_coherent(NULL,
6423 sizeof(struct msmsdcc_nc_dmadata),
6424 host->dma.nc, host->dma.nc_busaddr);
6425 }
6426 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306427 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006428 host_free:
6429 mmc_free_host(mmc);
6430 out:
6431 return ret;
6432}
6433
Pratibhasagar V713817b2012-09-07 11:28:30 +05306434#ifdef CONFIG_DEBUG_FS
6435static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6436{
6437 debugfs_remove_recursive(host->debugfs_host_dir);
6438 host->debugfs_host_dir = NULL;
6439}
6440#else
6441static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6442#endif
6443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006444static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006445{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006446 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6447 struct mmc_platform_data *plat;
6448 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006450 if (!mmc)
6451 return -ENXIO;
6452
6453 if (pm_runtime_suspended(&(pdev)->dev))
6454 pm_runtime_resume(&(pdev)->dev);
6455
6456 host = mmc_priv(mmc);
6457
6458 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6459 plat = host->plat;
6460
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306461 if (is_auto_cmd19(host))
6462 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306463 if (is_auto_cmd21(host))
6464 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306465 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006466 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306467 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306468 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006469
Pratibhasagar V713817b2012-09-07 11:28:30 +05306470 msmsdcc_remove_debugfs(host);
6471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006472 del_timer_sync(&host->req_tout_timer);
6473 tasklet_kill(&host->dma_tlet);
6474 tasklet_kill(&host->sps.tlet);
6475 mmc_remove_host(mmc);
6476
6477 if (plat->status_irq)
6478 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306479 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006480
6481 wake_lock_destroy(&host->sdio_suspend_wlock);
6482 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006483 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6484 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006486
Krishna Konda1963f432013-02-19 20:28:53 -08006487 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6488 wake_lock_destroy(&host->sdio_wlock);
6489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006490 free_irq(host->core_irqres->start, host);
6491 free_irq(host->core_irqres->start, host);
6492
6493 clk_put(host->clk);
6494 if (!IS_ERR(host->pclk))
6495 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306496 if (!IS_ERR_OR_NULL(host->bus_clk))
6497 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006498
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006499 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306500 pm_qos_remove_request(&host->pm_qos_req_dma);
6501
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306502 if (host->msm_bus_vote.client_handle) {
6503 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6504 msmsdcc_msm_bus_unregister(host);
6505 }
6506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006507 msmsdcc_vreg_init(host, false);
6508
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306509 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006510 if (host->dmares)
6511 dma_free_coherent(NULL,
6512 sizeof(struct msmsdcc_nc_dmadata),
6513 host->dma.nc, host->dma.nc_busaddr);
6514 }
6515
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306516 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006517 msmsdcc_dml_exit(host);
6518 msmsdcc_sps_exit(host);
6519 }
6520
6521 iounmap(host->base);
6522 mmc_free_host(mmc);
6523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006524 pm_runtime_disable(&(pdev)->dev);
6525 pm_runtime_set_suspended(&(pdev)->dev);
6526
6527 return 0;
6528}
6529
6530#ifdef CONFIG_MSM_SDIO_AL
6531int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6532{
6533 struct msmsdcc_host *host = mmc_priv(mmc);
6534 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306535 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006536
Asutosh Dasf5298c32012-04-03 14:51:47 +05306537 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006538 spin_lock_irqsave(&host->lock, flags);
6539 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6540 enable ? "En" : "Dis");
6541
6542 if (enable) {
6543 if (!host->sdcc_irq_disabled) {
6544 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306545 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006546 host->sdcc_irq_disabled = 1;
6547 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306548 rc = msmsdcc_setup_clocks(host, false);
6549 if (rc)
6550 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006551
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306552 if (host->plat->sdio_lpm_gpio_setup &&
6553 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006554 spin_unlock_irqrestore(&host->lock, flags);
6555 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6556 spin_lock_irqsave(&host->lock, flags);
6557 host->sdio_gpio_lpm = 1;
6558 }
6559
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306560 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006561 msmsdcc_enable_irq_wake(host);
6562 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306563 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006564 }
6565 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306566 rc = msmsdcc_setup_clocks(host, true);
6567 if (rc)
6568 goto out;
6569
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306570 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006571 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306572 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006573 msmsdcc_disable_irq_wake(host);
6574 }
6575
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306576 if (host->plat->sdio_lpm_gpio_setup &&
6577 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006578 spin_unlock_irqrestore(&host->lock, flags);
6579 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6580 spin_lock_irqsave(&host->lock, flags);
6581 host->sdio_gpio_lpm = 0;
6582 }
6583
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306584 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006585 writel_relaxed(host->mci_irqenable,
6586 host->base + MMCIMASK0);
6587 mb();
6588 enable_irq(host->core_irqres->start);
6589 host->sdcc_irq_disabled = 0;
6590 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006591 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306592out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006593 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306594 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306595 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006596}
6597#else
6598int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6599{
6600 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006601}
6602#endif
6603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006604#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306605#ifdef CONFIG_MMC_CLKGATE
6606static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6607{
6608 struct mmc_host *mmc = host->mmc;
6609 unsigned long flags;
6610
6611 mmc_host_clk_hold(mmc);
6612 spin_lock_irqsave(&mmc->clk_lock, flags);
6613 mmc->clk_old = mmc->ios.clock;
6614 mmc->ios.clock = 0;
6615 mmc->clk_gated = true;
6616 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6617 mmc_set_ios(mmc);
6618 mmc_host_clk_release(mmc);
6619}
6620
6621static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6622{
6623 struct mmc_host *mmc = host->mmc;
6624
6625 mmc_host_clk_hold(mmc);
6626 mmc->ios.clock = host->clk_rate;
6627 mmc_set_ios(mmc);
6628 mmc_host_clk_release(mmc);
6629}
6630#else
6631static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6632{
6633 struct mmc_host *mmc = host->mmc;
6634
6635 mmc->ios.clock = 0;
6636 mmc_set_ios(mmc);
6637}
6638
6639static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6640{
6641 struct mmc_host *mmc = host->mmc;
6642
6643 mmc->ios.clock = host->clk_rate;
6644 mmc_set_ios(mmc);
6645}
6646#endif
6647
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306648#if CONFIG_DEBUG_FS
6649static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306650 const char *func, int err)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306651{
6652 ktime_t diff;
6653
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306654 if (host->print_pm_stats && !err) {
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306655 diff = ktime_sub(ktime_get(), start);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306656 pr_info("%s: %s: Completed in %llu usec\n",
6657 mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306658 }
6659}
6660#else
6661static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306662 const char *func, int err) {}
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306663#endif
6664
San Mehat9d2bd732009-09-22 16:44:22 -07006665static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006666msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006667{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006668 struct mmc_host *mmc = dev_get_drvdata(dev);
6669 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006670 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306671 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306672 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006673
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306674 if (host->plat->is_sdio_al_client) {
6675 rc = 0;
6676 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006677 }
San Mehat9d2bd732009-09-22 16:44:22 -07006678
Sahitya Tummala7661a452011-07-18 13:28:35 +05306679 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006680 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006681 host->sdcc_suspending = 1;
6682 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006684 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006685 * MMC core thinks that host is disabled by now since
6686 * runtime suspend is scheduled after msmsdcc_disable()
6687 * is called. Thus, MMC core will try to enable the host
6688 * while suspending it. This results in a synchronous
6689 * runtime resume request while in runtime suspending
6690 * context and hence inorder to complete this resume
6691 * requet, it will wait for suspend to be complete,
6692 * but runtime suspend also can not proceed further
6693 * until the host is resumed. Thus, it leads to a hang.
6694 * Hence, increase the pm usage count before suspending
6695 * the host so that any resume requests after this will
6696 * simple become pm usage counter increment operations.
6697 */
6698 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306699 /* If there is pending detect work abort runtime suspend */
6700 if (unlikely(work_busy(&mmc->detect.work)))
6701 rc = -EAGAIN;
6702 else
6703 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006704 pm_runtime_put_noidle(dev);
6705
6706 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306707 spin_lock_irqsave(&host->lock, flags);
6708 host->sdcc_suspended = true;
6709 spin_unlock_irqrestore(&host->lock, flags);
6710 if (mmc->card && mmc_card_sdio(mmc->card) &&
6711 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006712 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306713 * If SDIO function driver doesn't want
6714 * to power off the card, atleast turn off
6715 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006716 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306717 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006718 }
6719 }
6720 host->sdcc_suspending = 0;
6721 mmc->suspend_task = NULL;
6722 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6723 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006724 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306725 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306726out:
6727 /* set bus bandwidth to 0 immediately */
6728 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306729 msmsdcc_print_pm_stats(host, start, __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07006730 return rc;
6731}
6732
6733static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006734msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006735{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006736 struct mmc_host *mmc = dev_get_drvdata(dev);
6737 struct msmsdcc_host *host = mmc_priv(mmc);
6738 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306739 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006741 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306742 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006743
Sahitya Tummala7661a452011-07-18 13:28:35 +05306744 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006745 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306746 if (mmc->card && mmc_card_sdio(mmc->card) &&
6747 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306748 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306749 }
San Mehat9d2bd732009-09-22 16:44:22 -07006750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006751 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006753 /*
6754 * FIXME: Clearing of flags must be handled in clients
6755 * resume handler.
6756 */
6757 spin_lock_irqsave(&host->lock, flags);
6758 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306759 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006760 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006762 /*
6763 * After resuming the host wait for sometime so that
6764 * the SDIO work will be processed.
6765 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306766 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306767 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006768 host->plat->sdiowakeup_irq) &&
6769 wake_lock_active(&host->sdio_wlock))
6770 wake_lock_timeout(&host->sdio_wlock, 1);
6771 }
6772
6773 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006774 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306775 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306776 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306777out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306778 msmsdcc_print_pm_stats(host, start, __func__, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07006779 return 0;
6780}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006781
6782static int msmsdcc_runtime_idle(struct device *dev)
6783{
6784 struct mmc_host *mmc = dev_get_drvdata(dev);
6785 struct msmsdcc_host *host = mmc_priv(mmc);
6786
6787 if (host->plat->is_sdio_al_client)
6788 return 0;
6789
6790 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306791 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006792
6793 return -EAGAIN;
6794}
6795
6796static int msmsdcc_pm_suspend(struct device *dev)
6797{
6798 struct mmc_host *mmc = dev_get_drvdata(dev);
6799 struct msmsdcc_host *host = mmc_priv(mmc);
6800 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306801 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006802
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306803 if (host->plat->is_sdio_al_client) {
6804 rc = 0;
6805 goto out;
6806 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306807 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006808 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306809 msmsdcc_disable_status_gpio(host);
6810 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006811
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306812 /*
6813 * If system comes out of suspend, msmsdcc_pm_resume() sets the
6814 * host->pending_resume flag if the SDCC wasn't runtime suspended.
6815 * Now if the system again goes to suspend without any SDCC activity
6816 * then host->pending_resume flag will remain set which may cause
6817 * the SDCC resume to happen first and then suspend.
6818 * To avoid this unnecessary resume/suspend, make sure that
6819 * pending_resume flag is cleared before calling the
6820 * msmsdcc_runtime_suspend().
6821 */
6822 if (!pm_runtime_suspended(dev) && !host->pending_resume)
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006823 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306824 out:
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306825 /* This flag must not be set if system is entering into suspend */
6826 host->pending_resume = false;
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306827 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006828 return rc;
6829}
6830
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306831static int msmsdcc_suspend_noirq(struct device *dev)
6832{
6833 struct mmc_host *mmc = dev_get_drvdata(dev);
6834 struct msmsdcc_host *host = mmc_priv(mmc);
6835 int rc = 0;
6836
6837 /*
6838 * After platform suspend there may be active request
6839 * which might have enabled clocks. For example, in SDIO
6840 * case, ksdioirq thread might have scheduled after sdcc
6841 * suspend but before system freeze. In that case abort
6842 * suspend and retry instead of keeping the clocks on
6843 * during suspend and not allowing TCXO.
6844 */
6845
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306846 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306847 pr_warn("%s: clocks are on after suspend, aborting system "
6848 "suspend\n", mmc_hostname(mmc));
6849 rc = -EAGAIN;
6850 }
6851
6852 return rc;
6853}
6854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006855static int msmsdcc_pm_resume(struct device *dev)
6856{
6857 struct mmc_host *mmc = dev_get_drvdata(dev);
6858 struct msmsdcc_host *host = mmc_priv(mmc);
6859 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306860 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006861
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306862 if (host->plat->is_sdio_al_client) {
6863 rc = 0;
6864 goto out;
6865 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006866 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306867 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306868 /*
6869 * As runtime PM is enabled before calling the device's platform resume
6870 * callback, we use the pm_runtime_suspended API to know if SDCC is
6871 * really runtime suspended or not and set the pending_resume flag only
6872 * if its not runtime suspended.
6873 */
6874 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006875 host->pending_resume = true;
6876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006877 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306878 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006879 msmsdcc_check_status((unsigned long)host);
6880 enable_irq(host->plat->status_irq);
6881 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306882out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306883 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006884 return rc;
6885}
6886
Daniel Walker08ecfde2010-06-23 12:32:20 -07006887#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006888static int msmsdcc_runtime_suspend(struct device *dev)
6889{
6890 return 0;
6891}
6892static int msmsdcc_runtime_idle(struct device *dev)
6893{
6894 return 0;
6895}
6896static int msmsdcc_pm_suspend(struct device *dev)
6897{
6898 return 0;
6899}
6900static int msmsdcc_pm_resume(struct device *dev)
6901{
6902 return 0;
6903}
6904static int msmsdcc_suspend_noirq(struct device *dev)
6905{
6906 return 0;
6907}
6908static int msmsdcc_runtime_resume(struct device *dev)
6909{
6910 return 0;
6911}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006912#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006913
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006914static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6915 .runtime_suspend = msmsdcc_runtime_suspend,
6916 .runtime_resume = msmsdcc_runtime_resume,
6917 .runtime_idle = msmsdcc_runtime_idle,
6918 .suspend = msmsdcc_pm_suspend,
6919 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306920 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006921};
6922
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306923static const struct of_device_id msmsdcc_dt_match[] = {
6924 {.compatible = "qcom,msm-sdcc"},
6925
6926};
6927MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6928
San Mehat9d2bd732009-09-22 16:44:22 -07006929static struct platform_driver msmsdcc_driver = {
6930 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006931 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006932 .driver = {
6933 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006934 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306935 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006936 },
6937};
6938
6939static int __init msmsdcc_init(void)
6940{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006941#if defined(CONFIG_DEBUG_FS)
6942 int ret = 0;
6943 ret = msmsdcc_dbg_init();
6944 if (ret) {
6945 pr_err("Failed to create debug fs dir \n");
6946 return ret;
6947 }
6948#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006949 return platform_driver_register(&msmsdcc_driver);
6950}
San Mehat9d2bd732009-09-22 16:44:22 -07006951
San Mehat9d2bd732009-09-22 16:44:22 -07006952static void __exit msmsdcc_exit(void)
6953{
6954 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006955
6956#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006957 debugfs_remove(debugfs_dir);
6958#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006959}
6960
6961module_init(msmsdcc_init);
6962module_exit(msmsdcc_exit);
6963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006964MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006965MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006966
6967#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05306968static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006969{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306970 struct msmsdcc_host *host = data;
6971
6972 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006973 return 0;
6974}
6975
Pratibhasagar V713817b2012-09-07 11:28:30 +05306976static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006977{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306978 struct msmsdcc_host *host = data;
6979 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006980
Pratibhasagar V713817b2012-09-07 11:28:30 +05306981 spin_lock_irqsave(&host->lock, flags);
6982 host->idle_tout = (u32)val * 1000;
6983 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006984
Pratibhasagar V713817b2012-09-07 11:28:30 +05306985 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006986}
6987
Pratibhasagar V713817b2012-09-07 11:28:30 +05306988DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
6989 msmsdcc_dbg_idle_tout_get,
6990 msmsdcc_dbg_idle_tout_set,
6991 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006992
Pratibhasagar V889d61c2012-09-09 19:51:14 +05306993static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
6994{
6995 struct msmsdcc_host *host = data;
6996
6997 *val = (u64) host->enforce_pio_mode;
6998 return 0;
6999}
7000
7001static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
7002{
7003 struct msmsdcc_host *host = data;
7004 unsigned long flags;
7005
7006 spin_lock_irqsave(&host->lock, flags);
7007 host->enforce_pio_mode = !!val;
7008 spin_unlock_irqrestore(&host->lock, flags);
7009
7010 return 0;
7011}
7012
7013DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
7014 msmsdcc_dbg_pio_mode_get,
7015 msmsdcc_dbg_pio_mode_set,
7016 "%llu\n");
7017
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307018static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
7019{
7020 struct msmsdcc_host *host = data;
7021
7022 *val = !!host->print_pm_stats;
7023 return 0;
7024}
7025
7026static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
7027{
7028 struct msmsdcc_host *host = data;
7029 unsigned long flags;
7030
7031 spin_lock_irqsave(&host->lock, flags);
7032 host->print_pm_stats = !!val;
7033 spin_unlock_irqrestore(&host->lock, flags);
7034
7035 return 0;
7036}
7037
7038DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
7039 msmsdcc_dbg_pm_stats_get,
7040 msmsdcc_dbg_pm_stats_set,
7041 "%llu\n");
7042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007043static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
7044{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307045 int err = 0;
7046
7047 if (!debugfs_dir)
7048 return;
7049
7050 host->debugfs_host_dir = debugfs_create_dir(
7051 mmc_hostname(host->mmc), debugfs_dir);
7052 if (IS_ERR(host->debugfs_host_dir)) {
7053 err = PTR_ERR(host->debugfs_host_dir);
7054 host->debugfs_host_dir = NULL;
7055 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
7056 mmc_hostname(host->mmc), err);
7057 return;
7058 }
7059
7060 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
7061 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7062 &msmsdcc_dbg_idle_tout_ops);
7063
7064 if (IS_ERR(host->debugfs_idle_tout)) {
7065 err = PTR_ERR(host->debugfs_idle_tout);
7066 host->debugfs_idle_tout = NULL;
7067 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
7068 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007069 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307070
7071 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
7072 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7073 &msmsdcc_dbg_pio_mode_ops);
7074
7075 if (IS_ERR(host->debugfs_pio_mode)) {
7076 err = PTR_ERR(host->debugfs_pio_mode);
7077 host->debugfs_pio_mode = NULL;
7078 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
7079 mmc_hostname(host->mmc), err);
7080 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307081
7082 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
7083 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7084 &msmsdcc_dbg_pm_stats_ops);
7085 if (IS_ERR(host->debugfs_pm_stats)) {
7086 err = PTR_ERR(host->debugfs_pm_stats);
7087 host->debugfs_pm_stats = NULL;
7088 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
7089 mmc_hostname(host->mmc), err);
7090 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007091}
7092
7093static int __init msmsdcc_dbg_init(void)
7094{
7095 int err;
7096
Pratibhasagar V713817b2012-09-07 11:28:30 +05307097 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007098 if (IS_ERR(debugfs_dir)) {
7099 err = PTR_ERR(debugfs_dir);
7100 debugfs_dir = NULL;
7101 return err;
7102 }
7103
7104 return 0;
7105}
7106#endif