blob: 3f3687b1a40e0860770caa5b00957a92a9355348 [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;
Sujit Reddy Thumma001a02f2013-01-23 10:31:38 +05301163 if ((i == data->sg_len - 1) &&
1164 (sps_pipe_handle ==
1165 host->sps.cons.pipe_handle)) {
1166 /*
1167 * set EOT only for consumer pipe, for
1168 * producer pipe h/w will set it.
1169 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 flags = SPS_IOVEC_FLAG_INT |
1171 SPS_IOVEC_FLAG_EOT;
Sujit Reddy Thumma001a02f2013-01-23 10:31:38 +05301172 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 }
1174 rc = sps_transfer_one(sps_pipe_handle, addr,
1175 data_cnt, host, flags);
1176 if (rc) {
1177 pr_err("%s: sps_transfer_one() error! rc=%d,"
1178 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1179 mmc_hostname(host->mmc), rc,
1180 (u32)sps_pipe_handle, (u32)sg, i);
1181 goto dma_map_err;
1182 }
1183 addr += data_cnt;
1184 len -= data_cnt;
1185 host->sps.xfer_req_cnt++;
1186 }
1187 sg++;
1188 }
1189 goto out;
1190
1191dma_map_err:
1192 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301193 if (!data->host_cookie)
1194 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1195 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196out:
1197 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001198}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199#else
1200static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1201 struct mmc_data *data) { return 0; }
1202#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001203
1204static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001205msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1206 struct mmc_command *cmd, u32 *c)
1207{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301208 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 cmd->opcode, cmd->arg, cmd->flags);
1210
San Mehat56a8b5b2009-11-21 12:29:46 -08001211 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1212
1213 if (cmd->flags & MMC_RSP_PRESENT) {
1214 if (cmd->flags & MMC_RSP_136)
1215 *c |= MCI_CPSM_LONGRSP;
1216 *c |= MCI_CPSM_RESPONSE;
1217 }
1218
1219 if (/*interrupt*/0)
1220 *c |= MCI_CPSM_INTERRUPT;
1221
Asutosh Das05049132012-05-09 12:38:15 +05301222 /* DAT_CMD bit should be set for all ADTC */
1223 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001224 *c |= MCI_CSPM_DATCMD;
1225
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301226 /* Check if AUTO CMD19/CMD21 is required or not? */
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301227 if (host->tuning_needed && (cmd->mrq->data &&
1228 (cmd->mrq->data->flags & MMC_DATA_READ)) &&
1229 (host->en_auto_cmd19 || host->en_auto_cmd21)) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301230 /*
1231 * For open ended block read operation (without CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301232 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1233 * the READ command.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301234 * For close ended block read operation (with CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301235 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1236 * CMD23.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301237 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301238 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1239 host->curr.mrq->cmd->opcode ==
1240 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301241 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301242 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301243 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1244 cmd->opcode == SD_IO_RW_EXTENDED))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301245 msmsdcc_enable_cdr_cm_sdc4_dll(host);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05301246 if (host->en_auto_cmd19 &&
1247 host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
1248 *c |= MCI_CSPM_AUTO_CMD19;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301249 else if (host->en_auto_cmd21 &&
1250 host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
1251 *c |= MCI_CSPM_AUTO_CMD21;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301252 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253 }
1254
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301255 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1256 writel_relaxed((readl_relaxed(host->base +
1257 MCI_DLL_CONFIG) | MCI_CDR_EN),
1258 host->base + MCI_DLL_CONFIG);
1259 else
1260 /* Clear CDR_EN bit for non read operations */
1261 writel_relaxed((readl_relaxed(host->base +
1262 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1263 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301264
Subhash Jadavani56fd4512012-12-19 19:05:02 +05301265 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301266 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301268 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001269 if (cmd == cmd->mrq->stop)
1270 *c |= MCI_CSPM_MCIABORT;
1271
San Mehat56a8b5b2009-11-21 12:29:46 -08001272 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301273 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001275 }
1276 host->curr.cmd = cmd;
1277}
1278
1279static void
1280msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1281 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001282{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301283 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001284 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001286 unsigned int pio_irqmask = 0;
1287
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301288 BUG_ON(!data->sg);
1289 BUG_ON(!data->sg_len);
1290
San Mehat9d2bd732009-09-22 16:44:22 -07001291 host->curr.data = data;
1292 host->curr.xfer_size = data->blksz * data->blocks;
1293 host->curr.xfer_remain = host->curr.xfer_size;
1294 host->curr.data_xfered = 0;
1295 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301296 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001297
San Mehat9d2bd732009-09-22 16:44:22 -07001298 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1299
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301300 if (host->curr.wait_for_auto_prog_done)
1301 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001302
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301303 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301304 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301306 } else if (is_sps_mode(host)) {
Krishna Konda7a05d532012-08-19 11:16:39 -07001307 if (!msmsdcc_sps_start_xfer(host, data)) {
1308 /* Now kick start DML transfer */
1309 mb();
1310 msmsdcc_dml_start_xfer(host, data);
1311 datactrl |= MCI_DPSM_DMAENABLE;
1312 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 }
1314 }
1315 }
1316
1317 /* Is data transfer in PIO mode required? */
1318 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001319 if (data->flags & MMC_DATA_READ) {
1320 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1321 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1322 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1323 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1325 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001326
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001327 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001328 }
1329
1330 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301331 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301332 else if (host->curr.use_wr_data_pend)
1333 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001334
Subhash Jadavanicfa14072013-01-30 16:47:07 +05301335 if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
1336 clks = (unsigned long long)data->timeout_ns *
1337 (host->clk_rate / 2);
1338 else
1339 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
1340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001342 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301343 WARN(!timeout,
1344 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1345 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001346
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301347 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 /* Use ADM (Application Data Mover) HW for Data transfer */
1349 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001350 host->cmd_timeout = timeout;
1351 host->cmd_pio_irqmask = pio_irqmask;
1352 host->cmd_datactrl = datactrl;
1353 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1356 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001357 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001358
1359 if (cmd) {
1360 msmsdcc_start_command_deferred(host, cmd, &c);
1361 host->cmd_c = c;
1362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1364 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1365 host->base + MMCIMASK0);
1366 mb();
1367 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001368 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1375 (~(MCI_IRQ_PIO))) | pio_irqmask,
1376 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001378
1379 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301380 /* Delay between data/command */
1381 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001382 /* Daisy-chain the command if requested */
1383 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301384 } else {
1385 /*
1386 * We don't need delay after writing to DATA_CTRL
1387 * register if we are not writing to CMD register
1388 * immediately after this. As we already have delay
1389 * before sending the command, we just need mb() here.
1390 */
1391 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001392 }
San Mehat9d2bd732009-09-22 16:44:22 -07001393 }
1394}
1395
1396static void
1397msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1398{
San Mehat56a8b5b2009-11-21 12:29:46 -08001399 msmsdcc_start_command_deferred(host, cmd, &c);
1400 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001401}
1402
1403static void
1404msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1405 unsigned int status)
1406{
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301407 if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
1408 u32 opcode = data->mrq->cmd->opcode;
1409
1410 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1411 || (opcode == MMC_BUS_TEST_R) ||
1412 (host->tuning_in_progress &&
1413 (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
1414 opcode == MMC_SEND_TUNING_BLOCK)))) {
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301415 /* Execute full tuning in case of CRC/timeout errors */
1416 host->saved_tuning_phase = INVALID_TUNING_PHASE;
1417
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301418 if (status & MCI_DATACRCFAIL) {
1419 pr_err("%s: Data CRC error\n",
1420 mmc_hostname(host->mmc));
1421 pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
1422 pr_err("%s: blksz %d, blocks %d\n", __func__,
1423 data->blksz, data->blocks);
1424 } else {
1425 pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
1426 mmc_hostname(host->mmc), opcode,
1427 (readl_relaxed(host->base
1428 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
1429 msmsdcc_dump_sdcc_state(host);
1430 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 }
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301432
1433 /*
1434 * CRC is optional for the bus test commands, not all
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435 * cards respond back with CRC. However controller
1436 * waits for the CRC and times out. Hence ignore the
1437 * data timeouts during the Bustest.
1438 */
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301439 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1440 || (opcode == MMC_BUS_TEST_R))) {
1441 if (status & MCI_DATACRCFAIL)
1442 data->error = -EILSEQ;
1443 else
1444 data->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 }
Subhash Jadavani355df542012-10-09 19:06:49 +05301446 /* In case of DATA CRC/timeout error, execute tuning again */
1447 if (host->tuning_needed && !host->tuning_in_progress)
1448 host->tuning_done = false;
1449
San Mehat9d2bd732009-09-22 16:44:22 -07001450 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001451 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001452 data->error = -EIO;
1453 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001454 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001455 data->error = -EIO;
1456 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001457 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001459 data->error = -EIO;
1460 }
San Mehat9d2bd732009-09-22 16:44:22 -07001461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001463 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 host->dummy_52_needed = 0;
1465}
San Mehat9d2bd732009-09-22 16:44:22 -07001466
1467static int
1468msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1469{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001471 uint32_t *ptr = (uint32_t *) buffer;
1472 int count = 0;
1473
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301474 if (remain % 4)
1475 remain = ((remain >> 2) + 1) << 2;
1476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1478
1479 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001480 ptr++;
1481 count += sizeof(uint32_t);
1482
1483 remain -= sizeof(uint32_t);
1484 if (remain == 0)
1485 break;
1486 }
1487 return count;
1488}
1489
1490static int
1491msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001493{
1494 void __iomem *base = host->base;
1495 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498 while (readl_relaxed(base + MMCISTATUS) &
1499 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1500 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001501
San Mehat9d2bd732009-09-22 16:44:22 -07001502 count = min(remain, maxcnt);
1503
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301504 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1505 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001506 ptr += count;
1507 remain -= count;
1508
1509 if (remain == 0)
1510 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 }
1512 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001513
1514 return ptr - buffer;
1515}
1516
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001517/*
1518 * Copy up to a word (4 bytes) between a scatterlist
1519 * and a temporary bounce buffer when the word lies across
1520 * two pages. The temporary buffer can then be read to/
1521 * written from the FIFO once.
1522 */
1523static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001524{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001525 struct msmsdcc_pio_data *pio = &host->pio;
1526 unsigned int bytes_avail;
1527
1528 if (host->curr.data->flags & MMC_DATA_READ)
1529 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1530 pio->bounce_buf_len);
1531 else
1532 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1533 pio->bounce_buf_len);
1534
1535 while (pio->bounce_buf_len != 4) {
1536 if (!sg_miter_next(&pio->sg_miter))
1537 break;
1538 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1539 4 - pio->bounce_buf_len);
1540 if (host->curr.data->flags & MMC_DATA_READ)
1541 memcpy(pio->sg_miter.addr,
1542 &pio->bounce_buf[pio->bounce_buf_len],
1543 bytes_avail);
1544 else
1545 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1546 pio->sg_miter.addr, bytes_avail);
1547
1548 pio->sg_miter.consumed = bytes_avail;
1549 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001550 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001551}
1552
1553/*
1554 * Use sg_miter_next to return as many 4-byte aligned
1555 * chunks as possible, using a temporary 4 byte buffer
1556 * for alignment if necessary
1557 */
1558static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1559{
1560 struct msmsdcc_pio_data *pio = &host->pio;
1561 unsigned int length, rlength;
1562 char *buffer;
1563
1564 if (!sg_miter_next(&pio->sg_miter))
1565 return 0;
1566
1567 buffer = pio->sg_miter.addr;
1568 length = pio->sg_miter.length;
1569
1570 if (length < host->curr.xfer_remain) {
1571 rlength = round_down(length, 4);
1572 if (rlength) {
1573 /*
1574 * We have a 4-byte aligned chunk.
1575 * The rounding will be reflected by
1576 * a call to msmsdcc_sg_consumed
1577 */
1578 length = rlength;
1579 goto sg_next_end;
1580 }
1581 /*
1582 * We have a length less than 4 bytes. Check to
1583 * see if more buffer is available, and combine
1584 * to make 4 bytes if possible.
1585 */
1586 pio->bounce_buf_len = length;
1587 memset(pio->bounce_buf, 0, 4);
1588
1589 /*
1590 * On a read, get 4 bytes from FIFO, and distribute
1591 * (4-bouce_buf_len) bytes into consecutive
1592 * sgl buffers when msmsdcc_sg_consumed is called
1593 */
1594 if (host->curr.data->flags & MMC_DATA_READ) {
1595 buffer = pio->bounce_buf;
1596 length = 4;
1597 goto sg_next_end;
1598 } else {
1599 _msmsdcc_sg_consume_word(host);
1600 buffer = pio->bounce_buf;
1601 length = pio->bounce_buf_len;
1602 }
1603 }
1604
1605sg_next_end:
1606 *buf = buffer;
1607 *len = length;
1608 return 1;
1609}
1610
1611/*
1612 * Update sg_miter.consumed based on how many bytes were
1613 * consumed. If the bounce buffer was used to read from FIFO,
1614 * redistribute into sgls.
1615 */
1616static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1617 unsigned int length)
1618{
1619 struct msmsdcc_pio_data *pio = &host->pio;
1620
1621 if (host->curr.data->flags & MMC_DATA_READ) {
1622 if (length > pio->sg_miter.consumed)
1623 /*
1624 * consumed 4 bytes, but sgl
1625 * describes < 4 bytes
1626 */
1627 _msmsdcc_sg_consume_word(host);
1628 else
1629 pio->sg_miter.consumed = length;
1630 } else
1631 if (length < pio->sg_miter.consumed)
1632 pio->sg_miter.consumed = length;
1633}
1634
1635static void msmsdcc_sg_start(struct msmsdcc_host *host)
1636{
1637 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1638
1639 host->pio.bounce_buf_len = 0;
1640
1641 if (host->curr.data->flags & MMC_DATA_READ)
1642 sg_miter_flags |= SG_MITER_TO_SG;
1643 else
1644 sg_miter_flags |= SG_MITER_FROM_SG;
1645
1646 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1647 host->curr.data->sg_len, sg_miter_flags);
1648}
1649
1650static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1651{
1652 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001653}
1654
San Mehat1cd22962010-02-03 12:59:29 -08001655static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001656msmsdcc_pio_irq(int irq, void *dev_id)
1657{
1658 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001660 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001661 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001662 unsigned int remain;
1663 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001664
Murali Palnati36448a42011-09-02 15:06:18 +05301665 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301666
Oluwafemi Adeyemi0bcb1332012-12-07 16:21:22 -08001667 if (!atomic_read(&host->clks_on)) {
1668 spin_unlock(&host->lock);
1669 return IRQ_NONE;
1670 }
1671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301675 (MCI_IRQ_PIO)) == 0) {
1676 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301677 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301678 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679#if IRQ_DEBUG
1680 msmsdcc_print_status(host, "irq1-r", status);
1681#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001682 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001683
1684 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001685 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1688 | MCI_RXDATAAVLBL)))
1689 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001690
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001691 if (!msmsdcc_sg_next(host, &buffer, &remain))
1692 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001693
San Mehat9d2bd732009-09-22 16:44:22 -07001694 len = 0;
1695 if (status & MCI_RXACTIVE)
1696 len = msmsdcc_pio_read(host, buffer, remain);
1697 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001699
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301700 /* len might have aligned to 32bits above */
1701 if (len > remain)
1702 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001703
San Mehat9d2bd732009-09-22 16:44:22 -07001704 host->curr.xfer_remain -= len;
1705 host->curr.data_xfered += len;
1706 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001707 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 if (remain) /* Done with this page? */
1710 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001713 } while (1);
1714
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001715 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001716 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1719 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1720 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1721 host->base + MMCIMASK0);
1722 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301723 /*
1724 * back to back write to MASK0 register don't need
1725 * synchronization delay.
1726 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1728 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1729 }
1730 mb();
1731 } else if (!host->curr.xfer_remain) {
1732 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1733 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1734 mb();
1735 }
San Mehat9d2bd732009-09-22 16:44:22 -07001736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001738
1739 return IRQ_HANDLED;
1740}
1741
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742static void
1743msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1744
1745static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1746 struct mmc_data *data)
1747{
1748 u32 loop_cnt = 0;
1749
1750 /*
1751 * For read commands with data less than fifo size, it is possible to
1752 * get DATAEND first and RXDATA_AVAIL might be set later because of
1753 * synchronization delay through the asynchronous RX FIFO. Thus, for
1754 * such cases, even after DATAEND interrupt is received software
1755 * should poll for RXDATA_AVAIL until the requested data is read out
1756 * of FIFO. This change is needed to get around this abnormal but
1757 * sometimes expected behavior of SDCC3 controller.
1758 *
1759 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1760 * after the data is loaded into RX FIFO. This would amount to less
1761 * than a microsecond and thus looping for 1000 times is good enough
1762 * for that delay.
1763 */
1764 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1765 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1766 spin_unlock(&host->lock);
1767 msmsdcc_pio_irq(1, host);
1768 spin_lock(&host->lock);
1769 }
1770 }
1771 if (loop_cnt == 1000) {
1772 pr_info("%s: Timed out while polling for Rx Data\n",
1773 mmc_hostname(host->mmc));
1774 data->error = -ETIMEDOUT;
1775 msmsdcc_reset_and_restore(host);
1776 }
1777}
1778
San Mehat9d2bd732009-09-22 16:44:22 -07001779static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1780{
1781 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001782
1783 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301784 if (mmc_resp_type(cmd))
1785 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1786 /*
1787 * Read rest of the response registers only if
1788 * long response is expected for this command
1789 */
1790 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1791 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1792 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1793 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1794 }
San Mehat9d2bd732009-09-22 16:44:22 -07001795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301797 pr_debug("%s: CMD%d: Command timeout\n",
1798 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001799 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301801 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301802 pr_err("%s: CMD%d: Command CRC error\n",
1803 mmc_hostname(host->mmc), cmd->opcode);
1804 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301805 /* Execute full tuning in case of CRC errors */
1806 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Subhash Jadavani355df542012-10-09 19:06:49 +05301807 if (host->tuning_needed)
1808 host->tuning_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001809 cmd->error = -EILSEQ;
1810 }
1811
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301812 if (!cmd->error) {
1813 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1814 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1815 mod_timer(&host->req_tout_timer, (jiffies +
1816 msecs_to_jiffies(host->curr.req_tout_ms)));
1817 }
1818 }
1819
San Mehat9d2bd732009-09-22 16:44:22 -07001820 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301822 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001823 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301825 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 /* Stop current SPS transfer */
1827 msmsdcc_sps_exit_curr_xfer(host);
1828 }
San Mehat9d2bd732009-09-22 16:44:22 -07001829 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301830 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001831 msmsdcc_stop_data(host);
1832 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301833 } else { /* host->data == NULL */
1834 if (!cmd->error && host->prog_enable) {
1835 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301837 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301839 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301840 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301841 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301842 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001843 if (host->dummy_52_needed)
1844 host->dummy_52_needed = 0;
1845 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301847 msmsdcc_request_end(host, cmd->mrq);
1848 }
1849 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301850 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301851 if (cmd == host->curr.mrq->sbc)
1852 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1853 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1854 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301855 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001856 }
1857}
1858
San Mehat9d2bd732009-09-22 16:44:22 -07001859static irqreturn_t
1860msmsdcc_irq(int irq, void *dev_id)
1861{
1862 struct msmsdcc_host *host = dev_id;
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301863 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001864 u32 status;
1865 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001867
1868 spin_lock(&host->lock);
1869
1870 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 struct mmc_command *cmd;
1872 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001873
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874 if (timer) {
1875 timer = 0;
1876 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001877 }
San Mehat9d2bd732009-09-22 16:44:22 -07001878
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301879 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 pr_debug("%s: %s: SDIO async irq received\n",
1881 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301882
1883 /*
1884 * Only async interrupt can come when clocks are off,
1885 * disable further interrupts and enable them when
1886 * clocks are on.
1887 */
1888 if (!host->sdcc_irq_disabled) {
1889 disable_irq_nosync(irq);
1890 host->sdcc_irq_disabled = 1;
1891 }
1892
1893 /*
1894 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1895 * will take care of signaling sdio irq during
1896 * mmc_sdio_resume().
1897 */
Krishna Konda1963f432013-02-19 20:28:53 -08001898 if (host->sdcc_suspended &&
1899 (host->plat->mpm_sdiowakeup_int ||
1900 host->plat->sdiowakeup_irq)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301901 /*
1902 * This is a wakeup interrupt so hold wakelock
1903 * until SDCC resume is handled.
1904 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301906 } else {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301907 if (!mmc->card || (mmc->card &&
1908 !mmc_card_sdio(mmc->card))) {
1909 pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1910 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301911 ret = 1;
1912 break;
1913 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301914 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301915 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301916 spin_lock(&host->lock);
1917 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301918 ret = 1;
1919 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 }
1921
1922 status = readl_relaxed(host->base + MMCISTATUS);
1923
1924 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1925 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001926 break;
1927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928#if IRQ_DEBUG
1929 msmsdcc_print_status(host, "irq0-r", status);
1930#endif
1931 status &= readl_relaxed(host->base + MMCIMASK0);
1932 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301933 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301934 if (host->clk_rate <=
1935 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301936 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937#if IRQ_DEBUG
1938 msmsdcc_print_status(host, "irq0-p", status);
1939#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 if (status & MCI_SDIOINTROPE) {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301942 if (!mmc->card || (mmc->card &&
1943 !mmc_card_sdio(mmc->card))) {
1944 pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
1945 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301946 ret = 1;
1947 break;
1948 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949 if (host->sdcc_suspending)
1950 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301951 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301953 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001954 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001955 data = host->curr.data;
1956
1957 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1959 MCI_CMDTIMEOUT)) {
1960 if (status & MCI_CMDTIMEOUT)
1961 pr_debug("%s: dummy CMD52 timeout\n",
1962 mmc_hostname(host->mmc));
1963 if (status & MCI_CMDCRCFAIL)
1964 pr_debug("%s: dummy CMD52 CRC failed\n",
1965 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001966 host->dummy_52_sent = 0;
1967 host->dummy_52_needed = 0;
1968 if (data) {
1969 msmsdcc_stop_data(host);
1970 msmsdcc_request_end(host, data->mrq);
1971 }
1972 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973 spin_unlock(&host->lock);
1974 return IRQ_HANDLED;
1975 }
1976 break;
1977 }
1978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 /*
1980 * Check for proper command response
1981 */
1982 cmd = host->curr.cmd;
1983 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1984 MCI_CMDTIMEOUT | MCI_PROGDONE |
1985 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1986 msmsdcc_do_cmdirq(host, status);
1987 }
1988
Subhash Jadavani2d7980f2013-01-09 16:18:08 +05301989 if (data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990 /* Check for data errors */
1991 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1992 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1993 msmsdcc_data_err(host, data, status);
1994 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301995 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001996 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301997 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998 /* Stop current SPS transfer */
1999 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302000 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 msmsdcc_reset_and_restore(host);
2002 if (host->curr.data)
2003 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302004 if (!data->stop || (host->curr.mrq->sbc
2005 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 timer |=
2007 msmsdcc_request_end(host,
2008 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302009 else if ((host->curr.mrq->sbc
2010 && data->error) ||
2011 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 msmsdcc_start_command(host,
2013 data->stop,
2014 0);
2015 timer = 1;
2016 }
2017 }
2018 }
2019
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302020 /* Check for prog done */
2021 if (host->curr.wait_for_auto_prog_done &&
2022 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302023 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 /* Check for data done */
2026 if (!host->curr.got_dataend && (status & MCI_DATAEND))
2027 host->curr.got_dataend = 1;
2028
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302029 if (host->curr.got_dataend &&
2030 (!host->curr.wait_for_auto_prog_done ||
2031 (host->curr.wait_for_auto_prog_done &&
2032 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 /*
2034 * If DMA is still in progress, we complete
2035 * via the completion handler
2036 */
2037 if (!host->dma.busy && !host->sps.busy) {
2038 /*
2039 * There appears to be an issue in the
2040 * controller where if you request a
2041 * small block transfer (< fifo size),
2042 * you may get your DATAEND/DATABLKEND
2043 * irq without the PIO data irq.
2044 *
2045 * Check to see if theres still data
2046 * to be read, and simulate a PIO irq.
2047 */
2048 if (data->flags & MMC_DATA_READ)
2049 msmsdcc_wait_for_rxdata(host,
2050 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002051 if (!data->error) {
2052 host->curr.data_xfered =
2053 host->curr.xfer_size;
2054 host->curr.xfer_remain -=
2055 host->curr.xfer_size;
2056 }
2057
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002058 if (!host->dummy_52_needed) {
2059 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302060 if (!data->stop ||
2061 (host->curr.mrq->sbc
2062 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002063 msmsdcc_request_end(
2064 host,
2065 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302066 else if ((host->curr.mrq->sbc
2067 && data->error) ||
2068 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002069 msmsdcc_start_command(
2070 host,
2071 data->stop, 0);
2072 timer = 1;
2073 }
2074 } else {
2075 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002077 &dummy52cmd,
2078 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 }
2080 }
2081 }
2082 }
2083
San Mehat9d2bd732009-09-22 16:44:22 -07002084 ret = 1;
2085 } while (status);
2086
2087 spin_unlock(&host->lock);
2088
San Mehat9d2bd732009-09-22 16:44:22 -07002089 return IRQ_RETVAL(ret);
2090}
2091
2092static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302093msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2094 bool is_first_request)
2095{
2096 struct msmsdcc_host *host = mmc_priv(mmc);
2097 struct mmc_data *data = mrq->data;
2098 int rc = 0;
2099
2100 if (unlikely(!data)) {
2101 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2102 __func__);
2103 return;
2104 }
2105 if (unlikely(data->host_cookie)) {
2106 /* Very wrong */
2107 data->host_cookie = 0;
2108 pr_err("%s: %s Request reposted for prepare\n",
2109 mmc_hostname(mmc), __func__);
2110 return;
2111 }
2112
2113 if (!msmsdcc_is_dma_possible(host, data))
2114 return;
2115
2116 rc = msmsdcc_prep_xfer(host, data);
2117 if (unlikely(rc < 0)) {
2118 data->host_cookie = 0;
2119 return;
2120 }
2121
2122 data->host_cookie = 1;
2123}
2124
2125static void
2126msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2127{
2128 struct msmsdcc_host *host = mmc_priv(mmc);
2129 unsigned int dir;
2130 struct mmc_data *data = mrq->data;
2131
2132 if (unlikely(!data)) {
2133 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2134 __func__);
2135 return;
2136 }
2137 if (data->flags & MMC_DATA_READ)
2138 dir = DMA_FROM_DEVICE;
2139 else
2140 dir = DMA_TO_DEVICE;
2141
2142 if (data->host_cookie)
2143 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2144 data->sg_len, dir);
2145
2146 data->host_cookie = 0;
2147}
2148
2149static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2151{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302152 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302154 if ((mrq->data->flags & MMC_DATA_READ) ||
2155 host->curr.use_wr_data_pend)
2156 msmsdcc_start_data(host, mrq->data,
2157 mrq->sbc ? mrq->sbc : mrq->cmd,
2158 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302159 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302160 msmsdcc_start_command(host,
2161 mrq->sbc ? mrq->sbc : mrq->cmd,
2162 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002163 } else {
2164 msmsdcc_start_command(host, mrq->cmd, 0);
2165 }
2166}
2167
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302168/*
2169 * This function returns true if AUTO_PROG_DONE feature of host is
2170 * applicable for current request, returns "false" otherwise.
2171 *
2172 * NOTE: Caller should call this function only for data write operations.
2173 */
2174static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2175 struct mmc_request *mrq)
2176{
2177 /*
2178 * Auto-prog done will be enabled for following cases:
2179 * mrq->sbc | mrq->stop
2180 * _____________|________________
2181 * True | Don't care
2182 * False | False (CMD24, ACMD25 use case)
2183 */
2184 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2185 return true;
2186
2187 return false;
2188}
2189
2190/*
2191 * This function returns true if controller can wait for prog done
2192 * for current request, returns "false" otherwise.
2193 *
2194 * NOTE: Caller should call this function only for data write operations.
2195 */
2196static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2197 struct mmc_request *mrq)
2198{
2199 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2200 return true;
2201
2202 return false;
2203}
2204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205static void
San Mehat9d2bd732009-09-22 16:44:22 -07002206msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2207{
2208 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302209 unsigned long flags;
Krishna Konda3d47c822013-02-21 18:28:11 -08002210 unsigned int error = 0;
Krishna Konda3ca90f02012-08-29 16:29:21 -07002211 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 /*
2214 * Get the SDIO AL client out of LPM.
2215 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002216 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217 if (host->plat->is_sdio_al_client)
2218 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002219
Krishna Konda3d47c822013-02-21 18:28:11 -08002220 /*
2221 * Don't start the request if SDCC is not in proper state to handle it
2222 * BAM state is checked below if applicable
2223 */
2224 if (!host->pwr || !atomic_read(&host->clks_on) ||
2225 host->sdcc_irq_disabled) {
2226 WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
2227 mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
2228 error = EIO;
2229 goto bad_state;
2230 }
2231
Krishna Konda3ca90f02012-08-29 16:29:21 -07002232 /* check if sps bam needs to be reset */
2233 if (is_sps_mode(host) && host->sps.reset_bam) {
2234 while (retries) {
2235 if (!msmsdcc_bam_dml_reset_and_restore(host))
2236 break;
2237 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2238 mmc_hostname(host->mmc), --retries);
2239 }
Krishna Konda3d47c822013-02-21 18:28:11 -08002240
2241 /* check if BAM reset succeeded or not */
2242 if (host->sps.reset_bam) {
2243 pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
2244 mmc_hostname(host->mmc), mrq->cmd->opcode);
2245 error = EAGAIN;
2246 goto bad_state;
2247 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302248 }
San Mehat9d2bd732009-09-22 16:44:22 -07002249
Subhash Jadavani355df542012-10-09 19:06:49 +05302250 /*
2251 * Check if DLL retuning is required? If yes, perform it here before
2252 * starting new request.
2253 */
2254 if (host->tuning_needed && !host->tuning_in_progress &&
2255 !host->tuning_done) {
2256 pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
2257 mmc_hostname(mmc), __func__, host->mmc->ios.timing);
2258 if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
2259 msmsdcc_execute_tuning(mmc,
2260 MMC_SEND_TUNING_BLOCK);
2261 else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
2262 msmsdcc_execute_tuning(mmc,
2263 MMC_SEND_TUNING_BLOCK_HS200);
2264 }
2265
San Mehat9d2bd732009-09-22 16:44:22 -07002266 if (host->eject) {
Krishna Konda3d47c822013-02-21 18:28:11 -08002267 error = ENOMEDIUM;
2268 goto card_ejected;
subhashjf181c292012-05-02 13:07:40 +05302269 }
2270
2271 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2272 " other request (CMD%d) is in progress\n",
2273 mmc_hostname(host->mmc), __func__,
2274 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2275
Krishna Konda3d47c822013-02-21 18:28:11 -08002276 spin_lock_irqsave(&host->lock, flags);
2277
subhashjf181c292012-05-02 13:07:40 +05302278 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302279 * Set timeout value to 10 secs (or more in case of buggy cards)
2280 */
2281 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302282 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302283 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302284 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302285 /*
2286 * Kick the software request timeout timer here with the timeout
2287 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302288 */
2289 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302290 (jiffies +
2291 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002292
San Mehat9d2bd732009-09-22 16:44:22 -07002293 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302294 if (mrq->sbc) {
2295 mrq->sbc->mrq = mrq;
2296 mrq->sbc->data = mrq->data;
2297 }
2298
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302299 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302300 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2301 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302302 } else {
2303 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2304 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 host->dummy_52_needed = 1;
2306 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302307
Subhash Jadavanif5277752011-10-12 16:47:52 +05302308 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
Subhash Jadavanicf58e6f2012-10-05 20:45:54 +05302309 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
2310 ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
2311 is_data_pend_for_cmd53(host)))
Subhash Jadavanif5277752011-10-12 16:47:52 +05302312 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002313 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302314
Subhash Jadavanif5277752011-10-12 16:47:52 +05302315 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002316 spin_unlock_irqrestore(&host->lock, flags);
Krishna Konda3d47c822013-02-21 18:28:11 -08002317 return;
2318
2319bad_state:
2320 msmsdcc_dump_sdcc_state(host);
2321card_ejected:
2322 mrq->cmd->error = -error;
2323 if (mrq->data) {
2324 mrq->data->error = -error;
2325 mrq->data->bytes_xfered = 0;
2326 }
2327 mmc_request_done(mmc, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002328}
2329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2331 int min_uV, int max_uV)
2332{
2333 int rc = 0;
2334
2335 if (vreg->set_voltage_sup) {
2336 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2337 if (rc) {
2338 pr_err("%s: regulator_set_voltage(%s) failed."
2339 " min_uV=%d, max_uV=%d, rc=%d\n",
2340 __func__, vreg->name, min_uV, max_uV, rc);
2341 }
2342 }
2343
2344 return rc;
2345}
2346
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302347static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2348{
2349 int rc = 0;
2350
2351 rc = regulator_get_voltage(vreg->reg);
2352 if (rc < 0)
2353 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2354 __func__, vreg->name, rc);
2355
2356 return rc;
2357}
2358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2360 int uA_load)
2361{
2362 int rc = 0;
2363
Krishna Kondafea60182011-11-01 16:01:34 -07002364 /* regulators that do not support regulator_set_voltage also
2365 do not support regulator_set_optimum_mode */
2366 if (vreg->set_voltage_sup) {
2367 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2368 if (rc < 0)
2369 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2370 "uA_load=%d) failed. rc=%d\n", __func__,
2371 vreg->name, uA_load, rc);
2372 else
2373 /* regulator_set_optimum_mode() can return non zero
2374 * value even for success case.
2375 */
2376 rc = 0;
2377 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378
2379 return rc;
2380}
2381
2382static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2383 struct device *dev)
2384{
2385 int rc = 0;
2386
2387 /* check if regulator is already initialized? */
2388 if (vreg->reg)
2389 goto out;
2390
2391 /* Get the regulator handle */
2392 vreg->reg = regulator_get(dev, vreg->name);
2393 if (IS_ERR(vreg->reg)) {
2394 rc = PTR_ERR(vreg->reg);
2395 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2396 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002397 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002399
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302400 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002401 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302402 /* sanity check */
2403 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2404 pr_err("%s: %s invalid constraints specified\n",
2405 __func__, vreg->name);
2406 rc = -EINVAL;
2407 }
2408 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410out:
2411 return rc;
2412}
2413
2414static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2415{
2416 if (vreg->reg)
2417 regulator_put(vreg->reg);
2418}
2419
2420/* This init function should be called only once for each SDCC slot */
2421static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2422{
2423 int rc = 0;
2424 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302425 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426 struct device *dev = mmc_dev(host->mmc);
2427
2428 curr_slot = host->plat->vreg_data;
2429 if (!curr_slot)
2430 goto out;
2431
2432 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302433 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434
2435 if (is_init) {
2436 /*
2437 * Get the regulator handle from voltage regulator framework
2438 * and then try to set the voltage level for the regulator
2439 */
2440 if (curr_vdd_reg) {
2441 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2442 if (rc)
2443 goto out;
2444 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302445 if (curr_vdd_io_reg) {
2446 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 if (rc)
2448 goto vdd_reg_deinit;
2449 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002450 rc = msmsdcc_vreg_reset(host);
2451 if (rc)
2452 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302453 host->pdev->id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 goto out;
2455 } else {
2456 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302457 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302459vdd_io_reg_deinit:
2460 if (curr_vdd_io_reg)
2461 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462vdd_reg_deinit:
2463 if (curr_vdd_reg)
2464 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2465out:
2466 return rc;
2467}
2468
2469static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2470{
2471 int rc = 0;
2472
Subhash Jadavanicc922692011-08-01 23:05:01 +05302473 /* Put regulator in HPM (high power mode) */
2474 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2475 if (rc < 0)
2476 goto out;
2477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002478 if (!vreg->is_enabled) {
2479 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302480 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2481 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482 if (rc)
2483 goto out;
2484
2485 rc = regulator_enable(vreg->reg);
2486 if (rc) {
2487 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2488 __func__, vreg->name, rc);
2489 goto out;
2490 }
2491 vreg->is_enabled = true;
2492 }
2493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494out:
2495 return rc;
2496}
2497
Krishna Konda3c4142d2012-06-27 11:01:56 -07002498static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499{
2500 int rc = 0;
2501
2502 /* Never disable regulator marked as always_on */
2503 if (vreg->is_enabled && !vreg->always_on) {
2504 rc = regulator_disable(vreg->reg);
2505 if (rc) {
2506 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2507 __func__, vreg->name, rc);
2508 goto out;
2509 }
2510 vreg->is_enabled = false;
2511
2512 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2513 if (rc < 0)
2514 goto out;
2515
2516 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302517 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518 if (rc)
2519 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002520 } else if (vreg->is_enabled && vreg->always_on) {
2521 if (!is_init && vreg->lpm_sup) {
2522 /* Put always_on regulator in LPM (low power mode) */
2523 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2524 if (rc < 0)
2525 goto out;
2526 } else if (is_init && vreg->reset_at_init) {
2527 /**
2528 * The regulator might not actually be disabled if it
2529 * is shared and in use by other drivers.
2530 */
2531 rc = regulator_disable(vreg->reg);
2532 if (rc) {
2533 pr_err("%s: regulator_disable(%s) failed at " \
2534 "bootup. rc=%d\n", __func__,
2535 vreg->name, rc);
2536 goto out;
2537 }
2538 vreg->is_enabled = false;
2539 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540 }
2541out:
2542 return rc;
2543}
2544
Krishna Konda3c4142d2012-06-27 11:01:56 -07002545static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2546 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547{
2548 int rc = 0, i;
2549 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302550 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551
2552 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302553 if (!curr_slot) {
Asutosh Dasd5902bf2012-10-03 18:28:20 +05302554 pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
2555 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002556 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302557 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558
Subhash Jadavani937c7502012-06-01 15:34:46 +05302559 vreg_table[0] = curr_slot->vdd_data;
2560 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561
2562 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2563 if (vreg_table[i]) {
2564 if (enable)
2565 rc = msmsdcc_vreg_enable(vreg_table[i]);
2566 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002567 rc = msmsdcc_vreg_disable(vreg_table[i],
2568 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569 if (rc)
2570 goto out;
2571 }
2572 }
2573out:
2574 return rc;
2575}
2576
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002577/*
2578 * Reset vreg by ensuring it is off during probe. A call
2579 * to enable vreg is needed to balance disable vreg
2580 */
2581static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2582{
2583 int rc;
2584
Krishna Konda3c4142d2012-06-27 11:01:56 -07002585 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002586 if (rc)
2587 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002588 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002589 return rc;
2590}
2591
Subhash Jadavani937c7502012-06-01 15:34:46 +05302592enum vdd_io_level {
2593 /* set vdd_io_data->low_vol_level */
2594 VDD_IO_LOW,
2595 /* set vdd_io_data->high_vol_level */
2596 VDD_IO_HIGH,
2597 /*
2598 * set whatever there in voltage_level (third argument) of
2599 * msmsdcc_set_vdd_io_vol() function.
2600 */
2601 VDD_IO_SET_LEVEL,
2602};
2603
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302604/*
2605 * This function returns the current VDD IO voltage level.
2606 * Returns negative value if it fails to read the voltage level
2607 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2608 * regulator were not defined for host.
2609 */
2610static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2611{
2612 int rc = 0;
2613
2614 if (host->plat->vreg_data) {
2615 struct msm_mmc_reg_data *io_reg =
2616 host->plat->vreg_data->vdd_io_data;
2617
2618 /*
2619 * If vdd_io is not defined, then we can consider that
2620 * IO voltage is same as VDD.
2621 */
2622 if (!io_reg)
2623 io_reg = host->plat->vreg_data->vdd_data;
2624
2625 if (io_reg && io_reg->is_enabled)
2626 rc = msmsdcc_vreg_get_voltage(io_reg);
2627 }
2628
2629 return rc;
2630}
2631
2632/*
2633 * This function updates the IO pad power switch bit in MCI_CLK register
2634 * based on currrent IO pad voltage level.
2635 * NOTE: This function assumes that host lock was not taken by caller.
2636 */
2637static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2638{
2639 int rc = 0;
2640 unsigned long flags;
2641
2642 if (!is_io_pad_pwr_switch(host))
2643 return;
2644
2645 rc = msmsdcc_get_vdd_io_vol(host);
2646
2647 spin_lock_irqsave(&host->lock, flags);
2648 /*
2649 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2650 * the SDCC instances support the dual voltage pads.
2651 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2652 * bit before using the pads in 1.8V mode.
2653 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2654 * IO_PAD_PWR_SWITCH bit is a don't care.
2655 * But we don't have an option to know (by reading some SDCC register)
2656 * that a particular SDCC instance supports dual voltage pads or not,
2657 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2658 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2659 * is anyway ignored.
2660 */
2661 if (rc > 0 && rc < 2700000)
2662 host->io_pad_pwr_switch = 1;
2663 else
2664 host->io_pad_pwr_switch = 0;
2665
2666 if (atomic_read(&host->clks_on)) {
2667 if (host->io_pad_pwr_switch)
2668 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2669 IO_PAD_PWR_SWITCH),
2670 host->base + MMCICLOCK);
2671 else
2672 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2673 ~IO_PAD_PWR_SWITCH),
2674 host->base + MMCICLOCK);
2675 msmsdcc_sync_reg_wr(host);
2676 }
2677 spin_unlock_irqrestore(&host->lock, flags);
2678}
2679
Subhash Jadavani937c7502012-06-01 15:34:46 +05302680static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2681 enum vdd_io_level level,
2682 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683{
2684 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302685 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686
2687 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302688 struct msm_mmc_reg_data *vdd_io_reg =
2689 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690
Subhash Jadavani937c7502012-06-01 15:34:46 +05302691 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2692 switch (level) {
2693 case VDD_IO_LOW:
2694 set_level = vdd_io_reg->low_vol_level;
2695 break;
2696 case VDD_IO_HIGH:
2697 set_level = vdd_io_reg->high_vol_level;
2698 break;
2699 case VDD_IO_SET_LEVEL:
2700 set_level = voltage_level;
2701 break;
2702 default:
2703 pr_err("%s: %s: invalid argument level = %d",
2704 mmc_hostname(host->mmc), __func__,
2705 level);
2706 rc = -EINVAL;
2707 goto out;
2708 }
2709 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2710 set_level, set_level);
2711 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 }
2713
Subhash Jadavani937c7502012-06-01 15:34:46 +05302714out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302715 return rc;
2716}
2717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002718static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2719{
2720 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2721 return 1;
2722 return 0;
2723}
2724
Asutosh Dasf5298c32012-04-03 14:51:47 +05302725/*
2726 * Any function calling msmsdcc_setup_clocks must
2727 * acquire clk_mutex. May sleep.
2728 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302729static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002730{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302731 int rc = 0;
2732
2733 if (enable && !atomic_read(&host->clks_on)) {
2734 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2735 rc = clk_prepare_enable(host->bus_clk);
2736 if (rc) {
2737 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2738 mmc_hostname(host->mmc), __func__, rc);
2739 goto out;
2740 }
2741 }
2742 if (!IS_ERR(host->pclk)) {
2743 rc = clk_prepare_enable(host->pclk);
2744 if (rc) {
2745 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2746 mmc_hostname(host->mmc), __func__, rc);
2747 goto disable_bus;
2748 }
2749 }
2750 rc = clk_prepare_enable(host->clk);
2751 if (rc) {
2752 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2753 mmc_hostname(host->mmc), __func__, rc);
2754 goto disable_pclk;
2755 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302756 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302757 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302758 atomic_set(&host->clks_on, 1);
2759 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302760 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302761 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302762 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302764 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302765 if (!IS_ERR_OR_NULL(host->bus_clk))
2766 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302767 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002768 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302769 goto out;
2770
2771disable_pclk:
2772 if (!IS_ERR_OR_NULL(host->pclk))
2773 clk_disable_unprepare(host->pclk);
2774disable_bus:
2775 if (!IS_ERR_OR_NULL(host->bus_clk))
2776 clk_disable_unprepare(host->bus_clk);
2777out:
2778 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779}
2780
2781static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2782 unsigned int req_clk)
2783{
2784 unsigned int sel_clk = -1;
2785
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302786 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2787 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2788 goto out;
2789 }
2790
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002791 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2792 unsigned char cnt;
2793
2794 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2795 if (host->plat->sup_clk_table[cnt] > req_clk)
2796 break;
2797 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2798 sel_clk = host->plat->sup_clk_table[cnt];
2799 break;
2800 } else
2801 sel_clk = host->plat->sup_clk_table[cnt];
2802 }
2803 } else {
2804 if ((req_clk < host->plat->msmsdcc_fmax) &&
2805 (req_clk > host->plat->msmsdcc_fmid))
2806 sel_clk = host->plat->msmsdcc_fmid;
2807 else
2808 sel_clk = req_clk;
2809 }
2810
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302811out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 return sel_clk;
2813}
2814
2815static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2816 struct msmsdcc_host *host)
2817{
2818 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2819 return host->plat->sup_clk_table[0];
2820 else
2821 return host->plat->msmsdcc_fmin;
2822}
2823
2824static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2825 struct msmsdcc_host *host)
2826{
2827 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2828 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2829 else
2830 return host->plat->msmsdcc_fmax;
2831}
2832
2833static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302834{
2835 struct msm_mmc_gpio_data *curr;
2836 int i, rc = 0;
2837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302839 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302840 if (!gpio_is_valid(curr->gpio[i].no)) {
2841 rc = -EINVAL;
2842 pr_err("%s: Invalid gpio = %d\n",
2843 mmc_hostname(host->mmc), curr->gpio[i].no);
2844 goto free_gpios;
2845 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302846 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847 if (curr->gpio[i].is_always_on &&
2848 curr->gpio[i].is_enabled)
2849 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302850 rc = gpio_request(curr->gpio[i].no,
2851 curr->gpio[i].name);
2852 if (rc) {
2853 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2854 mmc_hostname(host->mmc),
2855 curr->gpio[i].no,
2856 curr->gpio[i].name, rc);
2857 goto free_gpios;
2858 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002859 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302860 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861 if (curr->gpio[i].is_always_on)
2862 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302863 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002864 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302865 }
2866 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302868
2869free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302870 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302871 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872 curr->gpio[i].is_enabled = false;
2873 }
2874out:
2875 return rc;
2876}
2877
2878static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2879{
2880 struct msm_mmc_pad_data *curr;
2881 int i;
2882
2883 curr = host->plat->pin_data->pad_data;
2884 for (i = 0; i < curr->drv->size; i++) {
2885 if (enable)
2886 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2887 curr->drv->on[i].val);
2888 else
2889 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2890 curr->drv->off[i].val);
2891 }
2892
2893 for (i = 0; i < curr->pull->size; i++) {
2894 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002895 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002896 curr->pull->on[i].val);
2897 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002898 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899 curr->pull->off[i].val);
2900 }
2901
2902 return 0;
2903}
2904
2905static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2906{
2907 int rc = 0;
2908
2909 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2910 return 0;
2911
2912 if (host->plat->pin_data->is_gpio)
2913 rc = msmsdcc_setup_gpio(host, enable);
2914 else
2915 rc = msmsdcc_setup_pad(host, enable);
2916
2917 if (!rc)
2918 host->plat->pin_data->cfg_sts = enable;
2919
2920 return rc;
2921}
2922
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302923static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2924 unsigned mode)
2925{
2926 int ret = 0;
2927 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2928
2929 if (!pin)
2930 return 0;
2931
2932 switch (mode) {
2933 case SDC_DAT1_DISABLE:
2934 ret = msm_mpm_enable_pin(pin, 0);
2935 break;
2936 case SDC_DAT1_ENABLE:
2937 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2938 ret = msm_mpm_enable_pin(pin, 1);
2939 break;
2940 case SDC_DAT1_ENWAKE:
2941 ret = msm_mpm_set_pin_wake(pin, 1);
2942 break;
2943 case SDC_DAT1_DISWAKE:
2944 ret = msm_mpm_set_pin_wake(pin, 0);
2945 break;
2946 default:
2947 ret = -EINVAL;
2948 break;
2949 }
2950
2951 return ret;
2952}
2953
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302954static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2955{
2956 u32 pwr = 0;
2957 int ret = 0;
2958 struct mmc_host *mmc = host->mmc;
2959
2960 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2961 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2962 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002963 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302964
2965 if (ret) {
2966 pr_err("%s: Failed to setup voltage regulators\n",
2967 mmc_hostname(host->mmc));
2968 goto out;
2969 }
2970
2971 switch (ios->power_mode) {
2972 case MMC_POWER_OFF:
2973 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302974 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302975 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302976 * If VDD IO rail is always on, set low voltage for VDD
2977 * IO rail when slot is not in use (like when card is not
2978 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302979 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302980 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302981 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302982 msmsdcc_setup_pins(host, false);
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05302983 /*
2984 * Reset the mask to prevent hitting any pending interrupts
2985 * after powering up the card again.
2986 */
2987 if (atomic_read(&host->clks_on)) {
2988 writel_relaxed(0, host->base + MMCIMASK0);
2989 mb();
2990 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302991 break;
2992 case MMC_POWER_UP:
2993 /* writing PWR_UP bit is redundant */
2994 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302995 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302996
Subhash Jadavani937c7502012-06-01 15:34:46 +05302997 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302998 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302999 msmsdcc_setup_pins(host, true);
3000 break;
3001 case MMC_POWER_ON:
3002 pwr = MCI_PWR_ON;
3003 break;
3004 }
3005
3006out:
3007 return pwr;
3008}
3009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003010static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
3011{
3012 unsigned int wakeup_irq;
3013
3014 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3015 host->plat->sdiowakeup_irq :
3016 host->core_irqres->start;
3017
3018 if (!host->irq_wake_enabled) {
3019 enable_irq_wake(wakeup_irq);
3020 host->irq_wake_enabled = true;
3021 }
3022}
3023
3024static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
3025{
3026 unsigned int wakeup_irq;
3027
3028 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3029 host->plat->sdiowakeup_irq :
3030 host->core_irqres->start;
3031
3032 if (host->irq_wake_enabled) {
3033 disable_irq_wake(wakeup_irq);
3034 host->irq_wake_enabled = false;
3035 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05303036}
3037
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303038/* Returns required bandwidth in Bytes per Sec */
3039static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
3040 struct mmc_ios *ios)
3041{
3042 unsigned int bw;
3043
3044 bw = host->clk_rate;
3045 /*
3046 * For DDR mode, SDCC controller clock will be at
3047 * the double rate than the actual clock that goes to card.
3048 */
3049 if (ios->bus_width == MMC_BUS_WIDTH_4)
3050 bw /= 2;
3051 else if (ios->bus_width == MMC_BUS_WIDTH_1)
3052 bw /= 8;
3053
3054 return bw;
3055}
3056
3057static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
3058 unsigned int bw)
3059{
3060 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
3061 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
3062 int i;
3063
3064 if (host->msm_bus_vote.is_max_bw_needed && bw)
3065 return host->msm_bus_vote.max_bw_vote;
3066
3067 for (i = 0; i < size; i++) {
3068 if (bw <= table[i])
3069 break;
3070 }
3071
3072 if (i && (i == size))
3073 i--;
3074
3075 return i;
3076}
3077
3078static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
3079{
3080 int rc = 0;
3081 struct msm_bus_scale_pdata *use_cases;
3082
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303083 if (host->pdev->dev.of_node) {
3084 struct msm_mmc_bus_voting_data *data;
3085 struct device *dev = &host->pdev->dev;
3086
3087 data = devm_kzalloc(dev,
3088 sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
3089 if (!data) {
3090 dev_err(&host->pdev->dev,
3091 "%s: failed to allocate memory\n", __func__);
3092 rc = -ENOMEM;
3093 goto out;
3094 }
3095
3096 rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
3097 &data->bw_vecs, &data->bw_vecs_size, 0);
3098 if (!rc) {
3099 data->use_cases = msm_bus_cl_get_pdata(host->pdev);
3100 host->plat->msm_bus_voting_data = data;
3101 }
3102 }
3103
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303104 if (host->plat->msm_bus_voting_data &&
3105 host->plat->msm_bus_voting_data->use_cases &&
3106 host->plat->msm_bus_voting_data->bw_vecs &&
3107 host->plat->msm_bus_voting_data->bw_vecs_size) {
3108 use_cases = host->plat->msm_bus_voting_data->use_cases;
3109 host->msm_bus_vote.client_handle =
3110 msm_bus_scale_register_client(use_cases);
3111 } else {
3112 return 0;
3113 }
3114
3115 if (!host->msm_bus_vote.client_handle) {
3116 pr_err("%s: msm_bus_scale_register_client() failed\n",
3117 mmc_hostname(host->mmc));
3118 rc = -EFAULT;
3119 } else {
3120 /* cache the vote index for minimum and maximum bandwidth */
3121 host->msm_bus_vote.min_bw_vote =
3122 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3123 host->msm_bus_vote.max_bw_vote =
3124 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3125 }
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303126out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303127 return rc;
3128}
3129
3130static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3131{
3132 if (host->msm_bus_vote.client_handle)
3133 msm_bus_scale_unregister_client(
3134 host->msm_bus_vote.client_handle);
3135}
3136
3137/*
3138 * This function must be called with host lock acquired.
3139 * Caller of this function should also ensure that msm bus client
3140 * handle is not null.
3141 */
3142static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3143 int vote,
3144 unsigned long flags)
3145{
3146 int rc = 0;
3147
3148 if (vote != host->msm_bus_vote.curr_vote) {
3149 spin_unlock_irqrestore(&host->lock, flags);
3150 rc = msm_bus_scale_client_update_request(
3151 host->msm_bus_vote.client_handle, vote);
3152 if (rc)
3153 pr_err("%s: msm_bus_scale_client_update_request() failed."
3154 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3155 mmc_hostname(host->mmc),
3156 host->msm_bus_vote.client_handle, vote, rc);
3157 spin_lock_irqsave(&host->lock, flags);
3158 if (!rc)
3159 host->msm_bus_vote.curr_vote = vote;
3160 }
3161
3162 return rc;
3163}
3164
3165/*
3166 * Internal work. Work to set 0 bandwidth for msm bus.
3167 */
3168static void msmsdcc_msm_bus_work(struct work_struct *work)
3169{
3170 struct msmsdcc_host *host = container_of(work,
3171 struct msmsdcc_host,
3172 msm_bus_vote.vote_work.work);
3173 unsigned long flags;
3174
3175 if (!host->msm_bus_vote.client_handle)
3176 return;
3177
3178 spin_lock_irqsave(&host->lock, flags);
3179 /* don't vote for 0 bandwidth if any request is in progress */
3180 if (!host->curr.mrq)
3181 msmsdcc_msm_bus_set_vote(host,
3182 host->msm_bus_vote.min_bw_vote, flags);
3183 else
3184 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3185 " bus voting to 0 bandwidth\n",
3186 mmc_hostname(host->mmc), __func__);
3187 spin_unlock_irqrestore(&host->lock, flags);
3188}
3189
3190/*
3191 * This function cancels any scheduled delayed work
3192 * and sets the bus vote based on ios argument.
3193 * If "ios" argument is NULL, bandwidth required is 0 else
3194 * calculate the bandwidth based on ios parameters.
3195 */
3196static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3197 struct msmsdcc_host *host,
3198 struct mmc_ios *ios)
3199{
3200 unsigned long flags;
3201 unsigned int bw;
3202 int vote;
3203
3204 if (!host->msm_bus_vote.client_handle)
3205 return;
3206
3207 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3208
3209 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3210 spin_lock_irqsave(&host->lock, flags);
3211 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3212 msmsdcc_msm_bus_set_vote(host, vote, flags);
3213 spin_unlock_irqrestore(&host->lock, flags);
3214}
3215
3216/* This function queues a work which will set the bandwidth requiement to 0 */
3217static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3218{
3219 unsigned long flags;
3220
3221 if (!host->msm_bus_vote.client_handle)
3222 return;
3223
3224 spin_lock_irqsave(&host->lock, flags);
3225 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3226 queue_delayed_work(system_nrt_wq,
3227 &host->msm_bus_vote.vote_work,
3228 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3229 spin_unlock_irqrestore(&host->lock, flags);
3230}
3231
San Mehat9d2bd732009-09-22 16:44:22 -07003232static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303233msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3234{
3235 struct mmc_host *mmc = host->mmc;
3236
3237 /*
3238 * SDIO_AL clients has different mechanism of handling LPM through
3239 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3240 * part of that. Here, we are interested only in clients like WLAN.
3241 */
3242 if (!(mmc->card && mmc_card_sdio(mmc->card))
3243 || host->plat->is_sdio_al_client)
3244 goto out;
3245
3246 if (!host->sdcc_suspended) {
3247 /*
3248 * When MSM is not in power collapse and we
3249 * are disabling clocks, enable bit 22 in MASK0
3250 * to handle asynchronous SDIO interrupts.
3251 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303252 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303253 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303254 mb();
3255 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303256 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303257 msmsdcc_sync_reg_wr(host);
3258 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303259 goto out;
3260 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3261 /*
3262 * Wakeup MSM only if SDIO function drivers set
3263 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3264 */
3265 goto out;
3266 }
3267
3268 if (enable_wakeup_irq) {
3269 if (!host->plat->sdiowakeup_irq) {
3270 /*
3271 * When there is no gpio line that can be configured
3272 * as wakeup interrupt handle it by configuring
3273 * asynchronous sdio interrupts and DAT1 line.
3274 */
3275 writel_relaxed(MCI_SDIOINTMASK,
3276 host->base + MMCIMASK0);
3277 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303278 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303279 /* configure sdcc core interrupt as wakeup interrupt */
3280 msmsdcc_enable_irq_wake(host);
3281 } else {
3282 /* Let gpio line handle wakeup interrupt */
3283 writel_relaxed(0, host->base + MMCIMASK0);
3284 mb();
3285 if (host->sdio_wakeupirq_disabled) {
3286 host->sdio_wakeupirq_disabled = 0;
3287 /* configure gpio line as wakeup interrupt */
3288 msmsdcc_enable_irq_wake(host);
3289 enable_irq(host->plat->sdiowakeup_irq);
3290 }
3291 }
3292 } else {
3293 if (!host->plat->sdiowakeup_irq) {
3294 /*
3295 * We may not have cleared bit 22 in the interrupt
3296 * handler as the clocks might be off at that time.
3297 */
3298 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303299 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303300 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303301 msmsdcc_disable_irq_wake(host);
3302 } else if (!host->sdio_wakeupirq_disabled) {
3303 disable_irq_nosync(host->plat->sdiowakeup_irq);
3304 msmsdcc_disable_irq_wake(host);
3305 host->sdio_wakeupirq_disabled = 1;
3306 }
3307 }
3308out:
3309 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003310}
3311
3312static void
3313msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3314{
3315 struct msmsdcc_host *host = mmc_priv(mmc);
3316 u32 clk = 0, pwr = 0;
3317 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003318 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003319 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003320
Sahitya Tummala7a892482011-01-18 11:22:49 +05303321
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303322 /*
3323 * Disable SDCC core interrupt until set_ios is completed.
3324 * This avoids any race conditions with interrupt raised
3325 * when turning on/off the clocks. One possible
3326 * scenario is SDIO operational interrupt while the clock
3327 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303328 * host->lock is being released intermittently below.
3329 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303330 */
3331
Asutosh Dasf5298c32012-04-03 14:51:47 +05303332 mutex_lock(&host->clk_mutex);
3333 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003334 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303335 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303336 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303337 host->sdcc_irq_disabled = 1;
3338 }
San Mehatd0719e52009-12-03 10:58:54 -08003339 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003340
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303341 /* Make sure sdcc core irq is synchronized */
3342 synchronize_irq(host->core_irqres->start);
3343
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303344 pwr = msmsdcc_setup_pwr(host, ios);
3345
3346 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003347 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303348 spin_unlock_irqrestore(&host->lock, flags);
3349 rc = msmsdcc_setup_clocks(host, true);
3350 if (rc)
3351 goto out;
3352 spin_lock_irqsave(&host->lock, flags);
3353 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3354 mb();
3355 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003356 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 /*
3359 * For DDR50 mode, controller needs clock rate to be
3360 * double than what is required on the SD card CLK pin.
Subhash Jadavani2877d912012-10-09 20:01:56 +05303361 *
3362 * Setting DDR timing mode in controller before setting the
3363 * clock rate will make sure that card don't see the double
3364 * clock rate even for very small duration. Some eMMC
3365 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003366 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303367 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2877d912012-10-09 20:01:56 +05303368 u32 clk;
3369
3370 clk = readl_relaxed(host->base + MMCICLOCK);
3371 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3372 clk |= (3 << 14); /* set DDR timing mode */
3373 writel_relaxed(clk, host->base + MMCICLOCK);
3374 msmsdcc_sync_reg_wr(host);
3375
Subhash Jadavani879856d2013-03-04 16:28:04 +05303376 clock = msmsdcc_get_sup_clk_rate(host, ios->clock * 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 }
3378
3379 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303380 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003381 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303382 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303384 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385 mmc_hostname(mmc), clock);
3386 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303387 host->reg_write_delay =
3388 (1 + ((3 * USEC_PER_SEC) /
3389 (host->clk_rate ? host->clk_rate :
3390 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391 }
3392 /*
3393 * give atleast 2 MCLK cycles delay for clocks
3394 * and SDCC core to stabilize
3395 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303396 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003398 clk |= MCI_CLK_ENABLE;
3399 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 if (ios->bus_width == MMC_BUS_WIDTH_8)
3401 clk |= MCI_CLK_WIDEBUS_8;
3402 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3403 clk |= MCI_CLK_WIDEBUS_4;
3404 else
3405 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003407 if (msmsdcc_is_pwrsave(host))
3408 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003411
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003412 host->tuning_needed = 0;
3413 /*
3414 * Select the controller timing mode according
3415 * to current bus speed mode
3416 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303417 if (host->clk_rate > (100 * 1000 * 1000) &&
3418 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3419 ios->timing == MMC_TIMING_MMC_HS200)) {
3420 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003421 clk |= (4 << 14);
3422 host->tuning_needed = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 } else {
Subhash Jadavani355df542012-10-09 19:06:49 +05303424 if (ios->timing == MMC_TIMING_UHS_DDR50)
3425 clk |= (3 << 14);
3426 else
3427 clk |= (2 << 14); /* feedback clock */
3428
3429 host->tuning_done = false;
3430 if (atomic_read(&host->clks_on)) {
3431 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3432 writel_relaxed((readl_relaxed(host->base +
3433 MCI_DLL_CONFIG) | MCI_DLL_RST),
3434 host->base + MCI_DLL_CONFIG);
3435
3436 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3437 writel_relaxed((readl_relaxed(host->base +
3438 MCI_DLL_CONFIG) | MCI_DLL_PDN),
3439 host->base + MCI_DLL_CONFIG);
3440 }
San Mehat9d2bd732009-09-22 16:44:22 -07003441 }
3442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3444 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446 if (host->io_pad_pwr_switch)
3447 clk |= IO_PAD_PWR_SWITCH;
3448
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303449 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303450 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303451 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3452 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303453 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003454 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303455 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3456 host->pwr = pwr;
3457 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303458 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003459 }
San Mehat9d2bd732009-09-22 16:44:22 -07003460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303462 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303463 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303464 spin_unlock_irqrestore(&host->lock, flags);
3465 /*
3466 * May get a wake-up interrupt the instant we disable the
3467 * clocks. This would disable the wake-up interrupt.
3468 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303470 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303472
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303473 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303474 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303475 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303476
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303477 /* Let interrupts be disabled if the host is powered off */
3478 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3479 enable_irq(host->core_irqres->start);
3480 host->sdcc_irq_disabled = 0;
3481 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003482 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303483out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303484 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003485}
3486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3488{
3489 struct msmsdcc_host *host = mmc_priv(mmc);
3490 u32 clk;
3491
3492 clk = readl_relaxed(host->base + MMCICLOCK);
3493 pr_debug("Changing to pwr_save=%d", pwrsave);
3494 if (pwrsave && msmsdcc_is_pwrsave(host))
3495 clk |= MCI_CLK_PWRSAVE;
3496 else
3497 clk &= ~MCI_CLK_PWRSAVE;
3498 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303499 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500
3501 return 0;
3502}
3503
3504static int msmsdcc_get_ro(struct mmc_host *mmc)
3505{
3506 int status = -ENOSYS;
3507 struct msmsdcc_host *host = mmc_priv(mmc);
3508
3509 if (host->plat->wpswitch) {
3510 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303511 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003512 status = gpio_request(host->plat->wpswitch_gpio,
3513 "SD_WP_Switch");
3514 if (status) {
3515 pr_err("%s: %s: Failed to request GPIO %d\n",
3516 mmc_hostname(mmc), __func__,
3517 host->plat->wpswitch_gpio);
3518 } else {
3519 status = gpio_direction_input(
3520 host->plat->wpswitch_gpio);
3521 if (!status) {
3522 /*
3523 * Wait for atleast 300ms as debounce
3524 * time for GPIO input to stabilize.
3525 */
3526 msleep(300);
3527 status = gpio_get_value_cansleep(
3528 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303529 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 }
3531 gpio_free(host->plat->wpswitch_gpio);
3532 }
3533 }
3534
3535 if (status < 0)
3536 status = -ENOSYS;
3537 pr_debug("%s: Card read-only status %d\n", __func__, status);
3538
3539 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003540}
3541
3542static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3543{
3544 struct msmsdcc_host *host = mmc_priv(mmc);
3545 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003546
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303547 /*
3548 * We may come here with clocks turned off in that case don't
3549 * attempt to write into MASK0 register. While turning on the
3550 * clocks mci_irqenable will be written to MASK0 register.
3551 */
San Mehat9d2bd732009-09-22 16:44:22 -07003552
3553 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003555 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 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561 } else {
3562 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303563 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303564 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303566 mb();
3567 }
San Mehat9d2bd732009-09-22 16:44:22 -07003568 }
3569 spin_unlock_irqrestore(&host->lock, flags);
3570}
3571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303573static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003574{
subhashj245831e2012-04-30 18:46:17 +05303575 struct device *dev = mmc_dev(host->mmc);
3576
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303577 pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
Subhash Jadavani386ad802012-08-16 18:46:57 +05303578 mmc_hostname(host->mmc), host->sdcc_suspended,
3579 host->pending_resume, host->sdcc_suspending);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303580 pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
subhashj245831e2012-04-30 18:46:17 +05303581 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3582 " request_pending=%d, request=%d\n",
3583 mmc_hostname(host->mmc), dev->power.runtime_status,
3584 atomic_read(&dev->power.usage_count),
3585 dev->power.is_suspended, dev->power.disable_depth,
3586 dev->power.runtime_error, dev->power.request_pending,
3587 dev->power.request);
3588}
3589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003590static int msmsdcc_enable(struct mmc_host *mmc)
3591{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003592 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003594 struct msmsdcc_host *host = mmc_priv(mmc);
3595
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303596 msmsdcc_pm_qos_update_latency(host, 1);
3597
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003598 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303599 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600
Subhash Jadavani386ad802012-08-16 18:46:57 +05303601 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003602 host->pending_resume = false;
3603 pm_runtime_get_noresume(dev);
3604 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303605 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003606 }
3607
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303608 if (dev->power.runtime_status == RPM_SUSPENDING) {
3609 if (mmc->suspend_task == current) {
3610 pm_runtime_get_noresume(dev);
3611 goto out;
3612 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303613 } else if (dev->power.runtime_status == RPM_RESUMING) {
3614 pm_runtime_get_noresume(dev);
3615 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303616 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003617
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303618 rc = pm_runtime_get_sync(dev);
3619
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303620skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303621 if (rc < 0) {
Subhash Jadavani386ad802012-08-16 18:46:57 +05303622 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3623 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303624 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303625 return rc;
3626 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303627out:
3628 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303629 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003630}
3631
Steve Mucklef132c6c2012-06-06 18:30:57 -07003632static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003633{
3634 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303635 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303637 msmsdcc_pm_qos_update_latency(host, 0);
3638
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303639 if (mmc->card && mmc_card_sdio(mmc->card)) {
3640 rc = 0;
3641 goto out;
3642 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303643
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303644 if (host->plat->disable_runtime_pm)
3645 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646
3647 rc = pm_runtime_put_sync(mmc->parent);
3648
Subhash Jadavani386ad802012-08-16 18:46:57 +05303649 if (rc < 0) {
3650 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3651 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303652 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003653 return rc;
3654 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303655
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303656out:
3657 msmsdcc_msm_bus_queue_work(host);
3658 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659}
3660#else
subhashj245831e2012-04-30 18:46:17 +05303661static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3662
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303663static int msmsdcc_enable(struct mmc_host *mmc)
3664{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003665 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303666 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303667 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303668
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303669 msmsdcc_pm_qos_update_latency(host, 1);
3670
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303671 if (mmc->card && mmc_card_sdio(mmc->card)) {
3672 rc = 0;
3673 goto out;
3674 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003675
3676 if (host->sdcc_suspended && host->pending_resume) {
3677 host->pending_resume = false;
3678 rc = msmsdcc_runtime_resume(dev);
3679 goto out;
3680 }
3681
Asutosh Dasf5298c32012-04-03 14:51:47 +05303682 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303683 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303684 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303685
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003686out:
3687 if (rc < 0) {
3688 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3689 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303690 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003691 return rc;
3692 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303693 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303694 return 0;
3695}
3696
Steve Mucklef132c6c2012-06-06 18:30:57 -07003697static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303698{
3699 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303700 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303701
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303702 msmsdcc_pm_qos_update_latency(host, 0);
3703
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303704 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303705 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303706
Asutosh Dasf5298c32012-04-03 14:51:47 +05303707 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303708 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303709 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303710
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303711 if (rc) {
3712 msmsdcc_pm_qos_update_latency(host, 1);
3713 return rc;
3714 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303715out:
3716 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303717 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303718}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003719#endif
3720
Subhash Jadavani937c7502012-06-01 15:34:46 +05303721static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3722 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003723{
3724 struct msmsdcc_host *host = mmc_priv(mmc);
3725 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303726 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003727
Subhash Jadavani937c7502012-06-01 15:34:46 +05303728 switch (ios->signal_voltage) {
3729 case MMC_SIGNAL_VOLTAGE_330:
3730 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3731 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303732 if (!rc)
3733 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303734 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303735 case MMC_SIGNAL_VOLTAGE_180:
3736 break;
3737 case MMC_SIGNAL_VOLTAGE_120:
3738 /*
3739 * For eMMC cards, VDD_IO voltage range must be changed
3740 * only if it operates in HS200 SDR 1.2V mode or in
3741 * DDR 1.2V mode.
3742 */
3743 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303744 if (!rc)
3745 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003746 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303747 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303749 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 goto out;
3751 }
San Mehat9d2bd732009-09-22 16:44:22 -07003752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003753 /*
3754 * If we are here means voltage switch from high voltage to
3755 * low voltage is required
3756 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303757 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003758
3759 /*
3760 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3761 * register until they become all zeros.
3762 */
3763 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303764 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3766 mmc_hostname(mmc), __func__);
3767 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003768 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769
3770 /* Stop SD CLK output. */
3771 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3772 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303773 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003774 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775
3776 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303777 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3778 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303780 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303781 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003782 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003783
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303784 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785
3786 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3787 usleep_range(5000, 5500);
3788
3789 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303790 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3792 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303793 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003794 spin_unlock_irqrestore(&host->lock, flags);
3795
3796 /*
3797 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3798 * don't become all ones within 1 ms then a Voltage Switch
3799 * sequence has failed and a power cycle to the card is required.
3800 * Otherwise Voltage Switch sequence is completed successfully.
3801 */
3802 usleep_range(1000, 1500);
3803
3804 spin_lock_irqsave(&host->lock, flags);
3805 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3806 != (0xF << 1)) {
3807 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3808 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303809 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 goto out_unlock;
3811 }
3812
3813out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303814 /* Enable PWRSAVE */
3815 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3816 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303817 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 spin_unlock_irqrestore(&host->lock, flags);
3819out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303820 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821}
3822
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303823static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003826
3827 /* Program the MCLK value to MCLK_FREQ bit field */
3828 if (host->clk_rate <= 112000000)
3829 mclk_freq = 0;
3830 else if (host->clk_rate <= 125000000)
3831 mclk_freq = 1;
3832 else if (host->clk_rate <= 137000000)
3833 mclk_freq = 2;
3834 else if (host->clk_rate <= 150000000)
3835 mclk_freq = 3;
3836 else if (host->clk_rate <= 162000000)
3837 mclk_freq = 4;
3838 else if (host->clk_rate <= 175000000)
3839 mclk_freq = 5;
3840 else if (host->clk_rate <= 187000000)
3841 mclk_freq = 6;
3842 else if (host->clk_rate <= 200000000)
3843 mclk_freq = 7;
3844
3845 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3846 & ~(7 << 24)) | (mclk_freq << 24)),
3847 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848}
3849
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303850/* Initialize the DLL (Programmable Delay Line ) */
3851static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003853 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303854 unsigned long flags;
3855 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303857 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 /*
3859 * Make sure that clock is always enabled when DLL
3860 * tuning is in progress. Keeping PWRSAVE ON may
3861 * turn off the clock. So let's disable the PWRSAVE
3862 * here and re-enable it once tuning is completed.
3863 */
3864 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3865 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303866 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303867
3868 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3869 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3870 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3871
3872 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3873 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3874 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3875
3876 msmsdcc_cm_sdc4_dll_set_freq(host);
3877
3878 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3879 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3880 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3881
3882 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3883 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3884 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3885
3886 /* Set DLL_EN bit to 1. */
3887 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3888 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3889
3890 /* Set CK_OUT_EN bit to 1. */
3891 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3892 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3893
3894 wait_cnt = 50;
3895 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3896 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3897 /* max. wait for 50us sec for LOCK bit to be set */
3898 if (--wait_cnt == 0) {
3899 pr_err("%s: %s: DLL failed to LOCK\n",
3900 mmc_hostname(host->mmc), __func__);
3901 rc = -ETIMEDOUT;
3902 goto out;
3903 }
3904 /* wait for 1us before polling again */
3905 udelay(1);
3906 }
3907
3908out:
3909 /* re-enable PWRSAVE */
3910 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3911 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303912 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303913 spin_unlock_irqrestore(&host->lock, flags);
3914
3915 return rc;
3916}
3917
3918static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3919 u8 poll)
3920{
3921 int rc = 0;
3922 u32 wait_cnt = 50;
3923 u8 ck_out_en = 0;
3924
3925 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3926 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3927 MCI_CK_OUT_EN);
3928
3929 while (ck_out_en != poll) {
3930 if (--wait_cnt == 0) {
3931 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3932 mmc_hostname(host->mmc), __func__, poll);
3933 rc = -ETIMEDOUT;
3934 goto out;
3935 }
3936 udelay(1);
3937
3938 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3939 MCI_CK_OUT_EN);
3940 }
3941out:
3942 return rc;
3943}
3944
3945/*
3946 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3947 * calibration sequence. This function should be called before
3948 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3949 * commands (CMD17/CMD18).
3950 *
3951 * This function gets called when host spinlock acquired.
3952 */
3953static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3954{
3955 int rc = 0;
3956 u32 config;
3957
3958 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3959 config |= MCI_CDR_EN;
3960 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3961 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3962
3963 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3964 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3965 if (rc)
3966 goto err_out;
3967
3968 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3969 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3970 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3971
3972 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3973 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3974 if (rc)
3975 goto err_out;
3976
3977 goto out;
3978
3979err_out:
3980 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3981out:
3982 return rc;
3983}
3984
3985static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3986 u8 phase)
3987{
3988 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303989 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3990 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3991 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303992 unsigned long flags;
3993 u32 config;
3994
3995 spin_lock_irqsave(&host->lock, flags);
3996
3997 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3998 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3999 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
4000 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4001
4002 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
4003 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
4004 if (rc)
4005 goto err_out;
4006
4007 /*
4008 * Write the selected DLL clock output phase (0 ... 15)
4009 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
4010 */
4011 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
4012 & ~(0xF << 20))
4013 | (grey_coded_phase_table[phase] << 20)),
4014 host->base + MCI_DLL_CONFIG);
4015
4016 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4017 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4018 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4019
4020 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4021 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4022 if (rc)
4023 goto err_out;
4024
4025 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4026 config |= MCI_CDR_EN;
4027 config &= ~MCI_CDR_EXT_EN;
4028 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4029 goto out;
4030
4031err_out:
4032 pr_err("%s: %s: Failed to set DLL phase: %d\n",
4033 mmc_hostname(host->mmc), __func__, phase);
4034out:
4035 spin_unlock_irqrestore(&host->lock, flags);
4036 return rc;
4037}
4038
4039/*
4040 * Find out the greatest range of consecuitive selected
4041 * DLL clock output phases that can be used as sampling
4042 * setting for SD3.0 UHS-I card read operation (in SDR104
4043 * timing mode) or for eMMC4.5 card read operation (in HS200
4044 * timing mode).
4045 * Select the 3/4 of the range and configure the DLL with the
4046 * selected DLL clock output phase.
4047*/
Subhash Jadavani34187042012-03-02 10:59:49 +05304048static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304049 u8 *phase_table, u8 total_phases)
4050{
Subhash Jadavani6159c622012-03-15 19:05:55 +05304051 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05304052 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05304053 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
4054 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304055 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304056 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
4057 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304058
Subhash Jadavani6159c622012-03-15 19:05:55 +05304059 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304060 pr_err("%s: %s: invalid argument: total_phases=%d\n",
4061 mmc_hostname(host->mmc), __func__, total_phases);
4062 return -EINVAL;
4063 }
4064
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304065 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304066 ranges[row_index][col_index] = phase_table[cnt];
4067 phases_per_row[row_index] += 1;
4068 col_index++;
4069
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304070 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304071 continue;
4072 /* check if next phase in phase_table is consecutive or not */
4073 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
4074 row_index++;
4075 col_index = 0;
4076 }
4077 }
4078
Subhash Jadavani6159c622012-03-15 19:05:55 +05304079 if (row_index >= MAX_PHASES)
4080 return -EINVAL;
4081
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304082 /* Check if phase-0 is present in first valid window? */
4083 if (!ranges[0][0]) {
4084 phase_0_found = true;
4085 phase_0_raw_index = 0;
4086 /* Check if cycle exist between 2 valid windows */
4087 for (cnt = 1; cnt <= row_index; cnt++) {
4088 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05304089 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304090 if (ranges[cnt][i] == 15) {
4091 phase_15_found = true;
4092 phase_15_raw_index = cnt;
4093 break;
4094 }
4095 }
4096 }
4097 }
4098 }
4099
4100 /* If 2 valid windows form cycle then merge them as single window */
4101 if (phase_0_found && phase_15_found) {
4102 /* number of phases in raw where phase 0 is present */
4103 u8 phases_0 = phases_per_row[phase_0_raw_index];
4104 /* number of phases in raw where phase 15 is present */
4105 u8 phases_15 = phases_per_row[phase_15_raw_index];
4106
Subhash Jadavani6159c622012-03-15 19:05:55 +05304107 if (phases_0 + phases_15 >= MAX_PHASES)
4108 /*
4109 * If there are more than 1 phase windows then total
4110 * number of phases in both the windows should not be
4111 * more than or equal to MAX_PHASES.
4112 */
4113 return -EINVAL;
4114
4115 /* Merge 2 cyclic windows */
4116 i = phases_15;
4117 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304118 ranges[phase_15_raw_index][i] =
4119 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304120 if (++i >= MAX_PHASES)
4121 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304122 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304123
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304124 phases_per_row[phase_0_raw_index] = 0;
4125 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4126 }
4127
4128 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304129 if (phases_per_row[cnt] > curr_max) {
4130 curr_max = phases_per_row[cnt];
4131 selected_row_index = cnt;
4132 }
4133 }
4134
Subhash Jadavani6159c622012-03-15 19:05:55 +05304135 i = ((curr_max * 3) / 4);
4136 if (i)
4137 i--;
4138
Subhash Jadavani34187042012-03-02 10:59:49 +05304139 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304140
Subhash Jadavani6159c622012-03-15 19:05:55 +05304141 if (ret >= MAX_PHASES) {
4142 ret = -EINVAL;
4143 pr_err("%s: %s: invalid phase selected=%d\n",
4144 mmc_hostname(host->mmc), __func__, ret);
4145 }
4146
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304147 return ret;
4148}
4149
Girish K Sa3f41692012-02-29 12:00:09 +05304150static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304151{
4152 int rc = 0;
4153 struct msmsdcc_host *host = mmc_priv(mmc);
4154 unsigned long flags;
4155 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304156 const u32 *tuning_block_pattern = tuning_block_64;
4157 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304158 bool is_tuning_all_phases;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304159
4160 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4161
4162 /* Tuning is only required for SDR104 modes */
4163 if (!host->tuning_needed) {
4164 rc = 0;
4165 goto exit;
4166 }
4167
4168 spin_lock_irqsave(&host->lock, flags);
4169 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304170 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304171 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4172
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304173 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304174 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4175 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4176 tuning_block_pattern = tuning_block_128;
4177 size = sizeof(tuning_block_128);
4178 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304179 spin_unlock_irqrestore(&host->lock, flags);
4180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004181 /* first of all reset the tuning block */
4182 rc = msmsdcc_init_cm_sdc4_dll(host);
4183 if (rc)
4184 goto out;
4185
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304186 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 if (!data_buf) {
4188 rc = -ENOMEM;
4189 goto out;
4190 }
4191
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304192 is_tuning_all_phases = !(host->mmc->card &&
4193 (host->saved_tuning_phase != INVALID_TUNING_PHASE));
4194retry:
4195 if (is_tuning_all_phases)
4196 phase = 0; /* start from phase 0 during init */
4197 else
4198 phase = (u8)host->saved_tuning_phase;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199 do {
4200 struct mmc_command cmd = {0};
4201 struct mmc_data data = {0};
4202 struct mmc_request mrq = {
4203 .cmd = &cmd,
4204 .data = &data
4205 };
4206 struct scatterlist sg;
4207
4208 /* set the phase in delay line hw block */
4209 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4210 if (rc)
4211 goto kfree;
4212
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304213 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4215
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304216 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004217 data.blocks = 1;
4218 data.flags = MMC_DATA_READ;
4219 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4220
4221 data.sg = &sg;
4222 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304223 sg_init_one(&sg, data_buf, size);
4224 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225 mmc_wait_for_req(mmc, &mrq);
4226
4227 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304228 !memcmp(data_buf, tuning_block_pattern, size)) {
4229 /* tuning is successful at this tuning point */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304230 if (!is_tuning_all_phases)
4231 goto kfree;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004232 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304233 pr_debug("%s: %s: found good phase = %d\n",
4234 mmc_hostname(mmc), __func__, phase);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304235 } else if (!is_tuning_all_phases) {
4236 pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
4237 mmc_hostname(mmc), (u32)phase);
4238 is_tuning_all_phases = true;
4239 goto retry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004240 }
4241 } while (++phase < 16);
4242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004243 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304244 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304245 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304246 if (rc < 0)
4247 goto kfree;
4248 else
4249 phase = (u8)rc;
4250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 /*
4252 * Finally set the selected phase in delay
4253 * line hw block.
4254 */
4255 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4256 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304257 goto kfree;
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304258 else
4259 host->saved_tuning_phase = phase;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304260 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4261 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004262 } else {
4263 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304264 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004265 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304266 msmsdcc_dump_sdcc_state(host);
4267 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004268 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004269
4270kfree:
4271 kfree(data_buf);
4272out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304273 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304274 host->tuning_in_progress = 0;
Subhash Jadavani355df542012-10-09 19:06:49 +05304275 if (!rc)
4276 host->tuning_done = true;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304277 spin_unlock_irqrestore(&host->lock, flags);
4278exit:
4279 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004280 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004281}
4282
Asutosh Dasebd7d092012-07-09 19:08:26 +05304283/*
4284 * Work around of the unavailability of a power_reset functionality in SD cards
4285 * by turning the OFF & back ON the regulators supplying the SD card.
4286 */
4287void msmsdcc_hw_reset(struct mmc_host *mmc)
4288{
4289 struct mmc_card *card = mmc->card;
4290 struct msmsdcc_host *host = mmc_priv(mmc);
4291 int rc;
4292
4293 /* Write-protection bits would be lost on a hardware reset in emmc */
4294 if (!card || !mmc_card_sd(card))
4295 return;
4296
Pratibhasagar V1aa03dc2012-11-29 12:48:17 +05304297 pr_debug("%s: Starting h/w reset\n", mmc_hostname(host->mmc));
4298
4299 if (host->plat->translate_vdd || host->plat->vreg_data) {
4300
4301 /* Disable the regulators */
4302 if (host->plat->translate_vdd)
4303 rc = host->plat->translate_vdd(mmc_dev(mmc), 0);
4304 else if (host->plat->vreg_data)
4305 rc = msmsdcc_setup_vreg(host, false, false);
4306
4307 if (rc) {
4308 pr_err("%s: Failed to disable voltage regulator\n",
4309 mmc_hostname(host->mmc));
4310 BUG_ON(rc);
4311 }
4312
4313 /* 10ms delay for supply to reach the desired voltage level */
4314 usleep_range(10000, 12000);
4315
4316 /* Enable the regulators */
4317 if (host->plat->translate_vdd)
4318 rc = host->plat->translate_vdd(mmc_dev(mmc), 1);
4319 else if (host->plat->vreg_data)
4320 rc = msmsdcc_setup_vreg(host, true, false);
4321
4322 if (rc) {
4323 pr_err("%s: Failed to enable voltage regulator\n",
4324 mmc_hostname(host->mmc));
4325 BUG_ON(rc);
4326 }
4327
4328 /* 10ms delay for supply to reach the desired voltage level */
4329 usleep_range(10000, 12000);
Asutosh Dasebd7d092012-07-09 19:08:26 +05304330 }
Asutosh Dasebd7d092012-07-09 19:08:26 +05304331}
4332
Subhash Jadavanid076af72013-02-17 23:36:03 +02004333/**
4334 * msmsdcc_stop_request - stops ongoing request
4335 * @mmc: MMC host, running the request
4336 *
4337 * Stops currently running request synchronously. All relevant request
4338 * information is cleared.
4339 */
4340int msmsdcc_stop_request(struct mmc_host *mmc)
4341{
4342 struct msmsdcc_host *host = mmc_priv(mmc);
4343 struct mmc_request *mrq;
4344 unsigned long flags;
4345 int rc = 0;
4346
4347 spin_lock_irqsave(&host->lock, flags);
4348 mrq = host->curr.mrq;
4349 if (mrq) {
4350 msmsdcc_reset_and_restore(host);
4351 /*
4352 * Note: We are just taking care of SPS. We may also
4353 * need to think about ADM (and PIO?) later if required.
4354 */
4355 if (host->sps.sg && is_sps_mode(host)) {
4356 if (!mrq->data->host_cookie)
4357 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
4358 host->sps.num_ents, host->sps.dir);
4359 host->sps.sg = NULL;
4360 host->sps.busy = 0;
4361 }
4362
4363 /*
4364 * Clear current request information as current
4365 * request has ended
4366 */
4367 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
4368 del_timer(&host->req_tout_timer);
4369 } else {
4370 rc = -EINVAL;
4371 }
4372 spin_unlock_irqrestore(&host->lock, flags);
4373
4374 return rc;
4375}
4376
4377/**
4378 * msmsdcc_get_xfer_remain - returns number of bytes passed on bus
4379 * @mmc: MMC host, running the request
4380 *
4381 * Returns the number of bytes passed for SPS transfer. 0 - for non-SPS
4382 * transfer.
4383 */
4384unsigned int msmsdcc_get_xfer_remain(struct mmc_host *mmc)
4385{
4386 struct msmsdcc_host *host = mmc_priv(mmc);
4387 u32 data_cnt = 0;
4388
4389 /* Currently, we don't support to stop the non-SPS transfer */
4390 if (host->sps.busy && atomic_read(&host->clks_on))
4391 data_cnt = readl_relaxed(host->base + MMCIDATACNT);
4392
4393 return data_cnt;
4394}
4395
San Mehat9d2bd732009-09-22 16:44:22 -07004396static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004397 .enable = msmsdcc_enable,
4398 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304399 .pre_req = msmsdcc_pre_req,
4400 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004401 .request = msmsdcc_request,
4402 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004403 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004404 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304405 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304406 .execute_tuning = msmsdcc_execute_tuning,
4407 .hw_reset = msmsdcc_hw_reset,
Subhash Jadavanid076af72013-02-17 23:36:03 +02004408 .stop_request = msmsdcc_stop_request,
4409 .get_xfer_remain = msmsdcc_get_xfer_remain,
San Mehat9d2bd732009-09-22 16:44:22 -07004410};
4411
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304412static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4413{
4414 unsigned int gpio_no = host->plat->status_gpio;
4415 int status;
4416
4417 if (!gpio_is_valid(gpio_no))
4418 return;
4419
4420 status = gpio_request(gpio_no, "SD_HW_Detect");
4421 if (status)
4422 pr_err("%s: %s: gpio_request(%d) failed\n",
4423 mmc_hostname(host->mmc), __func__, gpio_no);
4424}
4425
4426static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4427{
4428 if (gpio_is_valid(host->plat->status_gpio))
4429 gpio_free(host->plat->status_gpio);
4430}
4431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004432static unsigned int
4433msmsdcc_slot_status(struct msmsdcc_host *host)
4434{
4435 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004436
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304437 status = gpio_get_value_cansleep(host->plat->status_gpio);
4438 if (host->plat->is_status_gpio_active_low)
4439 status = !status;
4440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004441 return status;
4442}
4443
San Mehat9d2bd732009-09-22 16:44:22 -07004444static void
4445msmsdcc_check_status(unsigned long data)
4446{
4447 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4448 unsigned int status;
4449
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304450 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004451 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004452 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004453 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004454 status = msmsdcc_slot_status(host);
4455
Krishna Konda941604a2012-01-10 17:46:34 -08004456 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004458 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004459 if (host->plat->status)
4460 pr_info("%s: Slot status change detected "
4461 "(%d -> %d)\n",
4462 mmc_hostname(host->mmc),
4463 host->oldstat, status);
4464 else if (host->plat->is_status_gpio_active_low)
4465 pr_info("%s: Slot status change detected "
4466 "(%d -> %d) and the card detect GPIO"
4467 " is ACTIVE_LOW\n",
4468 mmc_hostname(host->mmc),
4469 host->oldstat, status);
4470 else
4471 pr_info("%s: Slot status change detected "
4472 "(%d -> %d) and the card detect GPIO"
4473 " is ACTIVE_HIGH\n",
4474 mmc_hostname(host->mmc),
4475 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004476 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004477 }
4478 host->oldstat = status;
4479 } else {
4480 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004481 }
San Mehat9d2bd732009-09-22 16:44:22 -07004482}
4483
4484static irqreturn_t
4485msmsdcc_platform_status_irq(int irq, void *dev_id)
4486{
4487 struct msmsdcc_host *host = dev_id;
4488
Girish K Sa3c76eb2011-10-11 11:44:09 +05304489 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004490 msmsdcc_check_status((unsigned long) host);
4491 return IRQ_HANDLED;
4492}
4493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494static irqreturn_t
4495msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4496{
4497 struct msmsdcc_host *host = dev_id;
4498
4499 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4500 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304501 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004502 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304503 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004504 wake_lock(&host->sdio_wlock);
4505 msmsdcc_disable_irq_wake(host);
4506 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304507 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508 }
4509 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304511 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304512 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304513 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 }
4515 spin_unlock(&host->lock);
4516
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304517out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004518 return IRQ_HANDLED;
4519}
4520
San Mehat9d2bd732009-09-22 16:44:22 -07004521static void
4522msmsdcc_status_notify_cb(int card_present, void *dev_id)
4523{
4524 struct msmsdcc_host *host = dev_id;
4525
Girish K Sa3c76eb2011-10-11 11:44:09 +05304526 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004527 card_present);
4528 msmsdcc_check_status((unsigned long) host);
4529}
4530
San Mehat9d2bd732009-09-22 16:44:22 -07004531static int
4532msmsdcc_init_dma(struct msmsdcc_host *host)
4533{
4534 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4535 host->dma.host = host;
4536 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004537 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004538
4539 if (!host->dmares)
4540 return -ENODEV;
4541
4542 host->dma.nc = dma_alloc_coherent(NULL,
4543 sizeof(struct msmsdcc_nc_dmadata),
4544 &host->dma.nc_busaddr,
4545 GFP_KERNEL);
4546 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004547 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004548 return -ENOMEM;
4549 }
4550 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4551 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4552 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4553 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4554 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004555 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004556
4557 return 0;
4558}
4559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004560#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4561/**
4562 * Allocate and Connect a SDCC peripheral's SPS endpoint
4563 *
4564 * This function allocates endpoint context and
4565 * connect it with memory endpoint by calling
4566 * appropriate SPS driver APIs.
4567 *
4568 * Also registers a SPS callback function with
4569 * SPS driver
4570 *
4571 * This function should only be called once typically
4572 * during driver probe.
4573 *
4574 * @host - Pointer to sdcc host structure
4575 * @ep - Pointer to sps endpoint data structure
4576 * @is_produce - 1 means Producer endpoint
4577 * 0 means Consumer endpoint
4578 *
4579 * @return - 0 if successful else negative value.
4580 *
4581 */
4582static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4583 struct msmsdcc_sps_ep_conn_data *ep,
4584 bool is_producer)
4585{
4586 int rc = 0;
4587 struct sps_pipe *sps_pipe_handle;
4588 struct sps_connect *sps_config = &ep->config;
4589 struct sps_register_event *sps_event = &ep->event;
4590
4591 /* Allocate endpoint context */
4592 sps_pipe_handle = sps_alloc_endpoint();
4593 if (!sps_pipe_handle) {
4594 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4595 mmc_hostname(host->mmc), is_producer);
4596 rc = -ENOMEM;
4597 goto out;
4598 }
4599
4600 /* Get default connection configuration for an endpoint */
4601 rc = sps_get_config(sps_pipe_handle, sps_config);
4602 if (rc) {
4603 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4604 " rc=%d", mmc_hostname(host->mmc),
4605 (u32)sps_pipe_handle, rc);
4606 goto get_config_err;
4607 }
4608
4609 /* Modify the default connection configuration */
4610 if (is_producer) {
4611 /*
4612 * For SDCC producer transfer, source should be
4613 * SDCC peripheral where as destination should
4614 * be system memory.
4615 */
4616 sps_config->source = host->sps.bam_handle;
4617 sps_config->destination = SPS_DEV_HANDLE_MEM;
4618 /* Producer pipe will handle this connection */
4619 sps_config->mode = SPS_MODE_SRC;
4620 sps_config->options =
4621 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4622 } else {
4623 /*
4624 * For SDCC consumer transfer, source should be
4625 * system memory where as destination should
4626 * SDCC peripheral
4627 */
4628 sps_config->source = SPS_DEV_HANDLE_MEM;
4629 sps_config->destination = host->sps.bam_handle;
4630 sps_config->mode = SPS_MODE_DEST;
4631 sps_config->options =
4632 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4633 }
4634
4635 /* Producer pipe index */
4636 sps_config->src_pipe_index = host->sps.src_pipe_index;
4637 /* Consumer pipe index */
4638 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4639 /*
4640 * This event thresold value is only significant for BAM-to-BAM
4641 * transfer. It's ignored for BAM-to-System mode transfer.
4642 */
4643 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304644
4645 /* Allocate maximum descriptor fifo size */
4646 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4647 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004648 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4649 sps_config->desc.size,
4650 &sps_config->desc.phys_base,
4651 GFP_KERNEL);
4652
Pratibhasagar V00b94332011-10-18 14:57:27 +05304653 if (!sps_config->desc.base) {
4654 rc = -ENOMEM;
4655 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4656 , mmc_hostname(host->mmc));
4657 goto get_config_err;
4658 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004659 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4660
4661 /* Establish connection between peripheral and memory endpoint */
4662 rc = sps_connect(sps_pipe_handle, sps_config);
4663 if (rc) {
4664 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4665 " rc=%d", mmc_hostname(host->mmc),
4666 (u32)sps_pipe_handle, rc);
4667 goto sps_connect_err;
4668 }
4669
4670 sps_event->mode = SPS_TRIGGER_CALLBACK;
4671 sps_event->options = SPS_O_EOT;
4672 sps_event->callback = msmsdcc_sps_complete_cb;
4673 sps_event->xfer_done = NULL;
4674 sps_event->user = (void *)host;
4675
4676 /* Register callback event for EOT (End of transfer) event. */
4677 rc = sps_register_event(sps_pipe_handle, sps_event);
4678 if (rc) {
4679 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4680 " rc=%d", mmc_hostname(host->mmc),
4681 (u32)sps_pipe_handle, rc);
4682 goto reg_event_err;
4683 }
4684 /* Now save the sps pipe handle */
4685 ep->pipe_handle = sps_pipe_handle;
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004686 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"\
4687 " desc_fifo.phys_base=%pa\n", mmc_hostname(host->mmc),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688 __func__, is_producer ? "READ" : "WRITE",
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004689 (u32)sps_pipe_handle, &sps_config->desc.phys_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004690 goto out;
4691
4692reg_event_err:
4693 sps_disconnect(sps_pipe_handle);
4694sps_connect_err:
4695 dma_free_coherent(mmc_dev(host->mmc),
4696 sps_config->desc.size,
4697 sps_config->desc.base,
4698 sps_config->desc.phys_base);
4699get_config_err:
4700 sps_free_endpoint(sps_pipe_handle);
4701out:
4702 return rc;
4703}
4704
4705/**
4706 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4707 *
4708 * This function disconnect endpoint and deallocates
4709 * endpoint context.
4710 *
4711 * This function should only be called once typically
4712 * during driver remove.
4713 *
4714 * @host - Pointer to sdcc host structure
4715 * @ep - Pointer to sps endpoint data structure
4716 *
4717 */
4718static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4719 struct msmsdcc_sps_ep_conn_data *ep)
4720{
4721 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4722 struct sps_connect *sps_config = &ep->config;
4723 struct sps_register_event *sps_event = &ep->event;
4724
4725 sps_event->xfer_done = NULL;
4726 sps_event->callback = NULL;
4727 sps_register_event(sps_pipe_handle, sps_event);
4728 sps_disconnect(sps_pipe_handle);
4729 dma_free_coherent(mmc_dev(host->mmc),
4730 sps_config->desc.size,
4731 sps_config->desc.base,
4732 sps_config->desc.phys_base);
4733 sps_free_endpoint(sps_pipe_handle);
4734}
4735
4736/**
4737 * Reset SDCC peripheral's SPS endpoint
4738 *
4739 * This function disconnects an endpoint.
4740 *
4741 * This function should be called for reseting
4742 * SPS endpoint when data transfer error is
4743 * encountered during data transfer. This
4744 * can be considered as soft reset to endpoint.
4745 *
4746 * This function should only be called if
4747 * msmsdcc_sps_init() is already called.
4748 *
4749 * @host - Pointer to sdcc host structure
4750 * @ep - Pointer to sps endpoint data structure
4751 *
4752 * @return - 0 if successful else negative value.
4753 */
4754static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4755 struct msmsdcc_sps_ep_conn_data *ep)
4756{
4757 int rc = 0;
4758 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4759
4760 rc = sps_disconnect(sps_pipe_handle);
4761 if (rc) {
4762 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4763 " rc=%d", mmc_hostname(host->mmc), __func__,
4764 (u32)sps_pipe_handle, rc);
4765 goto out;
4766 }
4767 out:
4768 return rc;
4769}
4770
4771/**
4772 * Restore SDCC peripheral's SPS endpoint
4773 *
4774 * This function connects an endpoint.
4775 *
4776 * This function should be called for restoring
4777 * SPS endpoint after data transfer error is
4778 * encountered during data transfer. This
4779 * can be considered as soft reset to endpoint.
4780 *
4781 * This function should only be called if
4782 * msmsdcc_sps_reset_ep() is called before.
4783 *
4784 * @host - Pointer to sdcc host structure
4785 * @ep - Pointer to sps endpoint data structure
4786 *
4787 * @return - 0 if successful else negative value.
4788 */
4789static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4790 struct msmsdcc_sps_ep_conn_data *ep)
4791{
4792 int rc = 0;
4793 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4794 struct sps_connect *sps_config = &ep->config;
4795 struct sps_register_event *sps_event = &ep->event;
4796
4797 /* Establish connection between peripheral and memory endpoint */
4798 rc = sps_connect(sps_pipe_handle, sps_config);
4799 if (rc) {
4800 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4801 " rc=%d", mmc_hostname(host->mmc), __func__,
4802 (u32)sps_pipe_handle, rc);
4803 goto out;
4804 }
4805
4806 /* Register callback event for EOT (End of transfer) event. */
4807 rc = sps_register_event(sps_pipe_handle, sps_event);
4808 if (rc) {
4809 pr_err("%s: %s: sps_register_event() failed!!!"
4810 " pipe_handle=0x%x, rc=%d",
4811 mmc_hostname(host->mmc), __func__,
4812 (u32)sps_pipe_handle, rc);
4813 goto reg_event_err;
4814 }
4815 goto out;
4816
4817reg_event_err:
4818 sps_disconnect(sps_pipe_handle);
4819out:
4820 return rc;
4821}
4822
4823/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004824 * Handle BAM device's global error condition
4825 *
4826 * This is an error handler for the SDCC bam device
4827 *
4828 * This function is registered as a callback with SPS-BAM
4829 * driver and will called in case there are an errors for
4830 * the SDCC BAM deivce. Any error conditions in the BAM
4831 * device are global and will be result in this function
4832 * being called once per device.
4833 *
4834 * This function will be called from the sps driver's
4835 * interrupt context.
4836 *
4837 * @sps_cb_case - indicates what error it is
4838 * @user - Pointer to sdcc host structure
4839 */
4840static void
4841msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4842{
4843 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4844 struct mmc_request *mrq;
4845 unsigned long flags;
4846 int32_t error = 0;
4847
4848 BUG_ON(!host);
4849 BUG_ON(!is_sps_mode(host));
4850
4851 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004852 /* Reset all endpoints along with resetting bam. */
4853 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004854
4855 pr_err("%s: BAM Global ERROR IRQ happened\n",
4856 mmc_hostname(host->mmc));
4857 error = EAGAIN;
4858 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4859 /**
4860 * This means that there was an AHB access error and
4861 * the address we are trying to read/write is something
4862 * we dont have priviliges to do so.
4863 */
4864 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4865 mmc_hostname(host->mmc));
4866 error = EACCES;
4867 } else {
4868 /**
4869 * This should not have happened ideally. If this happens
4870 * there is some seriously wrong.
4871 */
4872 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4873 mmc_hostname(host->mmc), (u32) sps_cb_case);
4874 error = EIO;
4875 }
4876
4877 spin_lock_irqsave(&host->lock, flags);
4878
4879 mrq = host->curr.mrq;
4880
4881 if (mrq && mrq->cmd) {
4882 msmsdcc_dump_sdcc_state(host);
4883
4884 if (!mrq->cmd->error)
4885 mrq->cmd->error = -error;
4886 if (host->curr.data) {
4887 if (mrq->data && !mrq->data->error)
4888 mrq->data->error = -error;
4889 host->curr.data_xfered = 0;
4890 if (host->sps.sg && is_sps_mode(host)) {
4891 /* Stop current SPS transfer */
4892 msmsdcc_sps_exit_curr_xfer(host);
4893 } else {
4894 /* this condition should not have happened */
4895 pr_err("%s: something is seriously wrong. "\
4896 "Funtion: %s, line: %d\n",
4897 mmc_hostname(host->mmc),
4898 __func__, __LINE__);
4899 }
4900 } else {
4901 /* this condition should not have happened */
4902 pr_err("%s: something is seriously wrong. Funtion: "\
4903 "%s, line: %d\n", mmc_hostname(host->mmc),
4904 __func__, __LINE__);
4905 }
4906 }
4907 spin_unlock_irqrestore(&host->lock, flags);
4908}
4909
4910/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004911 * Initialize SPS HW connected with SDCC core
4912 *
4913 * This function register BAM HW resources with
4914 * SPS driver and then initialize 2 SPS endpoints
4915 *
4916 * This function should only be called once typically
4917 * during driver probe.
4918 *
4919 * @host - Pointer to sdcc host structure
4920 *
4921 * @return - 0 if successful else negative value.
4922 *
4923 */
4924static int msmsdcc_sps_init(struct msmsdcc_host *host)
4925{
4926 int rc = 0;
4927 struct sps_bam_props bam = {0};
4928
4929 host->bam_base = ioremap(host->bam_memres->start,
4930 resource_size(host->bam_memres));
4931 if (!host->bam_base) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004932 pr_err("%s: BAM ioremap() failed!!! resource: %pr\n",
4933 mmc_hostname(host->mmc), host->bam_memres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004934 rc = -ENOMEM;
4935 goto out;
4936 }
4937
4938 bam.phys_addr = host->bam_memres->start;
4939 bam.virt_addr = host->bam_base;
4940 /*
4941 * This event thresold value is only significant for BAM-to-BAM
4942 * transfer. It's ignored for BAM-to-System mode transfer.
4943 */
4944 bam.event_threshold = 0x10; /* Pipe event threshold */
4945 /*
4946 * This threshold controls when the BAM publish
4947 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304948 * SPS HW will be used for data transfer size even
4949 * less than SDCC FIFO size. So let's set BAM summing
4950 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304952 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004953 /* SPS driver wll handle the SDCC BAM IRQ */
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004954 bam.irq = host->bam_irqres->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004956 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4957 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004958
Krishna Kondacdff0902013-04-09 17:57:22 -07004959 /* bam reset messages will be limited to 5 times */
4960 bam.constrained_logging = true;
4961 bam.logging_number = 5;
4962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004963 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4964 (u32)bam.phys_addr);
4965 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4966 (u32)bam.virt_addr);
4967
4968 /* Register SDCC Peripheral BAM device to SPS driver */
4969 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4970 if (rc) {
4971 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4972 mmc_hostname(host->mmc), rc);
4973 goto reg_bam_err;
4974 }
4975 pr_info("%s: BAM device registered. bam_handle=0x%x",
4976 mmc_hostname(host->mmc), host->sps.bam_handle);
4977
4978 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4979 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4980
4981 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4982 SPS_PROD_PERIPHERAL);
4983 if (rc)
4984 goto sps_reset_err;
4985 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4986 SPS_CONS_PERIPHERAL);
4987 if (rc)
4988 goto cons_conn_err;
4989
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004990 pr_info("%s: Qualcomm MSM SDCC-BAM at %pr %pr\n",
4991 mmc_hostname(host->mmc), host->bam_memres, host->bam_irqres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 goto out;
4993
4994cons_conn_err:
4995 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4996sps_reset_err:
4997 sps_deregister_bam_device(host->sps.bam_handle);
4998reg_bam_err:
4999 iounmap(host->bam_base);
5000out:
5001 return rc;
5002}
5003
5004/**
5005 * De-initialize SPS HW connected with SDCC core
5006 *
5007 * This function deinitialize SPS endpoints and then
5008 * deregisters BAM resources from SPS driver.
5009 *
5010 * This function should only be called once typically
5011 * during driver remove.
5012 *
5013 * @host - Pointer to sdcc host structure
5014 *
5015 */
5016static void msmsdcc_sps_exit(struct msmsdcc_host *host)
5017{
5018 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
5019 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5020 sps_deregister_bam_device(host->sps.bam_handle);
5021 iounmap(host->bam_base);
5022}
5023#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
5024
5025static ssize_t
5026show_polling(struct device *dev, struct device_attribute *attr, char *buf)
5027{
5028 struct mmc_host *mmc = dev_get_drvdata(dev);
5029 struct msmsdcc_host *host = mmc_priv(mmc);
5030 int poll;
5031 unsigned long flags;
5032
5033 spin_lock_irqsave(&host->lock, flags);
5034 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
5035 spin_unlock_irqrestore(&host->lock, flags);
5036
5037 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
5038}
5039
5040static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305041store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005042 const char *buf, size_t count)
5043{
5044 struct mmc_host *mmc = dev_get_drvdata(dev);
5045 struct msmsdcc_host *host = mmc_priv(mmc);
5046 int value;
5047 unsigned long flags;
5048
5049 sscanf(buf, "%d", &value);
5050
5051 spin_lock_irqsave(&host->lock, flags);
5052 if (value) {
5053 mmc->caps |= MMC_CAP_NEEDS_POLL;
5054 mmc_detect_change(host->mmc, 0);
5055 } else {
5056 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5057 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 spin_unlock_irqrestore(&host->lock, flags);
5059 return count;
5060}
5061
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305062static ssize_t
5063show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
5064 char *buf)
5065{
5066 struct mmc_host *mmc = dev_get_drvdata(dev);
5067 struct msmsdcc_host *host = mmc_priv(mmc);
5068
5069 return snprintf(buf, PAGE_SIZE, "%u\n",
5070 host->msm_bus_vote.is_max_bw_needed);
5071}
5072
5073static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305074store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305075 const char *buf, size_t count)
5076{
5077 struct mmc_host *mmc = dev_get_drvdata(dev);
5078 struct msmsdcc_host *host = mmc_priv(mmc);
5079 uint32_t value;
5080 unsigned long flags;
5081
5082 if (!kstrtou32(buf, 0, &value)) {
5083 spin_lock_irqsave(&host->lock, flags);
5084 host->msm_bus_vote.is_max_bw_needed = !!value;
5085 spin_unlock_irqrestore(&host->lock, flags);
5086 }
5087
5088 return count;
5089}
5090
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305091static ssize_t
5092show_idle_timeout(struct device *dev, struct device_attribute *attr,
5093 char *buf)
5094{
5095 struct mmc_host *mmc = dev_get_drvdata(dev);
5096 struct msmsdcc_host *host = mmc_priv(mmc);
5097
5098 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05305099 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305100}
5101
5102static ssize_t
5103store_idle_timeout(struct device *dev, struct device_attribute *attr,
5104 const char *buf, size_t count)
5105{
5106 struct mmc_host *mmc = dev_get_drvdata(dev);
5107 struct msmsdcc_host *host = mmc_priv(mmc);
5108 unsigned int long flags;
5109 int timeout; /* in secs */
5110
5111 if (!kstrtou32(buf, 0, &timeout)
5112 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
5113 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05305114 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305115 spin_unlock_irqrestore(&host->lock, flags);
5116 }
5117 return count;
5118}
5119
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305120static inline void set_auto_cmd_setting(struct device *dev,
5121 const char *buf,
5122 bool is_cmd19)
5123{
5124 struct mmc_host *mmc = dev_get_drvdata(dev);
5125 struct msmsdcc_host *host = mmc_priv(mmc);
5126 unsigned int long flags;
5127 int temp;
5128
5129 if (!kstrtou32(buf, 0, &temp)) {
5130 spin_lock_irqsave(&host->lock, flags);
5131 if (is_cmd19)
5132 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305133 else
5134 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305135 spin_unlock_irqrestore(&host->lock, flags);
5136 }
5137}
5138
5139static ssize_t
5140show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5141 char *buf)
5142{
5143 struct mmc_host *mmc = dev_get_drvdata(dev);
5144 struct msmsdcc_host *host = mmc_priv(mmc);
5145
5146 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
5147}
5148
5149static ssize_t
5150store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5151 const char *buf, size_t count)
5152{
5153 set_auto_cmd_setting(dev, buf, true);
5154
5155 return count;
5156}
5157
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305158static ssize_t
5159show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5160 char *buf)
5161{
5162 struct mmc_host *mmc = dev_get_drvdata(dev);
5163 struct msmsdcc_host *host = mmc_priv(mmc);
5164
5165 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5166}
5167
5168static ssize_t
5169store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5170 const char *buf, size_t count)
5171{
5172 set_auto_cmd_setting(dev, buf, false);
5173
5174 return count;
5175}
5176
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305177static void msmsdcc_print_regs(const char *name, void __iomem *base,
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005178 resource_size_t phys_base,
5179 unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305180{
5181 unsigned int i;
5182
5183 if (!base)
5184 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305185
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005186 pr_err("===== %s: Register Dumps @phys_base=%pa, @virt_base=0x%x"\
5187 " =====\n", name, &phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305188 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305189 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305190 (u32)readl_relaxed(base + i*4),
5191 (u32)readl_relaxed(base + ((i+1)*4)),
5192 (u32)readl_relaxed(base + ((i+2)*4)),
5193 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305194 }
5195}
5196
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305197/*
5198 * This function prints the testbus debug output for all the
5199 * available SDCC controller test bus.
5200 *
5201 * Note: This function should only be called if the SDCC is clocked.
5202 */
5203static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
5204{
5205 int testbus_num;
5206
5207 if (!is_testbus_debug(host))
5208 return;
5209
5210 pr_err("== SDCC Test Bus Debug ==");
5211 for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
5212 writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
5213 | MCI_TESTBUS_ENA),
5214 host->base + MCI_TESTBUS_CONFIG);
5215 pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
5216 (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
5217 }
5218 /* Disable the test bus output */
5219 writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
5220}
5221
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305222static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5223{
5224 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305225 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305226 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305227 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305228 mmc_hostname(host->mmc),
5229 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305230 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305231 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305232 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5233
5234 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305235 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305236 msmsdcc_print_regs("SDCC-CORE", host->base,
5237 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305238 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5239 mmc_hostname(host->mmc),
5240 readl_relaxed(host->base + MCI_TEST_INPUT));
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305241 msmsdcc_print_testbus_info(host);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305242 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305243
5244 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305245 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305246 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305247 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305248 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305249 mmc_hostname(host->mmc), host->dma.busy,
5250 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305251 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305252 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305253 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5254 host->dml_memres->start,
5255 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305256 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305257 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305258 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305259
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305260 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305261 mmc_hostname(host->mmc), host->curr.xfer_size,
5262 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305263 }
5264
Krishna Konda3ca90f02012-08-29 16:29:21 -07005265 if (host->sps.reset_bam)
5266 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5267 mmc_hostname(host->mmc), host->sps.reset_bam);
5268
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305269 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305270 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5271 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5272 host->curr.got_dataend, host->prog_enable,
5273 host->curr.wait_for_auto_prog_done,
5274 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305275 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305276}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005278static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5279{
5280 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5281 struct mmc_request *mrq;
5282 unsigned long flags;
5283
5284 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005285 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005286 pr_info("%s: %s: dummy CMD52 timeout\n",
5287 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005288 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005289 }
5290
5291 mrq = host->curr.mrq;
5292
5293 if (mrq && mrq->cmd) {
Subhash Jadavani926a9cb2012-12-15 22:05:54 +05305294 if (!mrq->cmd->bkops_busy) {
5295 pr_info("%s: CMD%d: Request timeout\n",
5296 mmc_hostname(host->mmc), mrq->cmd->opcode);
5297 msmsdcc_dump_sdcc_state(host);
5298 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005300 if (!mrq->cmd->error)
5301 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305302 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005303 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005304 if (mrq->data && !mrq->data->error)
5305 mrq->data->error = -ETIMEDOUT;
5306 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305307 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005308 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305309 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005310 /* Stop current SPS transfer */
5311 msmsdcc_sps_exit_curr_xfer(host);
5312 } else {
5313 msmsdcc_reset_and_restore(host);
5314 msmsdcc_stop_data(host);
5315 if (mrq->data && mrq->data->stop)
5316 msmsdcc_start_command(host,
5317 mrq->data->stop, 0);
5318 else
5319 msmsdcc_request_end(host, mrq);
5320 }
5321 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305322 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305323 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005324 msmsdcc_reset_and_restore(host);
5325 msmsdcc_request_end(host, mrq);
5326 }
5327 }
5328 spin_unlock_irqrestore(&host->lock, flags);
5329}
5330
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305331/*
5332 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5333 *
5334 * @dev: device node from which the property value is to be read.
5335 * @prop_name: name of the property to be searched.
5336 * @out_array: filled array returned to caller
5337 * @len: filled array size returned to caller
5338 * @size: expected size of the array
5339 *
5340 * If expected "size" doesn't match with "len" an error is returned. If
5341 * expected size is zero, the length of actual array is returned provided
5342 * return value is zero.
5343 *
5344 * RETURNS:
5345 * zero on success, negative error if failed.
5346 */
5347static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5348 u32 **out_array, int *len, int size)
5349{
5350 int ret = 0;
5351 u32 *array = NULL;
5352 struct device_node *np = dev->of_node;
5353
5354 if (of_get_property(np, prop_name, len)) {
5355 size_t sz;
5356 sz = *len = *len / sizeof(*array);
5357
5358 if (sz > 0 && !(size > 0 && (sz != size))) {
5359 array = devm_kzalloc(dev, sz * sizeof(*array),
5360 GFP_KERNEL);
5361 if (!array) {
5362 dev_err(dev, "%s: no memory\n", prop_name);
5363 ret = -ENOMEM;
5364 goto out;
5365 }
5366
5367 ret = of_property_read_u32_array(np, prop_name,
5368 array, sz);
5369 if (ret < 0) {
5370 dev_err(dev, "%s: error reading array %d\n",
5371 prop_name, ret);
5372 goto out;
5373 }
5374 } else {
5375 dev_err(dev, "%s invalid size\n", prop_name);
5376 ret = -EINVAL;
5377 goto out;
5378 }
5379 } else {
5380 dev_err(dev, "%s not specified\n", prop_name);
5381 ret = -EINVAL;
5382 goto out;
5383 }
5384 *out_array = array;
5385out:
5386 if (ret)
5387 *len = 0;
5388 return ret;
5389}
5390
5391static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5392 struct msm_mmc_pad_pull_data **pad_pull_data)
5393{
5394 int ret = 0, base = 0, len, i;
5395 u32 *tmp;
5396 struct msm_mmc_pad_pull_data *pull_data;
5397 struct msm_mmc_pad_pull *pull;
5398
5399 switch (id) {
5400 case 1:
5401 base = TLMM_PULL_SDC1_CLK;
5402 break;
5403 case 2:
5404 base = TLMM_PULL_SDC2_CLK;
5405 break;
5406 case 3:
5407 base = TLMM_PULL_SDC3_CLK;
5408 break;
5409 case 4:
5410 base = TLMM_PULL_SDC4_CLK;
5411 break;
5412 default:
5413 dev_err(dev, "%s: Invalid slot id\n", __func__);
5414 ret = -EINVAL;
5415 goto err;
5416 }
5417
5418 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5419 GFP_KERNEL);
5420 if (!pull_data) {
5421 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5422 ret = -ENOMEM;
5423 goto err;
5424 }
5425 pull_data->size = 3; /* array size for clk, cmd, data */
5426
5427 /* Allocate on, off configs for clk, cmd, data */
5428 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5429 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5430 if (!pull) {
5431 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5432 ret = -ENOMEM;
5433 goto err;
5434 }
5435 pull_data->on = pull;
5436 pull_data->off = pull + pull_data->size;
5437
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005438 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305439 &tmp, &len, pull_data->size);
5440 if (!ret) {
5441 for (i = 0; i < len; i++) {
5442 pull_data->on[i].no = base + i;
5443 pull_data->on[i].val = tmp[i];
5444 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5445 i, pull_data->on[i].val);
5446 }
5447 } else {
5448 goto err;
5449 }
5450
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005451 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305452 &tmp, &len, pull_data->size);
5453 if (!ret) {
5454 for (i = 0; i < len; i++) {
5455 pull_data->off[i].no = base + i;
5456 pull_data->off[i].val = tmp[i];
5457 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5458 i, pull_data->off[i].val);
5459 }
5460 } else {
5461 goto err;
5462 }
5463
5464 *pad_pull_data = pull_data;
5465err:
5466 return ret;
5467}
5468
5469static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5470 struct msm_mmc_pad_drv_data **pad_drv_data)
5471{
5472 int ret = 0, base = 0, len, i;
5473 u32 *tmp;
5474 struct msm_mmc_pad_drv_data *drv_data;
5475 struct msm_mmc_pad_drv *drv;
5476
5477 switch (id) {
5478 case 1:
5479 base = TLMM_HDRV_SDC1_CLK;
5480 break;
5481 case 2:
5482 base = TLMM_HDRV_SDC2_CLK;
5483 break;
5484 case 3:
5485 base = TLMM_HDRV_SDC3_CLK;
5486 break;
5487 case 4:
5488 base = TLMM_HDRV_SDC4_CLK;
5489 break;
5490 default:
5491 dev_err(dev, "%s: Invalid slot id\n", __func__);
5492 ret = -EINVAL;
5493 goto err;
5494 }
5495
5496 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5497 GFP_KERNEL);
5498 if (!drv_data) {
5499 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5500 ret = -ENOMEM;
5501 goto err;
5502 }
5503 drv_data->size = 3; /* array size for clk, cmd, data */
5504
5505 /* Allocate on, off configs for clk, cmd, data */
5506 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5507 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5508 if (!drv) {
5509 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5510 ret = -ENOMEM;
5511 goto err;
5512 }
5513 drv_data->on = drv;
5514 drv_data->off = drv + drv_data->size;
5515
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005516 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305517 &tmp, &len, drv_data->size);
5518 if (!ret) {
5519 for (i = 0; i < len; i++) {
5520 drv_data->on[i].no = base + i;
5521 drv_data->on[i].val = tmp[i];
5522 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5523 i, drv_data->on[i].val);
5524 }
5525 } else {
5526 goto err;
5527 }
5528
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005529 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305530 &tmp, &len, drv_data->size);
5531 if (!ret) {
5532 for (i = 0; i < len; i++) {
5533 drv_data->off[i].no = base + i;
5534 drv_data->off[i].val = tmp[i];
5535 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5536 i, drv_data->off[i].val);
5537 }
5538 } else {
5539 goto err;
5540 }
5541
5542 *pad_drv_data = drv_data;
5543err:
5544 return ret;
5545}
5546
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305547static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5548 struct mmc_platform_data *pdata)
5549{
5550 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5551 struct device_node *np = dev->of_node;
5552
5553 pdata->status_gpio = of_get_named_gpio_flags(np,
5554 "cd-gpios", 0, &flags);
5555 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005556 struct platform_device *pdev = container_of(dev,
5557 struct platform_device, dev);
5558 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305559 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5560 }
5561
5562 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5563 "wp-gpios", 0, &flags);
5564 if (gpio_is_valid(pdata->wpswitch_gpio))
5565 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5566}
5567
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305568static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5569 struct mmc_platform_data *pdata)
5570{
5571 int ret = 0, id = 0, cnt, i;
5572 struct msm_mmc_pin_data *pin_data;
5573 struct device_node *np = dev->of_node;
5574
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305575 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5576
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305577 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5578 if (!pin_data) {
5579 dev_err(dev, "No memory for pin_data\n");
5580 ret = -ENOMEM;
5581 goto err;
5582 }
5583
5584 cnt = of_gpio_count(np);
5585 if (cnt > 0) {
5586 pin_data->is_gpio = true;
5587
5588 pin_data->gpio_data = devm_kzalloc(dev,
5589 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5590 if (!pin_data->gpio_data) {
5591 dev_err(dev, "No memory for gpio_data\n");
5592 ret = -ENOMEM;
5593 goto err;
5594 }
5595 pin_data->gpio_data->size = cnt;
5596 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5597 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5598 if (!pin_data->gpio_data->gpio) {
5599 dev_err(dev, "No memory for gpio\n");
5600 ret = -ENOMEM;
5601 goto err;
5602 }
5603
5604 for (i = 0; i < cnt; i++) {
5605 const char *name = NULL;
5606 char result[32];
5607 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5608 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005609 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305610
5611 snprintf(result, 32, "%s-%s",
5612 dev_name(dev), name ? name : "?");
5613 pin_data->gpio_data->gpio[i].name = result;
5614 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5615 pin_data->gpio_data->gpio[i].name,
5616 pin_data->gpio_data->gpio[i].no);
5617 }
5618 } else {
5619 pin_data->pad_data = devm_kzalloc(dev,
5620 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5621 if (!pin_data->pad_data) {
5622 dev_err(dev, "No memory for pin_data->pad_data\n");
5623 ret = -ENOMEM;
5624 goto err;
5625 }
5626
5627 of_property_read_u32(np, "cell-index", &id);
5628
5629 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5630 &pin_data->pad_data->pull);
5631 if (ret)
5632 goto err;
5633 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5634 &pin_data->pad_data->drv);
5635 if (ret)
5636 goto err;
5637 }
5638
5639 pdata->pin_data = pin_data;
5640err:
5641 if (ret)
5642 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5643 return ret;
5644}
5645
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305646#define MAX_PROP_SIZE 32
5647static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5648 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5649{
5650 int len, ret = 0;
5651 const __be32 *prop;
5652 char prop_name[MAX_PROP_SIZE];
5653 struct msm_mmc_reg_data *vreg;
5654 struct device_node *np = dev->of_node;
5655
5656 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5657 if (of_parse_phandle(np, prop_name, 0)) {
5658 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5659 if (!vreg) {
5660 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5661 ret = -ENOMEM;
5662 goto err;
5663 }
5664
5665 vreg->name = vreg_name;
5666
5667 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005668 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305669 if (of_get_property(np, prop_name, NULL))
5670 vreg->always_on = true;
5671
5672 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005673 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305674 if (of_get_property(np, prop_name, NULL))
5675 vreg->lpm_sup = true;
5676
5677 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005678 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305679 prop = of_get_property(np, prop_name, &len);
5680 if (!prop || (len != (2 * sizeof(__be32)))) {
5681 dev_warn(dev, "%s %s property\n",
5682 prop ? "invalid format" : "no", prop_name);
5683 } else {
5684 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5685 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5686 }
5687
5688 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005689 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305690 prop = of_get_property(np, prop_name, &len);
5691 if (!prop || (len != (2 * sizeof(__be32)))) {
5692 dev_warn(dev, "%s %s property\n",
5693 prop ? "invalid format" : "no", prop_name);
5694 } else {
5695 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5696 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5697 }
5698
5699 *vreg_data = vreg;
5700 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5701 vreg->name, vreg->always_on ? "always_on," : "",
5702 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5703 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5704 }
5705
5706err:
5707 return ret;
5708}
5709
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305710static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5711{
5712 int i, ret;
5713 struct mmc_platform_data *pdata;
5714 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305715 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005716 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305717 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305718
5719 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5720 if (!pdata) {
5721 dev_err(dev, "could not allocate memory for platform data\n");
5722 goto err;
5723 }
5724
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005725 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305726 if (bus_width == 8) {
5727 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5728 } else if (bus_width == 4) {
5729 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5730 } else {
5731 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5732 pdata->mmc_bus_width = 0;
5733 }
5734
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005735 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305736 &sup_voltages, &sup_volt_len, 0);
5737 if (!ret) {
5738 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305739 u32 mask;
5740
5741 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5742 sup_voltages[i + 1]);
5743 if (!mask)
5744 dev_err(dev, "Invalide voltage range %d\n", i);
5745 pdata->ocr_mask |= mask;
5746 }
5747 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305748 }
5749
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005750 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305751 &clk_table, &clk_table_len, 0);
5752 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305753 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305754 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305755 }
5756
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305757 pdata->vreg_data = devm_kzalloc(dev,
5758 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5759 if (!pdata->vreg_data) {
5760 dev_err(dev, "could not allocate memory for vreg_data\n");
5761 goto err;
5762 }
5763
5764 if (msmsdcc_dt_parse_vreg_info(dev,
5765 &pdata->vreg_data->vdd_data, "vdd"))
5766 goto err;
5767
5768 if (msmsdcc_dt_parse_vreg_info(dev,
5769 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5770 goto err;
5771
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305772 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5773 goto err;
5774
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005775 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305776
5777 for (i = 0; i < len; i++) {
5778 const char *name = NULL;
5779
5780 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005781 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305782 if (!name)
5783 continue;
5784
5785 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5786 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5787 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5788 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5789 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5790 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5791 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5792 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5793 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5794 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5795 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5796 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5797 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5798 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5799 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5800 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5801 | MMC_CAP_UHS_DDR50;
5802 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5803 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5804 | MMC_CAP_UHS_DDR50;
5805 }
5806
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005807 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305808 if (current_limit == 800)
5809 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5810 else if (current_limit == 600)
5811 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5812 else if (current_limit == 400)
5813 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5814 else if (current_limit == 200)
5815 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5816
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005817 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305818 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005819 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305820 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005821 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305822 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305823 of_property_read_u32(np, "qcom,dat1-mpm-int",
5824 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305825
5826 return pdata;
5827err:
5828 return NULL;
5829}
5830
San Mehat9d2bd732009-09-22 16:44:22 -07005831static int
5832msmsdcc_probe(struct platform_device *pdev)
5833{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305834 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005835 struct msmsdcc_host *host;
5836 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005837 unsigned long flags;
5838 struct resource *core_irqres = NULL;
5839 struct resource *bam_irqres = NULL;
5840 struct resource *core_memres = NULL;
5841 struct resource *dml_memres = NULL;
5842 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005843 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005844 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305845 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005846
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305847 if (pdev->dev.of_node) {
5848 plat = msmsdcc_populate_pdata(&pdev->dev);
5849 of_property_read_u32((&pdev->dev)->of_node,
5850 "cell-index", &pdev->id);
5851 } else {
5852 plat = pdev->dev.platform_data;
5853 }
San Mehat9d2bd732009-09-22 16:44:22 -07005854
5855 /* must have platform data */
5856 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005857 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005858 ret = -EINVAL;
5859 goto out;
5860 }
5861
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -08005862 if (disable_slots & (1 << (pdev->id - 1))) {
5863 pr_info("%s: Slot %d disabled\n", __func__, pdev->id);
5864 return -ENODEV;
5865 }
5866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005867 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005868 return -EINVAL;
5869
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305870 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5871 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5872 return -EINVAL;
5873 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005874
San Mehat9d2bd732009-09-22 16:44:22 -07005875 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005876 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005877 return -ENXIO;
5878 }
5879
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305880 core_memres = platform_get_resource_byname(pdev,
5881 IORESOURCE_MEM, "core_mem");
5882 bam_memres = platform_get_resource_byname(pdev,
5883 IORESOURCE_MEM, "bam_mem");
5884 dml_memres = platform_get_resource_byname(pdev,
5885 IORESOURCE_MEM, "dml_mem");
5886 core_irqres = platform_get_resource_byname(pdev,
5887 IORESOURCE_IRQ, "core_irq");
5888 bam_irqres = platform_get_resource_byname(pdev,
5889 IORESOURCE_IRQ, "bam_irq");
5890 dmares = platform_get_resource_byname(pdev,
5891 IORESOURCE_DMA, "dma_chnl");
5892 dma_crci_res = platform_get_resource_byname(pdev,
5893 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005894
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005895 if (!core_irqres || !core_memres) {
5896 pr_err("%s: Invalid sdcc core resource\n", __func__);
5897 return -ENXIO;
5898 }
5899
5900 /*
5901 * Both BAM and DML memory resource should be preset.
5902 * BAM IRQ resource should also be present.
5903 */
5904 if ((bam_memres && !dml_memres) ||
5905 (!bam_memres && dml_memres) ||
5906 ((bam_memres && dml_memres) && !bam_irqres)) {
5907 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005908 return -ENXIO;
5909 }
5910
5911 /*
5912 * Setup our host structure
5913 */
San Mehat9d2bd732009-09-22 16:44:22 -07005914 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5915 if (!mmc) {
5916 ret = -ENOMEM;
5917 goto out;
5918 }
5919
5920 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305921 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005922 host->plat = plat;
5923 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005924 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305925
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305926 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305927 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005928 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305929 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005931 host->base = ioremap(core_memres->start,
5932 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005933 if (!host->base) {
5934 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305935 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005936 }
5937
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005938 host->core_irqres = core_irqres;
5939 host->bam_irqres = bam_irqres;
5940 host->core_memres = core_memres;
5941 host->dml_memres = dml_memres;
5942 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005943 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005944 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005945 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305946 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005948#ifdef CONFIG_MMC_EMBEDDED_SDIO
5949 if (plat->embedded_sdio)
5950 mmc_set_embedded_sdio_data(mmc,
5951 &plat->embedded_sdio->cis,
5952 &plat->embedded_sdio->cccr,
5953 plat->embedded_sdio->funcs,
5954 plat->embedded_sdio->num_funcs);
5955#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005956
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305957 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5958 (unsigned long)host);
5959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005960 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5961 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305962 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005963 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305964 ret = msmsdcc_init_dma(host);
5965 if (ret)
5966 goto ioremap_free;
5967 } else {
5968 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005969 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305970 }
San Mehat9d2bd732009-09-22 16:44:22 -07005971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005972 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305973 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005974 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305975 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5976 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5977 /* Vote for max. clk rate for max. performance */
5978 ret = clk_set_rate(host->bus_clk, INT_MAX);
5979 if (ret)
5980 goto bus_clk_put;
5981 ret = clk_prepare_enable(host->bus_clk);
5982 if (ret)
5983 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005984 }
5985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005986 /*
5987 * Setup main peripheral bus clock
5988 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005989 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005990 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305991 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005992 if (ret)
5993 goto pclk_put;
5994
5995 host->pclk_rate = clk_get_rate(host->pclk);
5996 }
5997
5998 /*
5999 * Setup SDC MMC clock
6000 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006001 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07006002 if (IS_ERR(host->clk)) {
6003 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006004 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07006005 }
6006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006007 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05306008 if (ret) {
6009 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
6010 goto clk_put;
6011 }
6012
Asutosh Dasf5298c32012-04-03 14:51:47 +05306013 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006014 if (ret)
6015 goto clk_put;
6016
San Mehat9d2bd732009-09-22 16:44:22 -07006017 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306018 if (!host->clk_rate)
6019 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05306020
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306021 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05306022 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306023
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306024 /*
6025 * Set the register write delay according to min. clock frequency
6026 * supported and update later when the host->clk_rate changes.
6027 */
6028 host->reg_write_delay =
6029 (1 + ((3 * USEC_PER_SEC) /
6030 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006031
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306032 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05306033 /* Apply Hard reset to SDCC to put it in power on default state */
6034 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006035
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006036#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306037 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006038 if (host->plat->cpu_dma_latency)
6039 host->cpu_dma_latency = host->plat->cpu_dma_latency;
6040 else
6041 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
6042 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306043 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
6044
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306045 ret = msmsdcc_msm_bus_register(host);
6046 if (ret)
6047 goto pm_qos_remove;
6048
6049 if (host->msm_bus_vote.client_handle)
6050 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
6051 msmsdcc_msm_bus_work);
6052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006053 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07006054 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006055 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07006056 goto clk_disable;
6057 }
6058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006059
6060 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306061 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006062 /* Initialize SPS */
6063 ret = msmsdcc_sps_init(host);
6064 if (ret)
6065 goto vreg_deinit;
6066 /* Initialize DML */
6067 ret = msmsdcc_dml_init(host);
6068 if (ret)
6069 goto sps_exit;
6070 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05306071 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07006072
San Mehat9d2bd732009-09-22 16:44:22 -07006073 /*
6074 * Setup MMC host structure
6075 */
6076 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006077 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
6078 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006079 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05306080 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
6081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006082 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
6083 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07006084 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05306085 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05306086 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306087 /*
6088 * If we send the CMD23 before multi block write/read command
6089 * then we need not to send CMD12 at the end of the transfer.
6090 * If we don't send the CMD12 then only way to detect the PROG_DONE
6091 * status is to use the AUTO_PROG_DONE status provided by SDCC4
6092 * controller. So let's enable the CMD23 for SDCC4 only.
6093 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306094 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306095 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07006096
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006097 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05306098 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006099 /*
6100 * XPC controls the maximum current in the default speed mode of SDXC
6101 * card. XPC=0 means 100mA (max.) but speed class is not supported.
6102 * XPC=1 means 150mA (max.) and speed class is supported.
6103 */
6104 if (plat->xpc_cap)
6105 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
6106 MMC_CAP_SET_XPC_180);
6107
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02006108 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02006109 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05306110 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03006111 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03006112 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02006113 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Konstantin Dorfmana2c84222013-03-12 15:33:53 +02006114 mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
Yaniv Gardi14098552012-06-04 10:56:03 +03006115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006116 if (plat->nonremovable)
6117 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006118 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006119
6120 if (plat->is_sdio_al_client)
6121 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07006122
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306123 mmc->max_segs = msmsdcc_get_nr_sg(host);
6124 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
6125 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07006126
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306127 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07006128 mmc->max_seg_size = mmc->max_req_size;
6129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006130 writel_relaxed(0, host->base + MMCIMASK0);
6131 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05306132 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006134 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
6135 mb();
6136 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07006137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006138 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
6139 DRIVER_NAME " (cmd)", host);
6140 if (ret)
6141 goto dml_exit;
6142
6143 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
6144 DRIVER_NAME " (pio)", host);
6145 if (ret)
6146 goto irq_free;
6147
6148 /*
6149 * Enable SDCC IRQ only when host is powered on. Otherwise, this
6150 * IRQ is un-necessarily being monitored by MPM (Modem power
6151 * management block) during idle-power collapse. The MPM will be
6152 * configured to monitor the DATA1 GPIO line with level-low trigger
6153 * and thus depending on the GPIO status, it prevents TCXO shutdown
6154 * during idle-power collapse.
6155 */
6156 disable_irq(core_irqres->start);
6157 host->sdcc_irq_disabled = 1;
6158
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05306159 if (!plat->sdiowakeup_irq) {
6160 /* Check if registered as IORESOURCE_IRQ */
6161 plat->sdiowakeup_irq =
6162 platform_get_irq_byname(pdev, "sdiowakeup_irq");
6163 if (plat->sdiowakeup_irq < 0)
6164 plat->sdiowakeup_irq = 0;
6165 }
6166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006167 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006168 ret = request_irq(plat->sdiowakeup_irq,
6169 msmsdcc_platform_sdiowakeup_irq,
6170 IRQF_SHARED | IRQF_TRIGGER_LOW,
6171 DRIVER_NAME "sdiowakeup", host);
6172 if (ret) {
6173 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6174 plat->sdiowakeup_irq, ret);
6175 goto pio_irq_free;
6176 } else {
6177 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306178 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006179 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306180 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006181 }
6182 spin_unlock_irqrestore(&host->lock, flags);
6183 }
6184 }
6185
Krishna Konda1963f432013-02-19 20:28:53 -08006186 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006187 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6188 mmc_hostname(mmc));
6189 }
6190
6191 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6192 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006193 /*
6194 * Setup card detect change
6195 */
6196
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306197 if (!plat->status_gpio)
6198 plat->status_gpio = -ENOENT;
6199 if (!plat->wpswitch_gpio)
6200 plat->wpswitch_gpio = -ENOENT;
6201
6202 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306203 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306205 } else {
6206 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006207 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306208 }
Krishna Konda941604a2012-01-10 17:46:34 -08006209 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006210 }
San Mehat9d2bd732009-09-22 16:44:22 -07006211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006212 if (plat->status_irq) {
6213 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006214 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006215 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006216 DRIVER_NAME " (slot)",
6217 host);
6218 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006219 pr_err("Unable to get slot IRQ %d (%d)\n",
6220 plat->status_irq, ret);
6221 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006222 }
6223 } else if (plat->register_status_notify) {
6224 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6225 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006226 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006227 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006228
6229 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006230
6231 ret = pm_runtime_set_active(&(pdev)->dev);
6232 if (ret < 0)
6233 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6234 __func__, ret);
6235 /*
6236 * There is no notion of suspend/resume for SD/MMC/SDIO
6237 * cards. So host can be suspended/resumed with out
6238 * worrying about its children.
6239 */
6240 pm_suspend_ignore_children(&(pdev)->dev, true);
6241
6242 /*
6243 * MMC/SD/SDIO bus suspend/resume operations are defined
6244 * only for the slots that will be used for non-removable
6245 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6246 * defined. Otherwise, they simply become card removal and
6247 * insertion events during suspend and resume respectively.
6248 * Hence, enable run-time PM only for slots for which bus
6249 * suspend/resume operations are defined.
6250 */
6251#ifdef CONFIG_MMC_UNSAFE_RESUME
6252 /*
6253 * If this capability is set, MMC core will enable/disable host
6254 * for every claim/release operation on a host. We use this
6255 * notification to increment/decrement runtime pm usage count.
6256 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006257 pm_runtime_enable(&(pdev)->dev);
6258#else
6259 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006260 pm_runtime_enable(&(pdev)->dev);
6261 }
6262#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306263 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006264 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6265 (unsigned long)host);
6266
San Mehat9d2bd732009-09-22 16:44:22 -07006267 mmc_add_host(mmc);
6268
Sujit Reddy Thumma97a35d22012-10-31 22:45:45 +05306269 mmc->clk_scaling.up_threshold = 35;
6270 mmc->clk_scaling.down_threshold = 5;
6271 mmc->clk_scaling.polling_delay_ms = 100;
6272 mmc->caps2 |= MMC_CAP2_CLK_SCALE;
6273
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006274 pr_info("%s: Qualcomm MSM SDCC-core %pr %pr,%d dma %d dmacrcri %d\n",
6275 mmc_hostname(mmc), core_memres, core_irqres,
Krishna Konda25786ec2011-07-25 16:21:36 -07006276 (unsigned int) plat->status_irq, host->dma.channel,
6277 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006278
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306279 pr_info("%s: Controller capabilities: 0x%.8x\n",
6280 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006281 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6282 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6283 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6284 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6285 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6286 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6287 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6288 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6289 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6290 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6291 host->eject);
6292 pr_info("%s: Power save feature enable = %d\n",
6293 mmc_hostname(mmc), msmsdcc_pwrsave);
6294
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306295 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006296 && host->dma.crci != -1) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006297 pr_info("%s: DM non-cached buffer at %p, dma_addr: %pa\n",
6298 mmc_hostname(mmc), host->dma.nc, &host->dma.nc_busaddr);
6299 pr_info("%s: DM cmd busaddr: %pa, cmdptr busaddr: %pa\n",
6300 mmc_hostname(mmc), &host->dma.cmd_busaddr,
6301 &host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306302 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006303 pr_info("%s: SPS-BAM data transfer mode available\n",
6304 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006305 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006306 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006308#if defined(CONFIG_DEBUG_FS)
6309 msmsdcc_dbg_createhost(host);
6310#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306311
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306312 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6313 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6314 sysfs_attr_init(&host->max_bus_bw.attr);
6315 host->max_bus_bw.attr.name = "max_bus_bw";
6316 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6317 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306318 if (ret)
6319 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306320
6321 if (!plat->status_irq) {
6322 host->polling.show = show_polling;
6323 host->polling.store = store_polling;
6324 sysfs_attr_init(&host->polling.attr);
6325 host->polling.attr.name = "polling";
6326 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6327 ret = device_create_file(&pdev->dev, &host->polling);
6328 if (ret)
6329 goto remove_max_bus_bw_file;
6330 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306331 host->idle_timeout.show = show_idle_timeout;
6332 host->idle_timeout.store = store_idle_timeout;
6333 sysfs_attr_init(&host->idle_timeout.attr);
6334 host->idle_timeout.attr.name = "idle_timeout";
6335 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6336 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6337 if (ret)
6338 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306339
6340 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306341 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306342
6343 /* Sysfs entry for AUTO CMD19 control */
6344 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6345 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6346 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6347 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6348 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6349 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6350 if (ret)
6351 goto remove_idle_timeout_file;
6352
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306353 add_auto_cmd21_atrr:
6354 if (!is_auto_cmd21(host))
6355 goto exit;
6356
6357 /* Sysfs entry for AUTO CMD21 control */
6358 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6359 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6360 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6361 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6362 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6363 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6364 if (ret)
6365 goto remove_auto_cmd19_attr_file;
6366
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306367 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006368 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006369
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306370 remove_auto_cmd19_attr_file:
6371 if (is_auto_cmd19(host))
6372 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306373 remove_idle_timeout_file:
6374 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306375 remove_polling_file:
6376 if (!plat->status_irq)
6377 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306378 remove_max_bus_bw_file:
6379 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006380 platform_irq_free:
6381 del_timer_sync(&host->req_tout_timer);
6382 pm_runtime_disable(&(pdev)->dev);
6383 pm_runtime_set_suspended(&(pdev)->dev);
6384
6385 if (plat->status_irq)
6386 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306387 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006388 sdiowakeup_irq_free:
Krishna Konda1963f432013-02-19 20:28:53 -08006389 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6390 wake_lock_destroy(&host->sdio_wlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006391 wake_lock_destroy(&host->sdio_suspend_wlock);
6392 if (plat->sdiowakeup_irq)
6393 free_irq(plat->sdiowakeup_irq, host);
6394 pio_irq_free:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006395 free_irq(core_irqres->start, host);
6396 irq_free:
6397 free_irq(core_irqres->start, host);
6398 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306399 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006400 msmsdcc_dml_exit(host);
6401 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306402 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006403 msmsdcc_sps_exit(host);
6404 vreg_deinit:
6405 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006406 clk_disable:
Krishna Konda7dd56c22012-11-08 17:52:32 -08006407 clk_disable_unprepare(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306408 msmsdcc_msm_bus_unregister(host);
6409 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006410 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306411 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006412 clk_put:
6413 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006414 pclk_disable:
6415 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306416 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006417 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006418 if (!IS_ERR(host->pclk))
6419 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306420 if (!IS_ERR_OR_NULL(host->bus_clk))
6421 clk_disable_unprepare(host->bus_clk);
6422 bus_clk_put:
6423 if (!IS_ERR_OR_NULL(host->bus_clk))
6424 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306425 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006426 if (host->dmares)
6427 dma_free_coherent(NULL,
6428 sizeof(struct msmsdcc_nc_dmadata),
6429 host->dma.nc, host->dma.nc_busaddr);
6430 }
6431 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306432 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006433 host_free:
6434 mmc_free_host(mmc);
6435 out:
6436 return ret;
6437}
6438
Pratibhasagar V713817b2012-09-07 11:28:30 +05306439#ifdef CONFIG_DEBUG_FS
6440static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6441{
6442 debugfs_remove_recursive(host->debugfs_host_dir);
6443 host->debugfs_host_dir = NULL;
6444}
6445#else
6446static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6447#endif
6448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006449static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006450{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006451 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6452 struct mmc_platform_data *plat;
6453 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006455 if (!mmc)
6456 return -ENXIO;
6457
6458 if (pm_runtime_suspended(&(pdev)->dev))
6459 pm_runtime_resume(&(pdev)->dev);
6460
6461 host = mmc_priv(mmc);
6462
6463 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6464 plat = host->plat;
6465
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306466 if (is_auto_cmd19(host))
6467 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306468 if (is_auto_cmd21(host))
6469 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306470 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006471 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306472 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306473 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006474
Pratibhasagar V713817b2012-09-07 11:28:30 +05306475 msmsdcc_remove_debugfs(host);
6476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006477 del_timer_sync(&host->req_tout_timer);
6478 tasklet_kill(&host->dma_tlet);
6479 tasklet_kill(&host->sps.tlet);
6480 mmc_remove_host(mmc);
6481
6482 if (plat->status_irq)
6483 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306484 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006485
6486 wake_lock_destroy(&host->sdio_suspend_wlock);
6487 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006488 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6489 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006490 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006491
Krishna Konda1963f432013-02-19 20:28:53 -08006492 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6493 wake_lock_destroy(&host->sdio_wlock);
6494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006495 free_irq(host->core_irqres->start, host);
6496 free_irq(host->core_irqres->start, host);
6497
6498 clk_put(host->clk);
6499 if (!IS_ERR(host->pclk))
6500 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306501 if (!IS_ERR_OR_NULL(host->bus_clk))
6502 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006503
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006504 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306505 pm_qos_remove_request(&host->pm_qos_req_dma);
6506
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306507 if (host->msm_bus_vote.client_handle) {
6508 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6509 msmsdcc_msm_bus_unregister(host);
6510 }
6511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006512 msmsdcc_vreg_init(host, false);
6513
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306514 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006515 if (host->dmares)
6516 dma_free_coherent(NULL,
6517 sizeof(struct msmsdcc_nc_dmadata),
6518 host->dma.nc, host->dma.nc_busaddr);
6519 }
6520
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306521 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006522 msmsdcc_dml_exit(host);
6523 msmsdcc_sps_exit(host);
6524 }
6525
6526 iounmap(host->base);
6527 mmc_free_host(mmc);
6528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006529 pm_runtime_disable(&(pdev)->dev);
6530 pm_runtime_set_suspended(&(pdev)->dev);
6531
6532 return 0;
6533}
6534
6535#ifdef CONFIG_MSM_SDIO_AL
6536int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6537{
6538 struct msmsdcc_host *host = mmc_priv(mmc);
6539 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306540 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006541
Asutosh Dasf5298c32012-04-03 14:51:47 +05306542 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006543 spin_lock_irqsave(&host->lock, flags);
6544 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6545 enable ? "En" : "Dis");
6546
6547 if (enable) {
6548 if (!host->sdcc_irq_disabled) {
6549 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306550 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006551 host->sdcc_irq_disabled = 1;
6552 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306553 rc = msmsdcc_setup_clocks(host, false);
6554 if (rc)
6555 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006556
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306557 if (host->plat->sdio_lpm_gpio_setup &&
6558 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006559 spin_unlock_irqrestore(&host->lock, flags);
6560 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6561 spin_lock_irqsave(&host->lock, flags);
6562 host->sdio_gpio_lpm = 1;
6563 }
6564
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306565 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006566 msmsdcc_enable_irq_wake(host);
6567 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306568 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006569 }
6570 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306571 rc = msmsdcc_setup_clocks(host, true);
6572 if (rc)
6573 goto out;
6574
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306575 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006576 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306577 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006578 msmsdcc_disable_irq_wake(host);
6579 }
6580
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306581 if (host->plat->sdio_lpm_gpio_setup &&
6582 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006583 spin_unlock_irqrestore(&host->lock, flags);
6584 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6585 spin_lock_irqsave(&host->lock, flags);
6586 host->sdio_gpio_lpm = 0;
6587 }
6588
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306589 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006590 writel_relaxed(host->mci_irqenable,
6591 host->base + MMCIMASK0);
6592 mb();
6593 enable_irq(host->core_irqres->start);
6594 host->sdcc_irq_disabled = 0;
6595 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006596 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306597out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006598 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306599 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306600 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006601}
6602#else
6603int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6604{
6605 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006606}
6607#endif
6608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006609#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306610#ifdef CONFIG_MMC_CLKGATE
6611static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6612{
6613 struct mmc_host *mmc = host->mmc;
6614 unsigned long flags;
6615
6616 mmc_host_clk_hold(mmc);
6617 spin_lock_irqsave(&mmc->clk_lock, flags);
6618 mmc->clk_old = mmc->ios.clock;
6619 mmc->ios.clock = 0;
6620 mmc->clk_gated = true;
6621 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6622 mmc_set_ios(mmc);
6623 mmc_host_clk_release(mmc);
6624}
6625
6626static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6627{
6628 struct mmc_host *mmc = host->mmc;
6629
6630 mmc_host_clk_hold(mmc);
6631 mmc->ios.clock = host->clk_rate;
6632 mmc_set_ios(mmc);
6633 mmc_host_clk_release(mmc);
6634}
6635#else
6636static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6637{
6638 struct mmc_host *mmc = host->mmc;
6639
6640 mmc->ios.clock = 0;
6641 mmc_set_ios(mmc);
6642}
6643
6644static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6645{
6646 struct mmc_host *mmc = host->mmc;
6647
6648 mmc->ios.clock = host->clk_rate;
6649 mmc_set_ios(mmc);
6650}
6651#endif
6652
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306653#if CONFIG_DEBUG_FS
6654static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306655 const char *func, int err)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306656{
6657 ktime_t diff;
6658
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306659 if (host->print_pm_stats && !err) {
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306660 diff = ktime_sub(ktime_get(), start);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306661 pr_info("%s: %s: Completed in %llu usec\n",
6662 mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306663 }
6664}
6665#else
6666static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306667 const char *func, int err) {}
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306668#endif
6669
San Mehat9d2bd732009-09-22 16:44:22 -07006670static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006671msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006672{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006673 struct mmc_host *mmc = dev_get_drvdata(dev);
6674 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006675 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306676 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306677 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006678
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306679 if (host->plat->is_sdio_al_client) {
6680 rc = 0;
6681 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006682 }
San Mehat9d2bd732009-09-22 16:44:22 -07006683
Sahitya Tummala7661a452011-07-18 13:28:35 +05306684 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006685 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006686 host->sdcc_suspending = 1;
6687 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006689 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006690 * MMC core thinks that host is disabled by now since
6691 * runtime suspend is scheduled after msmsdcc_disable()
6692 * is called. Thus, MMC core will try to enable the host
6693 * while suspending it. This results in a synchronous
6694 * runtime resume request while in runtime suspending
6695 * context and hence inorder to complete this resume
6696 * requet, it will wait for suspend to be complete,
6697 * but runtime suspend also can not proceed further
6698 * until the host is resumed. Thus, it leads to a hang.
6699 * Hence, increase the pm usage count before suspending
6700 * the host so that any resume requests after this will
6701 * simple become pm usage counter increment operations.
6702 */
6703 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306704 /* If there is pending detect work abort runtime suspend */
6705 if (unlikely(work_busy(&mmc->detect.work)))
6706 rc = -EAGAIN;
6707 else
6708 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006709 pm_runtime_put_noidle(dev);
6710
6711 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306712 spin_lock_irqsave(&host->lock, flags);
6713 host->sdcc_suspended = true;
6714 spin_unlock_irqrestore(&host->lock, flags);
6715 if (mmc->card && mmc_card_sdio(mmc->card) &&
6716 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006717 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306718 * If SDIO function driver doesn't want
6719 * to power off the card, atleast turn off
6720 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006721 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306722 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006723 }
6724 }
6725 host->sdcc_suspending = 0;
6726 mmc->suspend_task = NULL;
6727 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6728 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006729 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306730 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306731out:
6732 /* set bus bandwidth to 0 immediately */
6733 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306734 msmsdcc_print_pm_stats(host, start, __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07006735 return rc;
6736}
6737
6738static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006739msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006740{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006741 struct mmc_host *mmc = dev_get_drvdata(dev);
6742 struct msmsdcc_host *host = mmc_priv(mmc);
6743 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306744 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006746 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306747 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006748
Sahitya Tummala7661a452011-07-18 13:28:35 +05306749 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006750 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306751 if (mmc->card && mmc_card_sdio(mmc->card) &&
6752 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306753 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306754 }
San Mehat9d2bd732009-09-22 16:44:22 -07006755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006756 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006757
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006758 /*
6759 * FIXME: Clearing of flags must be handled in clients
6760 * resume handler.
6761 */
6762 spin_lock_irqsave(&host->lock, flags);
6763 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306764 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006765 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006767 /*
6768 * After resuming the host wait for sometime so that
6769 * the SDIO work will be processed.
6770 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306771 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306772 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006773 host->plat->sdiowakeup_irq) &&
6774 wake_lock_active(&host->sdio_wlock))
6775 wake_lock_timeout(&host->sdio_wlock, 1);
6776 }
6777
6778 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006779 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306780 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306781 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306782out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306783 msmsdcc_print_pm_stats(host, start, __func__, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07006784 return 0;
6785}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006786
6787static int msmsdcc_runtime_idle(struct device *dev)
6788{
6789 struct mmc_host *mmc = dev_get_drvdata(dev);
6790 struct msmsdcc_host *host = mmc_priv(mmc);
6791
6792 if (host->plat->is_sdio_al_client)
6793 return 0;
6794
6795 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306796 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006797
6798 return -EAGAIN;
6799}
6800
6801static int msmsdcc_pm_suspend(struct device *dev)
6802{
6803 struct mmc_host *mmc = dev_get_drvdata(dev);
6804 struct msmsdcc_host *host = mmc_priv(mmc);
6805 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306806 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006807
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306808 if (host->plat->is_sdio_al_client) {
6809 rc = 0;
6810 goto out;
6811 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306812 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006813 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306814 msmsdcc_disable_status_gpio(host);
6815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006816
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306817 /*
6818 * If system comes out of suspend, msmsdcc_pm_resume() sets the
6819 * host->pending_resume flag if the SDCC wasn't runtime suspended.
6820 * Now if the system again goes to suspend without any SDCC activity
6821 * then host->pending_resume flag will remain set which may cause
6822 * the SDCC resume to happen first and then suspend.
6823 * To avoid this unnecessary resume/suspend, make sure that
6824 * pending_resume flag is cleared before calling the
6825 * msmsdcc_runtime_suspend().
6826 */
6827 if (!pm_runtime_suspended(dev) && !host->pending_resume)
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006828 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306829 out:
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306830 /* This flag must not be set if system is entering into suspend */
6831 host->pending_resume = false;
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306832 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006833 return rc;
6834}
6835
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306836static int msmsdcc_suspend_noirq(struct device *dev)
6837{
6838 struct mmc_host *mmc = dev_get_drvdata(dev);
6839 struct msmsdcc_host *host = mmc_priv(mmc);
6840 int rc = 0;
6841
6842 /*
6843 * After platform suspend there may be active request
6844 * which might have enabled clocks. For example, in SDIO
6845 * case, ksdioirq thread might have scheduled after sdcc
6846 * suspend but before system freeze. In that case abort
6847 * suspend and retry instead of keeping the clocks on
6848 * during suspend and not allowing TCXO.
6849 */
6850
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306851 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306852 pr_warn("%s: clocks are on after suspend, aborting system "
6853 "suspend\n", mmc_hostname(mmc));
6854 rc = -EAGAIN;
6855 }
6856
6857 return rc;
6858}
6859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006860static int msmsdcc_pm_resume(struct device *dev)
6861{
6862 struct mmc_host *mmc = dev_get_drvdata(dev);
6863 struct msmsdcc_host *host = mmc_priv(mmc);
6864 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306865 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006866
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306867 if (host->plat->is_sdio_al_client) {
6868 rc = 0;
6869 goto out;
6870 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006871 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306872 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306873 /*
6874 * As runtime PM is enabled before calling the device's platform resume
6875 * callback, we use the pm_runtime_suspended API to know if SDCC is
6876 * really runtime suspended or not and set the pending_resume flag only
6877 * if its not runtime suspended.
6878 */
6879 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006880 host->pending_resume = true;
6881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006882 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306883 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006884 msmsdcc_check_status((unsigned long)host);
6885 enable_irq(host->plat->status_irq);
6886 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306887out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306888 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006889 return rc;
6890}
6891
Daniel Walker08ecfde2010-06-23 12:32:20 -07006892#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006893static int msmsdcc_runtime_suspend(struct device *dev)
6894{
6895 return 0;
6896}
6897static int msmsdcc_runtime_idle(struct device *dev)
6898{
6899 return 0;
6900}
6901static int msmsdcc_pm_suspend(struct device *dev)
6902{
6903 return 0;
6904}
6905static int msmsdcc_pm_resume(struct device *dev)
6906{
6907 return 0;
6908}
6909static int msmsdcc_suspend_noirq(struct device *dev)
6910{
6911 return 0;
6912}
6913static int msmsdcc_runtime_resume(struct device *dev)
6914{
6915 return 0;
6916}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006917#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006919static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6920 .runtime_suspend = msmsdcc_runtime_suspend,
6921 .runtime_resume = msmsdcc_runtime_resume,
6922 .runtime_idle = msmsdcc_runtime_idle,
6923 .suspend = msmsdcc_pm_suspend,
6924 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306925 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006926};
6927
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306928static const struct of_device_id msmsdcc_dt_match[] = {
6929 {.compatible = "qcom,msm-sdcc"},
6930
6931};
6932MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6933
San Mehat9d2bd732009-09-22 16:44:22 -07006934static struct platform_driver msmsdcc_driver = {
6935 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006936 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006937 .driver = {
6938 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006939 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306940 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006941 },
6942};
6943
6944static int __init msmsdcc_init(void)
6945{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006946#if defined(CONFIG_DEBUG_FS)
6947 int ret = 0;
6948 ret = msmsdcc_dbg_init();
6949 if (ret) {
6950 pr_err("Failed to create debug fs dir \n");
6951 return ret;
6952 }
6953#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006954 return platform_driver_register(&msmsdcc_driver);
6955}
San Mehat9d2bd732009-09-22 16:44:22 -07006956
San Mehat9d2bd732009-09-22 16:44:22 -07006957static void __exit msmsdcc_exit(void)
6958{
6959 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006960
6961#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006962 debugfs_remove(debugfs_dir);
6963#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006964}
6965
6966module_init(msmsdcc_init);
6967module_exit(msmsdcc_exit);
6968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006969MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006970MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006971
6972#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05306973static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006974{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306975 struct msmsdcc_host *host = data;
6976
6977 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006978 return 0;
6979}
6980
Pratibhasagar V713817b2012-09-07 11:28:30 +05306981static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006982{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306983 struct msmsdcc_host *host = data;
6984 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006985
Pratibhasagar V713817b2012-09-07 11:28:30 +05306986 spin_lock_irqsave(&host->lock, flags);
6987 host->idle_tout = (u32)val * 1000;
6988 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006989
Pratibhasagar V713817b2012-09-07 11:28:30 +05306990 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006991}
6992
Pratibhasagar V713817b2012-09-07 11:28:30 +05306993DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
6994 msmsdcc_dbg_idle_tout_get,
6995 msmsdcc_dbg_idle_tout_set,
6996 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006997
Pratibhasagar V889d61c2012-09-09 19:51:14 +05306998static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
6999{
7000 struct msmsdcc_host *host = data;
7001
7002 *val = (u64) host->enforce_pio_mode;
7003 return 0;
7004}
7005
7006static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
7007{
7008 struct msmsdcc_host *host = data;
7009 unsigned long flags;
7010
7011 spin_lock_irqsave(&host->lock, flags);
7012 host->enforce_pio_mode = !!val;
7013 spin_unlock_irqrestore(&host->lock, flags);
7014
7015 return 0;
7016}
7017
7018DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
7019 msmsdcc_dbg_pio_mode_get,
7020 msmsdcc_dbg_pio_mode_set,
7021 "%llu\n");
7022
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307023static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
7024{
7025 struct msmsdcc_host *host = data;
7026
7027 *val = !!host->print_pm_stats;
7028 return 0;
7029}
7030
7031static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
7032{
7033 struct msmsdcc_host *host = data;
7034 unsigned long flags;
7035
7036 spin_lock_irqsave(&host->lock, flags);
7037 host->print_pm_stats = !!val;
7038 spin_unlock_irqrestore(&host->lock, flags);
7039
7040 return 0;
7041}
7042
7043DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
7044 msmsdcc_dbg_pm_stats_get,
7045 msmsdcc_dbg_pm_stats_set,
7046 "%llu\n");
7047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007048static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
7049{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307050 int err = 0;
7051
7052 if (!debugfs_dir)
7053 return;
7054
7055 host->debugfs_host_dir = debugfs_create_dir(
7056 mmc_hostname(host->mmc), debugfs_dir);
7057 if (IS_ERR(host->debugfs_host_dir)) {
7058 err = PTR_ERR(host->debugfs_host_dir);
7059 host->debugfs_host_dir = NULL;
7060 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
7061 mmc_hostname(host->mmc), err);
7062 return;
7063 }
7064
7065 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
7066 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7067 &msmsdcc_dbg_idle_tout_ops);
7068
7069 if (IS_ERR(host->debugfs_idle_tout)) {
7070 err = PTR_ERR(host->debugfs_idle_tout);
7071 host->debugfs_idle_tout = NULL;
7072 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
7073 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007074 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307075
7076 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
7077 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7078 &msmsdcc_dbg_pio_mode_ops);
7079
7080 if (IS_ERR(host->debugfs_pio_mode)) {
7081 err = PTR_ERR(host->debugfs_pio_mode);
7082 host->debugfs_pio_mode = NULL;
7083 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
7084 mmc_hostname(host->mmc), err);
7085 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307086
7087 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
7088 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7089 &msmsdcc_dbg_pm_stats_ops);
7090 if (IS_ERR(host->debugfs_pm_stats)) {
7091 err = PTR_ERR(host->debugfs_pm_stats);
7092 host->debugfs_pm_stats = NULL;
7093 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
7094 mmc_hostname(host->mmc), err);
7095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007096}
7097
7098static int __init msmsdcc_dbg_init(void)
7099{
7100 int err;
7101
Pratibhasagar V713817b2012-09-07 11:28:30 +05307102 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007103 if (IS_ERR(debugfs_dir)) {
7104 err = PTR_ERR(debugfs_dir);
7105 debugfs_dir = NULL;
7106 return err;
7107 }
7108
7109 return 0;
7110}
7111#endif