blob: ca186b17ee8307d98d6d16f0adb397b1bb003031 [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;
Subhash Jadavani34a47f02013-05-02 15:36:48 +0530961 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
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05304396static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
4397{
4398 int err = 0;
4399 unsigned long rate;
4400 struct msmsdcc_host *host = mmc_priv(mmc);
4401
4402 if (IS_ERR_OR_NULL(host->bus_clk))
4403 goto out;
4404
4405 switch (state) {
4406 case MMC_LOAD_HIGH:
4407 rate = MSMSDCC_BUS_VOTE_MAX_RATE;
4408 break;
4409 case MMC_LOAD_LOW:
4410 rate = MSMSDCC_BUS_VOTE_MIN_RATE;
4411 break;
4412 default:
4413 err = -EINVAL;
4414 goto out;
4415 }
4416
4417 if (rate != host->bus_clk_rate) {
4418 err = clk_set_rate(host->bus_clk, rate);
4419 if (err)
4420 pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
4421 mmc_hostname(mmc), __func__, rate, err);
4422 else
4423 host->bus_clk_rate = rate;
4424 }
4425out:
4426 return err;
4427}
4428
San Mehat9d2bd732009-09-22 16:44:22 -07004429static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004430 .enable = msmsdcc_enable,
4431 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304432 .pre_req = msmsdcc_pre_req,
4433 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004434 .request = msmsdcc_request,
4435 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004436 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004437 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304438 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304439 .execute_tuning = msmsdcc_execute_tuning,
4440 .hw_reset = msmsdcc_hw_reset,
Subhash Jadavanid076af72013-02-17 23:36:03 +02004441 .stop_request = msmsdcc_stop_request,
4442 .get_xfer_remain = msmsdcc_get_xfer_remain,
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05304443 .notify_load = msmsdcc_notify_load,
San Mehat9d2bd732009-09-22 16:44:22 -07004444};
4445
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304446static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4447{
4448 unsigned int gpio_no = host->plat->status_gpio;
4449 int status;
4450
4451 if (!gpio_is_valid(gpio_no))
4452 return;
4453
4454 status = gpio_request(gpio_no, "SD_HW_Detect");
4455 if (status)
4456 pr_err("%s: %s: gpio_request(%d) failed\n",
4457 mmc_hostname(host->mmc), __func__, gpio_no);
4458}
4459
4460static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4461{
4462 if (gpio_is_valid(host->plat->status_gpio))
4463 gpio_free(host->plat->status_gpio);
4464}
4465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004466static unsigned int
4467msmsdcc_slot_status(struct msmsdcc_host *host)
4468{
4469 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004470
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304471 status = gpio_get_value_cansleep(host->plat->status_gpio);
4472 if (host->plat->is_status_gpio_active_low)
4473 status = !status;
4474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004475 return status;
4476}
4477
San Mehat9d2bd732009-09-22 16:44:22 -07004478static void
4479msmsdcc_check_status(unsigned long data)
4480{
4481 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4482 unsigned int status;
4483
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304484 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004485 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004486 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004487 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004488 status = msmsdcc_slot_status(host);
4489
Krishna Konda941604a2012-01-10 17:46:34 -08004490 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004493 if (host->plat->status)
4494 pr_info("%s: Slot status change detected "
4495 "(%d -> %d)\n",
4496 mmc_hostname(host->mmc),
4497 host->oldstat, status);
4498 else if (host->plat->is_status_gpio_active_low)
4499 pr_info("%s: Slot status change detected "
4500 "(%d -> %d) and the card detect GPIO"
4501 " is ACTIVE_LOW\n",
4502 mmc_hostname(host->mmc),
4503 host->oldstat, status);
4504 else
4505 pr_info("%s: Slot status change detected "
4506 "(%d -> %d) and the card detect GPIO"
4507 " is ACTIVE_HIGH\n",
4508 mmc_hostname(host->mmc),
4509 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004510 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511 }
4512 host->oldstat = status;
4513 } else {
4514 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004515 }
San Mehat9d2bd732009-09-22 16:44:22 -07004516}
4517
4518static irqreturn_t
4519msmsdcc_platform_status_irq(int irq, void *dev_id)
4520{
4521 struct msmsdcc_host *host = dev_id;
4522
Girish K Sa3c76eb2011-10-11 11:44:09 +05304523 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004524 msmsdcc_check_status((unsigned long) host);
4525 return IRQ_HANDLED;
4526}
4527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528static irqreturn_t
4529msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4530{
4531 struct msmsdcc_host *host = dev_id;
4532
4533 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4534 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304535 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004536 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304537 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004538 wake_lock(&host->sdio_wlock);
4539 msmsdcc_disable_irq_wake(host);
4540 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304541 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004542 }
4543 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004544 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304545 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304546 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304547 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548 }
4549 spin_unlock(&host->lock);
4550
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304551out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 return IRQ_HANDLED;
4553}
4554
San Mehat9d2bd732009-09-22 16:44:22 -07004555static void
4556msmsdcc_status_notify_cb(int card_present, void *dev_id)
4557{
4558 struct msmsdcc_host *host = dev_id;
4559
Girish K Sa3c76eb2011-10-11 11:44:09 +05304560 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004561 card_present);
4562 msmsdcc_check_status((unsigned long) host);
4563}
4564
San Mehat9d2bd732009-09-22 16:44:22 -07004565static int
4566msmsdcc_init_dma(struct msmsdcc_host *host)
4567{
4568 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4569 host->dma.host = host;
4570 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004571 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004572
4573 if (!host->dmares)
4574 return -ENODEV;
4575
4576 host->dma.nc = dma_alloc_coherent(NULL,
4577 sizeof(struct msmsdcc_nc_dmadata),
4578 &host->dma.nc_busaddr,
4579 GFP_KERNEL);
4580 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004581 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004582 return -ENOMEM;
4583 }
4584 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4585 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4586 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4587 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4588 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004589 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004590
4591 return 0;
4592}
4593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004594#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4595/**
4596 * Allocate and Connect a SDCC peripheral's SPS endpoint
4597 *
4598 * This function allocates endpoint context and
4599 * connect it with memory endpoint by calling
4600 * appropriate SPS driver APIs.
4601 *
4602 * Also registers a SPS callback function with
4603 * SPS driver
4604 *
4605 * This function should only be called once typically
4606 * during driver probe.
4607 *
4608 * @host - Pointer to sdcc host structure
4609 * @ep - Pointer to sps endpoint data structure
4610 * @is_produce - 1 means Producer endpoint
4611 * 0 means Consumer endpoint
4612 *
4613 * @return - 0 if successful else negative value.
4614 *
4615 */
4616static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4617 struct msmsdcc_sps_ep_conn_data *ep,
4618 bool is_producer)
4619{
4620 int rc = 0;
4621 struct sps_pipe *sps_pipe_handle;
4622 struct sps_connect *sps_config = &ep->config;
4623 struct sps_register_event *sps_event = &ep->event;
4624
4625 /* Allocate endpoint context */
4626 sps_pipe_handle = sps_alloc_endpoint();
4627 if (!sps_pipe_handle) {
4628 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4629 mmc_hostname(host->mmc), is_producer);
4630 rc = -ENOMEM;
4631 goto out;
4632 }
4633
4634 /* Get default connection configuration for an endpoint */
4635 rc = sps_get_config(sps_pipe_handle, sps_config);
4636 if (rc) {
4637 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4638 " rc=%d", mmc_hostname(host->mmc),
4639 (u32)sps_pipe_handle, rc);
4640 goto get_config_err;
4641 }
4642
4643 /* Modify the default connection configuration */
4644 if (is_producer) {
4645 /*
4646 * For SDCC producer transfer, source should be
4647 * SDCC peripheral where as destination should
4648 * be system memory.
4649 */
4650 sps_config->source = host->sps.bam_handle;
4651 sps_config->destination = SPS_DEV_HANDLE_MEM;
4652 /* Producer pipe will handle this connection */
4653 sps_config->mode = SPS_MODE_SRC;
4654 sps_config->options =
4655 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4656 } else {
4657 /*
4658 * For SDCC consumer transfer, source should be
4659 * system memory where as destination should
4660 * SDCC peripheral
4661 */
4662 sps_config->source = SPS_DEV_HANDLE_MEM;
4663 sps_config->destination = host->sps.bam_handle;
4664 sps_config->mode = SPS_MODE_DEST;
4665 sps_config->options =
4666 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4667 }
4668
4669 /* Producer pipe index */
4670 sps_config->src_pipe_index = host->sps.src_pipe_index;
4671 /* Consumer pipe index */
4672 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4673 /*
4674 * This event thresold value is only significant for BAM-to-BAM
4675 * transfer. It's ignored for BAM-to-System mode transfer.
4676 */
4677 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304678
4679 /* Allocate maximum descriptor fifo size */
4680 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4681 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004682 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4683 sps_config->desc.size,
4684 &sps_config->desc.phys_base,
4685 GFP_KERNEL);
4686
Pratibhasagar V00b94332011-10-18 14:57:27 +05304687 if (!sps_config->desc.base) {
4688 rc = -ENOMEM;
4689 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4690 , mmc_hostname(host->mmc));
4691 goto get_config_err;
4692 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4694
4695 /* Establish connection between peripheral and memory endpoint */
4696 rc = sps_connect(sps_pipe_handle, sps_config);
4697 if (rc) {
4698 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4699 " rc=%d", mmc_hostname(host->mmc),
4700 (u32)sps_pipe_handle, rc);
4701 goto sps_connect_err;
4702 }
4703
4704 sps_event->mode = SPS_TRIGGER_CALLBACK;
4705 sps_event->options = SPS_O_EOT;
4706 sps_event->callback = msmsdcc_sps_complete_cb;
4707 sps_event->xfer_done = NULL;
4708 sps_event->user = (void *)host;
4709
4710 /* Register callback event for EOT (End of transfer) event. */
4711 rc = sps_register_event(sps_pipe_handle, sps_event);
4712 if (rc) {
4713 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4714 " rc=%d", mmc_hostname(host->mmc),
4715 (u32)sps_pipe_handle, rc);
4716 goto reg_event_err;
4717 }
4718 /* Now save the sps pipe handle */
4719 ep->pipe_handle = sps_pipe_handle;
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004720 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"\
4721 " desc_fifo.phys_base=%pa\n", mmc_hostname(host->mmc),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004722 __func__, is_producer ? "READ" : "WRITE",
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004723 (u32)sps_pipe_handle, &sps_config->desc.phys_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004724 goto out;
4725
4726reg_event_err:
4727 sps_disconnect(sps_pipe_handle);
4728sps_connect_err:
4729 dma_free_coherent(mmc_dev(host->mmc),
4730 sps_config->desc.size,
4731 sps_config->desc.base,
4732 sps_config->desc.phys_base);
4733get_config_err:
4734 sps_free_endpoint(sps_pipe_handle);
4735out:
4736 return rc;
4737}
4738
4739/**
4740 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4741 *
4742 * This function disconnect endpoint and deallocates
4743 * endpoint context.
4744 *
4745 * This function should only be called once typically
4746 * during driver remove.
4747 *
4748 * @host - Pointer to sdcc host structure
4749 * @ep - Pointer to sps endpoint data structure
4750 *
4751 */
4752static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4753 struct msmsdcc_sps_ep_conn_data *ep)
4754{
4755 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4756 struct sps_connect *sps_config = &ep->config;
4757 struct sps_register_event *sps_event = &ep->event;
4758
4759 sps_event->xfer_done = NULL;
4760 sps_event->callback = NULL;
4761 sps_register_event(sps_pipe_handle, sps_event);
4762 sps_disconnect(sps_pipe_handle);
4763 dma_free_coherent(mmc_dev(host->mmc),
4764 sps_config->desc.size,
4765 sps_config->desc.base,
4766 sps_config->desc.phys_base);
4767 sps_free_endpoint(sps_pipe_handle);
4768}
4769
4770/**
4771 * Reset SDCC peripheral's SPS endpoint
4772 *
4773 * This function disconnects an endpoint.
4774 *
4775 * This function should be called for reseting
4776 * SPS endpoint when data transfer error is
4777 * encountered during data transfer. This
4778 * can be considered as soft reset to endpoint.
4779 *
4780 * This function should only be called if
4781 * msmsdcc_sps_init() is already called.
4782 *
4783 * @host - Pointer to sdcc host structure
4784 * @ep - Pointer to sps endpoint data structure
4785 *
4786 * @return - 0 if successful else negative value.
4787 */
4788static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4789 struct msmsdcc_sps_ep_conn_data *ep)
4790{
4791 int rc = 0;
4792 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4793
4794 rc = sps_disconnect(sps_pipe_handle);
4795 if (rc) {
4796 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4797 " rc=%d", mmc_hostname(host->mmc), __func__,
4798 (u32)sps_pipe_handle, rc);
4799 goto out;
4800 }
4801 out:
4802 return rc;
4803}
4804
4805/**
4806 * Restore SDCC peripheral's SPS endpoint
4807 *
4808 * This function connects an endpoint.
4809 *
4810 * This function should be called for restoring
4811 * SPS endpoint after data transfer error is
4812 * encountered during data transfer. This
4813 * can be considered as soft reset to endpoint.
4814 *
4815 * This function should only be called if
4816 * msmsdcc_sps_reset_ep() is called before.
4817 *
4818 * @host - Pointer to sdcc host structure
4819 * @ep - Pointer to sps endpoint data structure
4820 *
4821 * @return - 0 if successful else negative value.
4822 */
4823static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4824 struct msmsdcc_sps_ep_conn_data *ep)
4825{
4826 int rc = 0;
4827 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4828 struct sps_connect *sps_config = &ep->config;
4829 struct sps_register_event *sps_event = &ep->event;
4830
4831 /* Establish connection between peripheral and memory endpoint */
4832 rc = sps_connect(sps_pipe_handle, sps_config);
4833 if (rc) {
4834 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4835 " rc=%d", mmc_hostname(host->mmc), __func__,
4836 (u32)sps_pipe_handle, rc);
4837 goto out;
4838 }
4839
4840 /* Register callback event for EOT (End of transfer) event. */
4841 rc = sps_register_event(sps_pipe_handle, sps_event);
4842 if (rc) {
4843 pr_err("%s: %s: sps_register_event() failed!!!"
4844 " pipe_handle=0x%x, rc=%d",
4845 mmc_hostname(host->mmc), __func__,
4846 (u32)sps_pipe_handle, rc);
4847 goto reg_event_err;
4848 }
4849 goto out;
4850
4851reg_event_err:
4852 sps_disconnect(sps_pipe_handle);
4853out:
4854 return rc;
4855}
4856
4857/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004858 * Handle BAM device's global error condition
4859 *
4860 * This is an error handler for the SDCC bam device
4861 *
4862 * This function is registered as a callback with SPS-BAM
4863 * driver and will called in case there are an errors for
4864 * the SDCC BAM deivce. Any error conditions in the BAM
4865 * device are global and will be result in this function
4866 * being called once per device.
4867 *
4868 * This function will be called from the sps driver's
4869 * interrupt context.
4870 *
4871 * @sps_cb_case - indicates what error it is
4872 * @user - Pointer to sdcc host structure
4873 */
4874static void
4875msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4876{
4877 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4878 struct mmc_request *mrq;
4879 unsigned long flags;
4880 int32_t error = 0;
4881
4882 BUG_ON(!host);
4883 BUG_ON(!is_sps_mode(host));
4884
4885 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004886 /* Reset all endpoints along with resetting bam. */
4887 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004888
4889 pr_err("%s: BAM Global ERROR IRQ happened\n",
4890 mmc_hostname(host->mmc));
4891 error = EAGAIN;
4892 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4893 /**
4894 * This means that there was an AHB access error and
4895 * the address we are trying to read/write is something
4896 * we dont have priviliges to do so.
4897 */
4898 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4899 mmc_hostname(host->mmc));
4900 error = EACCES;
4901 } else {
4902 /**
4903 * This should not have happened ideally. If this happens
4904 * there is some seriously wrong.
4905 */
4906 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4907 mmc_hostname(host->mmc), (u32) sps_cb_case);
4908 error = EIO;
4909 }
4910
4911 spin_lock_irqsave(&host->lock, flags);
4912
4913 mrq = host->curr.mrq;
4914
4915 if (mrq && mrq->cmd) {
4916 msmsdcc_dump_sdcc_state(host);
4917
4918 if (!mrq->cmd->error)
4919 mrq->cmd->error = -error;
4920 if (host->curr.data) {
4921 if (mrq->data && !mrq->data->error)
4922 mrq->data->error = -error;
4923 host->curr.data_xfered = 0;
4924 if (host->sps.sg && is_sps_mode(host)) {
4925 /* Stop current SPS transfer */
4926 msmsdcc_sps_exit_curr_xfer(host);
4927 } else {
4928 /* this condition should not have happened */
4929 pr_err("%s: something is seriously wrong. "\
4930 "Funtion: %s, line: %d\n",
4931 mmc_hostname(host->mmc),
4932 __func__, __LINE__);
4933 }
4934 } else {
4935 /* this condition should not have happened */
4936 pr_err("%s: something is seriously wrong. Funtion: "\
4937 "%s, line: %d\n", mmc_hostname(host->mmc),
4938 __func__, __LINE__);
4939 }
4940 }
4941 spin_unlock_irqrestore(&host->lock, flags);
4942}
4943
4944/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945 * Initialize SPS HW connected with SDCC core
4946 *
4947 * This function register BAM HW resources with
4948 * SPS driver and then initialize 2 SPS endpoints
4949 *
4950 * This function should only be called once typically
4951 * during driver probe.
4952 *
4953 * @host - Pointer to sdcc host structure
4954 *
4955 * @return - 0 if successful else negative value.
4956 *
4957 */
4958static int msmsdcc_sps_init(struct msmsdcc_host *host)
4959{
4960 int rc = 0;
4961 struct sps_bam_props bam = {0};
4962
4963 host->bam_base = ioremap(host->bam_memres->start,
4964 resource_size(host->bam_memres));
4965 if (!host->bam_base) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004966 pr_err("%s: BAM ioremap() failed!!! resource: %pr\n",
4967 mmc_hostname(host->mmc), host->bam_memres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004968 rc = -ENOMEM;
4969 goto out;
4970 }
4971
4972 bam.phys_addr = host->bam_memres->start;
4973 bam.virt_addr = host->bam_base;
4974 /*
4975 * This event thresold value is only significant for BAM-to-BAM
4976 * transfer. It's ignored for BAM-to-System mode transfer.
4977 */
4978 bam.event_threshold = 0x10; /* Pipe event threshold */
4979 /*
4980 * This threshold controls when the BAM publish
4981 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304982 * SPS HW will be used for data transfer size even
4983 * less than SDCC FIFO size. So let's set BAM summing
4984 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004985 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304986 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004987 /* SPS driver wll handle the SDCC BAM IRQ */
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004988 bam.irq = host->bam_irqres->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004989 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004990 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4991 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992
Krishna Kondacdff0902013-04-09 17:57:22 -07004993 /* bam reset messages will be limited to 5 times */
4994 bam.constrained_logging = true;
4995 bam.logging_number = 5;
4996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004997 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4998 (u32)bam.phys_addr);
4999 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
5000 (u32)bam.virt_addr);
5001
5002 /* Register SDCC Peripheral BAM device to SPS driver */
5003 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
5004 if (rc) {
5005 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
5006 mmc_hostname(host->mmc), rc);
5007 goto reg_bam_err;
5008 }
5009 pr_info("%s: BAM device registered. bam_handle=0x%x",
5010 mmc_hostname(host->mmc), host->sps.bam_handle);
5011
5012 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
5013 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
5014
5015 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
5016 SPS_PROD_PERIPHERAL);
5017 if (rc)
5018 goto sps_reset_err;
5019 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
5020 SPS_CONS_PERIPHERAL);
5021 if (rc)
5022 goto cons_conn_err;
5023
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005024 pr_info("%s: Qualcomm MSM SDCC-BAM at %pr %pr\n",
5025 mmc_hostname(host->mmc), host->bam_memres, host->bam_irqres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005026 goto out;
5027
5028cons_conn_err:
5029 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5030sps_reset_err:
5031 sps_deregister_bam_device(host->sps.bam_handle);
5032reg_bam_err:
5033 iounmap(host->bam_base);
5034out:
5035 return rc;
5036}
5037
5038/**
5039 * De-initialize SPS HW connected with SDCC core
5040 *
5041 * This function deinitialize SPS endpoints and then
5042 * deregisters BAM resources from SPS driver.
5043 *
5044 * This function should only be called once typically
5045 * during driver remove.
5046 *
5047 * @host - Pointer to sdcc host structure
5048 *
5049 */
5050static void msmsdcc_sps_exit(struct msmsdcc_host *host)
5051{
5052 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
5053 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5054 sps_deregister_bam_device(host->sps.bam_handle);
5055 iounmap(host->bam_base);
5056}
5057#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
5058
5059static ssize_t
5060show_polling(struct device *dev, struct device_attribute *attr, char *buf)
5061{
5062 struct mmc_host *mmc = dev_get_drvdata(dev);
5063 struct msmsdcc_host *host = mmc_priv(mmc);
5064 int poll;
5065 unsigned long flags;
5066
5067 spin_lock_irqsave(&host->lock, flags);
5068 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
5069 spin_unlock_irqrestore(&host->lock, flags);
5070
5071 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
5072}
5073
5074static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305075store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005076 const char *buf, size_t count)
5077{
5078 struct mmc_host *mmc = dev_get_drvdata(dev);
5079 struct msmsdcc_host *host = mmc_priv(mmc);
5080 int value;
5081 unsigned long flags;
5082
5083 sscanf(buf, "%d", &value);
5084
5085 spin_lock_irqsave(&host->lock, flags);
5086 if (value) {
5087 mmc->caps |= MMC_CAP_NEEDS_POLL;
5088 mmc_detect_change(host->mmc, 0);
5089 } else {
5090 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5091 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005092 spin_unlock_irqrestore(&host->lock, flags);
5093 return count;
5094}
5095
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305096static ssize_t
5097show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
5098 char *buf)
5099{
5100 struct mmc_host *mmc = dev_get_drvdata(dev);
5101 struct msmsdcc_host *host = mmc_priv(mmc);
5102
5103 return snprintf(buf, PAGE_SIZE, "%u\n",
5104 host->msm_bus_vote.is_max_bw_needed);
5105}
5106
5107static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305108store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305109 const char *buf, size_t count)
5110{
5111 struct mmc_host *mmc = dev_get_drvdata(dev);
5112 struct msmsdcc_host *host = mmc_priv(mmc);
5113 uint32_t value;
5114 unsigned long flags;
5115
5116 if (!kstrtou32(buf, 0, &value)) {
5117 spin_lock_irqsave(&host->lock, flags);
5118 host->msm_bus_vote.is_max_bw_needed = !!value;
5119 spin_unlock_irqrestore(&host->lock, flags);
5120 }
5121
5122 return count;
5123}
5124
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305125static ssize_t
5126show_idle_timeout(struct device *dev, struct device_attribute *attr,
5127 char *buf)
5128{
5129 struct mmc_host *mmc = dev_get_drvdata(dev);
5130 struct msmsdcc_host *host = mmc_priv(mmc);
5131
5132 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05305133 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305134}
5135
5136static ssize_t
5137store_idle_timeout(struct device *dev, struct device_attribute *attr,
5138 const char *buf, size_t count)
5139{
5140 struct mmc_host *mmc = dev_get_drvdata(dev);
5141 struct msmsdcc_host *host = mmc_priv(mmc);
5142 unsigned int long flags;
5143 int timeout; /* in secs */
5144
5145 if (!kstrtou32(buf, 0, &timeout)
5146 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
5147 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05305148 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305149 spin_unlock_irqrestore(&host->lock, flags);
5150 }
5151 return count;
5152}
5153
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305154static inline void set_auto_cmd_setting(struct device *dev,
5155 const char *buf,
5156 bool is_cmd19)
5157{
5158 struct mmc_host *mmc = dev_get_drvdata(dev);
5159 struct msmsdcc_host *host = mmc_priv(mmc);
5160 unsigned int long flags;
5161 int temp;
5162
5163 if (!kstrtou32(buf, 0, &temp)) {
5164 spin_lock_irqsave(&host->lock, flags);
5165 if (is_cmd19)
5166 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305167 else
5168 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305169 spin_unlock_irqrestore(&host->lock, flags);
5170 }
5171}
5172
5173static ssize_t
5174show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5175 char *buf)
5176{
5177 struct mmc_host *mmc = dev_get_drvdata(dev);
5178 struct msmsdcc_host *host = mmc_priv(mmc);
5179
5180 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
5181}
5182
5183static ssize_t
5184store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5185 const char *buf, size_t count)
5186{
5187 set_auto_cmd_setting(dev, buf, true);
5188
5189 return count;
5190}
5191
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305192static ssize_t
5193show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5194 char *buf)
5195{
5196 struct mmc_host *mmc = dev_get_drvdata(dev);
5197 struct msmsdcc_host *host = mmc_priv(mmc);
5198
5199 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5200}
5201
5202static ssize_t
5203store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5204 const char *buf, size_t count)
5205{
5206 set_auto_cmd_setting(dev, buf, false);
5207
5208 return count;
5209}
5210
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305211static void msmsdcc_print_regs(const char *name, void __iomem *base,
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005212 resource_size_t phys_base,
5213 unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305214{
5215 unsigned int i;
5216
5217 if (!base)
5218 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305219
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005220 pr_err("===== %s: Register Dumps @phys_base=%pa, @virt_base=0x%x"\
5221 " =====\n", name, &phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305222 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305223 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305224 (u32)readl_relaxed(base + i*4),
5225 (u32)readl_relaxed(base + ((i+1)*4)),
5226 (u32)readl_relaxed(base + ((i+2)*4)),
5227 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305228 }
5229}
5230
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305231/*
5232 * This function prints the testbus debug output for all the
5233 * available SDCC controller test bus.
5234 *
5235 * Note: This function should only be called if the SDCC is clocked.
5236 */
5237static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
5238{
5239 int testbus_num;
5240
5241 if (!is_testbus_debug(host))
5242 return;
5243
5244 pr_err("== SDCC Test Bus Debug ==");
5245 for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
5246 writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
5247 | MCI_TESTBUS_ENA),
5248 host->base + MCI_TESTBUS_CONFIG);
5249 pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
5250 (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
5251 }
5252 /* Disable the test bus output */
5253 writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
5254}
5255
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305256static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5257{
5258 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305259 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305260 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305261 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305262 mmc_hostname(host->mmc),
5263 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305264 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305265 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305266 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5267
5268 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305269 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305270 msmsdcc_print_regs("SDCC-CORE", host->base,
5271 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305272 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5273 mmc_hostname(host->mmc),
5274 readl_relaxed(host->base + MCI_TEST_INPUT));
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305275 msmsdcc_print_testbus_info(host);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305276 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305277
5278 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305279 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305280 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305281 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305282 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305283 mmc_hostname(host->mmc), host->dma.busy,
5284 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305285 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305286 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305287 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5288 host->dml_memres->start,
5289 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305290 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305291 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305292 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305293
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305294 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305295 mmc_hostname(host->mmc), host->curr.xfer_size,
5296 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305297 }
5298
Krishna Konda3ca90f02012-08-29 16:29:21 -07005299 if (host->sps.reset_bam)
5300 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5301 mmc_hostname(host->mmc), host->sps.reset_bam);
5302
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305303 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305304 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5305 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5306 host->curr.got_dataend, host->prog_enable,
5307 host->curr.wait_for_auto_prog_done,
5308 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305309 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305310}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005312static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5313{
5314 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5315 struct mmc_request *mrq;
5316 unsigned long flags;
5317
5318 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005319 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005320 pr_info("%s: %s: dummy CMD52 timeout\n",
5321 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005322 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005323 }
5324
5325 mrq = host->curr.mrq;
5326
5327 if (mrq && mrq->cmd) {
Subhash Jadavani926a9cb2012-12-15 22:05:54 +05305328 if (!mrq->cmd->bkops_busy) {
5329 pr_info("%s: CMD%d: Request timeout\n",
5330 mmc_hostname(host->mmc), mrq->cmd->opcode);
5331 msmsdcc_dump_sdcc_state(host);
5332 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005334 if (!mrq->cmd->error)
5335 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305336 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005337 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005338 if (mrq->data && !mrq->data->error)
5339 mrq->data->error = -ETIMEDOUT;
5340 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305341 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005342 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305343 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005344 /* Stop current SPS transfer */
5345 msmsdcc_sps_exit_curr_xfer(host);
5346 } else {
5347 msmsdcc_reset_and_restore(host);
5348 msmsdcc_stop_data(host);
5349 if (mrq->data && mrq->data->stop)
5350 msmsdcc_start_command(host,
5351 mrq->data->stop, 0);
5352 else
5353 msmsdcc_request_end(host, mrq);
5354 }
5355 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305356 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305357 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005358 msmsdcc_reset_and_restore(host);
5359 msmsdcc_request_end(host, mrq);
5360 }
5361 }
5362 spin_unlock_irqrestore(&host->lock, flags);
5363}
5364
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305365/*
5366 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5367 *
5368 * @dev: device node from which the property value is to be read.
5369 * @prop_name: name of the property to be searched.
5370 * @out_array: filled array returned to caller
5371 * @len: filled array size returned to caller
5372 * @size: expected size of the array
5373 *
5374 * If expected "size" doesn't match with "len" an error is returned. If
5375 * expected size is zero, the length of actual array is returned provided
5376 * return value is zero.
5377 *
5378 * RETURNS:
5379 * zero on success, negative error if failed.
5380 */
5381static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5382 u32 **out_array, int *len, int size)
5383{
5384 int ret = 0;
5385 u32 *array = NULL;
5386 struct device_node *np = dev->of_node;
5387
5388 if (of_get_property(np, prop_name, len)) {
5389 size_t sz;
5390 sz = *len = *len / sizeof(*array);
5391
5392 if (sz > 0 && !(size > 0 && (sz != size))) {
5393 array = devm_kzalloc(dev, sz * sizeof(*array),
5394 GFP_KERNEL);
5395 if (!array) {
5396 dev_err(dev, "%s: no memory\n", prop_name);
5397 ret = -ENOMEM;
5398 goto out;
5399 }
5400
5401 ret = of_property_read_u32_array(np, prop_name,
5402 array, sz);
5403 if (ret < 0) {
5404 dev_err(dev, "%s: error reading array %d\n",
5405 prop_name, ret);
5406 goto out;
5407 }
5408 } else {
5409 dev_err(dev, "%s invalid size\n", prop_name);
5410 ret = -EINVAL;
5411 goto out;
5412 }
5413 } else {
5414 dev_err(dev, "%s not specified\n", prop_name);
5415 ret = -EINVAL;
5416 goto out;
5417 }
5418 *out_array = array;
5419out:
5420 if (ret)
5421 *len = 0;
5422 return ret;
5423}
5424
5425static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5426 struct msm_mmc_pad_pull_data **pad_pull_data)
5427{
5428 int ret = 0, base = 0, len, i;
5429 u32 *tmp;
5430 struct msm_mmc_pad_pull_data *pull_data;
5431 struct msm_mmc_pad_pull *pull;
5432
5433 switch (id) {
5434 case 1:
5435 base = TLMM_PULL_SDC1_CLK;
5436 break;
5437 case 2:
5438 base = TLMM_PULL_SDC2_CLK;
5439 break;
5440 case 3:
5441 base = TLMM_PULL_SDC3_CLK;
5442 break;
5443 case 4:
5444 base = TLMM_PULL_SDC4_CLK;
5445 break;
5446 default:
5447 dev_err(dev, "%s: Invalid slot id\n", __func__);
5448 ret = -EINVAL;
5449 goto err;
5450 }
5451
5452 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5453 GFP_KERNEL);
5454 if (!pull_data) {
5455 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5456 ret = -ENOMEM;
5457 goto err;
5458 }
5459 pull_data->size = 3; /* array size for clk, cmd, data */
5460
5461 /* Allocate on, off configs for clk, cmd, data */
5462 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5463 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5464 if (!pull) {
5465 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5466 ret = -ENOMEM;
5467 goto err;
5468 }
5469 pull_data->on = pull;
5470 pull_data->off = pull + pull_data->size;
5471
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005472 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305473 &tmp, &len, pull_data->size);
5474 if (!ret) {
5475 for (i = 0; i < len; i++) {
5476 pull_data->on[i].no = base + i;
5477 pull_data->on[i].val = tmp[i];
5478 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5479 i, pull_data->on[i].val);
5480 }
5481 } else {
5482 goto err;
5483 }
5484
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005485 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305486 &tmp, &len, pull_data->size);
5487 if (!ret) {
5488 for (i = 0; i < len; i++) {
5489 pull_data->off[i].no = base + i;
5490 pull_data->off[i].val = tmp[i];
5491 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5492 i, pull_data->off[i].val);
5493 }
5494 } else {
5495 goto err;
5496 }
5497
5498 *pad_pull_data = pull_data;
5499err:
5500 return ret;
5501}
5502
5503static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5504 struct msm_mmc_pad_drv_data **pad_drv_data)
5505{
5506 int ret = 0, base = 0, len, i;
5507 u32 *tmp;
5508 struct msm_mmc_pad_drv_data *drv_data;
5509 struct msm_mmc_pad_drv *drv;
5510
5511 switch (id) {
5512 case 1:
5513 base = TLMM_HDRV_SDC1_CLK;
5514 break;
5515 case 2:
5516 base = TLMM_HDRV_SDC2_CLK;
5517 break;
5518 case 3:
5519 base = TLMM_HDRV_SDC3_CLK;
5520 break;
5521 case 4:
5522 base = TLMM_HDRV_SDC4_CLK;
5523 break;
5524 default:
5525 dev_err(dev, "%s: Invalid slot id\n", __func__);
5526 ret = -EINVAL;
5527 goto err;
5528 }
5529
5530 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5531 GFP_KERNEL);
5532 if (!drv_data) {
5533 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5534 ret = -ENOMEM;
5535 goto err;
5536 }
5537 drv_data->size = 3; /* array size for clk, cmd, data */
5538
5539 /* Allocate on, off configs for clk, cmd, data */
5540 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5541 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5542 if (!drv) {
5543 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5544 ret = -ENOMEM;
5545 goto err;
5546 }
5547 drv_data->on = drv;
5548 drv_data->off = drv + drv_data->size;
5549
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005550 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305551 &tmp, &len, drv_data->size);
5552 if (!ret) {
5553 for (i = 0; i < len; i++) {
5554 drv_data->on[i].no = base + i;
5555 drv_data->on[i].val = tmp[i];
5556 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5557 i, drv_data->on[i].val);
5558 }
5559 } else {
5560 goto err;
5561 }
5562
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005563 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305564 &tmp, &len, drv_data->size);
5565 if (!ret) {
5566 for (i = 0; i < len; i++) {
5567 drv_data->off[i].no = base + i;
5568 drv_data->off[i].val = tmp[i];
5569 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5570 i, drv_data->off[i].val);
5571 }
5572 } else {
5573 goto err;
5574 }
5575
5576 *pad_drv_data = drv_data;
5577err:
5578 return ret;
5579}
5580
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305581static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5582 struct mmc_platform_data *pdata)
5583{
5584 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5585 struct device_node *np = dev->of_node;
5586
5587 pdata->status_gpio = of_get_named_gpio_flags(np,
5588 "cd-gpios", 0, &flags);
5589 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005590 struct platform_device *pdev = container_of(dev,
5591 struct platform_device, dev);
5592 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305593 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5594 }
5595
5596 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5597 "wp-gpios", 0, &flags);
5598 if (gpio_is_valid(pdata->wpswitch_gpio))
5599 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5600}
5601
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305602static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5603 struct mmc_platform_data *pdata)
5604{
5605 int ret = 0, id = 0, cnt, i;
5606 struct msm_mmc_pin_data *pin_data;
5607 struct device_node *np = dev->of_node;
5608
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305609 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5610
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305611 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5612 if (!pin_data) {
5613 dev_err(dev, "No memory for pin_data\n");
5614 ret = -ENOMEM;
5615 goto err;
5616 }
5617
5618 cnt = of_gpio_count(np);
5619 if (cnt > 0) {
5620 pin_data->is_gpio = true;
5621
5622 pin_data->gpio_data = devm_kzalloc(dev,
5623 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5624 if (!pin_data->gpio_data) {
5625 dev_err(dev, "No memory for gpio_data\n");
5626 ret = -ENOMEM;
5627 goto err;
5628 }
5629 pin_data->gpio_data->size = cnt;
5630 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5631 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5632 if (!pin_data->gpio_data->gpio) {
5633 dev_err(dev, "No memory for gpio\n");
5634 ret = -ENOMEM;
5635 goto err;
5636 }
5637
5638 for (i = 0; i < cnt; i++) {
5639 const char *name = NULL;
5640 char result[32];
5641 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5642 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005643 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305644
5645 snprintf(result, 32, "%s-%s",
5646 dev_name(dev), name ? name : "?");
5647 pin_data->gpio_data->gpio[i].name = result;
5648 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5649 pin_data->gpio_data->gpio[i].name,
5650 pin_data->gpio_data->gpio[i].no);
5651 }
5652 } else {
5653 pin_data->pad_data = devm_kzalloc(dev,
5654 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5655 if (!pin_data->pad_data) {
5656 dev_err(dev, "No memory for pin_data->pad_data\n");
5657 ret = -ENOMEM;
5658 goto err;
5659 }
5660
5661 of_property_read_u32(np, "cell-index", &id);
5662
5663 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5664 &pin_data->pad_data->pull);
5665 if (ret)
5666 goto err;
5667 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5668 &pin_data->pad_data->drv);
5669 if (ret)
5670 goto err;
5671 }
5672
5673 pdata->pin_data = pin_data;
5674err:
5675 if (ret)
5676 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5677 return ret;
5678}
5679
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305680#define MAX_PROP_SIZE 32
5681static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5682 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5683{
5684 int len, ret = 0;
5685 const __be32 *prop;
5686 char prop_name[MAX_PROP_SIZE];
5687 struct msm_mmc_reg_data *vreg;
5688 struct device_node *np = dev->of_node;
5689
5690 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5691 if (of_parse_phandle(np, prop_name, 0)) {
5692 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5693 if (!vreg) {
5694 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5695 ret = -ENOMEM;
5696 goto err;
5697 }
5698
5699 vreg->name = vreg_name;
5700
5701 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005702 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305703 if (of_get_property(np, prop_name, NULL))
5704 vreg->always_on = true;
5705
5706 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005707 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305708 if (of_get_property(np, prop_name, NULL))
5709 vreg->lpm_sup = true;
5710
5711 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005712 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305713 prop = of_get_property(np, prop_name, &len);
5714 if (!prop || (len != (2 * sizeof(__be32)))) {
5715 dev_warn(dev, "%s %s property\n",
5716 prop ? "invalid format" : "no", prop_name);
5717 } else {
5718 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5719 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5720 }
5721
5722 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005723 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305724 prop = of_get_property(np, prop_name, &len);
5725 if (!prop || (len != (2 * sizeof(__be32)))) {
5726 dev_warn(dev, "%s %s property\n",
5727 prop ? "invalid format" : "no", prop_name);
5728 } else {
5729 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5730 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5731 }
5732
5733 *vreg_data = vreg;
5734 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5735 vreg->name, vreg->always_on ? "always_on," : "",
5736 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5737 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5738 }
5739
5740err:
5741 return ret;
5742}
5743
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305744static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5745{
5746 int i, ret;
5747 struct mmc_platform_data *pdata;
5748 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305749 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005750 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305751 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305752
5753 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5754 if (!pdata) {
5755 dev_err(dev, "could not allocate memory for platform data\n");
5756 goto err;
5757 }
5758
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005759 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305760 if (bus_width == 8) {
5761 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5762 } else if (bus_width == 4) {
5763 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5764 } else {
5765 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5766 pdata->mmc_bus_width = 0;
5767 }
5768
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005769 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305770 &sup_voltages, &sup_volt_len, 0);
5771 if (!ret) {
5772 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305773 u32 mask;
5774
5775 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5776 sup_voltages[i + 1]);
5777 if (!mask)
5778 dev_err(dev, "Invalide voltage range %d\n", i);
5779 pdata->ocr_mask |= mask;
5780 }
5781 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305782 }
5783
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005784 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305785 &clk_table, &clk_table_len, 0);
5786 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305787 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305788 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305789 }
5790
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305791 pdata->vreg_data = devm_kzalloc(dev,
5792 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5793 if (!pdata->vreg_data) {
5794 dev_err(dev, "could not allocate memory for vreg_data\n");
5795 goto err;
5796 }
5797
5798 if (msmsdcc_dt_parse_vreg_info(dev,
5799 &pdata->vreg_data->vdd_data, "vdd"))
5800 goto err;
5801
5802 if (msmsdcc_dt_parse_vreg_info(dev,
5803 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5804 goto err;
5805
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305806 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5807 goto err;
5808
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005809 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305810
5811 for (i = 0; i < len; i++) {
5812 const char *name = NULL;
5813
5814 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005815 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305816 if (!name)
5817 continue;
5818
5819 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5820 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5821 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5822 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5823 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5824 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5825 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5826 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5827 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5828 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5829 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5830 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5831 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5832 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5833 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5834 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5835 | MMC_CAP_UHS_DDR50;
5836 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5837 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5838 | MMC_CAP_UHS_DDR50;
5839 }
5840
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005841 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305842 if (current_limit == 800)
5843 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5844 else if (current_limit == 600)
5845 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5846 else if (current_limit == 400)
5847 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5848 else if (current_limit == 200)
5849 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5850
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005851 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305852 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005853 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305854 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005855 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305856 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305857 of_property_read_u32(np, "qcom,dat1-mpm-int",
5858 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305859
5860 return pdata;
5861err:
5862 return NULL;
5863}
5864
San Mehat9d2bd732009-09-22 16:44:22 -07005865static int
5866msmsdcc_probe(struct platform_device *pdev)
5867{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305868 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005869 struct msmsdcc_host *host;
5870 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005871 unsigned long flags;
5872 struct resource *core_irqres = NULL;
5873 struct resource *bam_irqres = NULL;
5874 struct resource *core_memres = NULL;
5875 struct resource *dml_memres = NULL;
5876 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005877 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005878 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305879 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005880
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305881 if (pdev->dev.of_node) {
5882 plat = msmsdcc_populate_pdata(&pdev->dev);
5883 of_property_read_u32((&pdev->dev)->of_node,
5884 "cell-index", &pdev->id);
5885 } else {
5886 plat = pdev->dev.platform_data;
5887 }
San Mehat9d2bd732009-09-22 16:44:22 -07005888
5889 /* must have platform data */
5890 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005891 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005892 ret = -EINVAL;
5893 goto out;
5894 }
5895
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -08005896 if (disable_slots & (1 << (pdev->id - 1))) {
5897 pr_info("%s: Slot %d disabled\n", __func__, pdev->id);
5898 return -ENODEV;
5899 }
5900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005901 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005902 return -EINVAL;
5903
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305904 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5905 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5906 return -EINVAL;
5907 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005908
San Mehat9d2bd732009-09-22 16:44:22 -07005909 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005910 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005911 return -ENXIO;
5912 }
5913
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305914 core_memres = platform_get_resource_byname(pdev,
5915 IORESOURCE_MEM, "core_mem");
5916 bam_memres = platform_get_resource_byname(pdev,
5917 IORESOURCE_MEM, "bam_mem");
5918 dml_memres = platform_get_resource_byname(pdev,
5919 IORESOURCE_MEM, "dml_mem");
5920 core_irqres = platform_get_resource_byname(pdev,
5921 IORESOURCE_IRQ, "core_irq");
5922 bam_irqres = platform_get_resource_byname(pdev,
5923 IORESOURCE_IRQ, "bam_irq");
5924 dmares = platform_get_resource_byname(pdev,
5925 IORESOURCE_DMA, "dma_chnl");
5926 dma_crci_res = platform_get_resource_byname(pdev,
5927 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005929 if (!core_irqres || !core_memres) {
5930 pr_err("%s: Invalid sdcc core resource\n", __func__);
5931 return -ENXIO;
5932 }
5933
5934 /*
5935 * Both BAM and DML memory resource should be preset.
5936 * BAM IRQ resource should also be present.
5937 */
5938 if ((bam_memres && !dml_memres) ||
5939 (!bam_memres && dml_memres) ||
5940 ((bam_memres && dml_memres) && !bam_irqres)) {
5941 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005942 return -ENXIO;
5943 }
5944
5945 /*
5946 * Setup our host structure
5947 */
San Mehat9d2bd732009-09-22 16:44:22 -07005948 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5949 if (!mmc) {
5950 ret = -ENOMEM;
5951 goto out;
5952 }
5953
5954 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305955 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005956 host->plat = plat;
5957 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005958 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305959
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305960 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305961 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005962 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305963 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005965 host->base = ioremap(core_memres->start,
5966 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005967 if (!host->base) {
5968 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305969 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005970 }
5971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005972 host->core_irqres = core_irqres;
5973 host->bam_irqres = bam_irqres;
5974 host->core_memres = core_memres;
5975 host->dml_memres = dml_memres;
5976 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005977 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005978 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005979 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305980 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005982#ifdef CONFIG_MMC_EMBEDDED_SDIO
5983 if (plat->embedded_sdio)
5984 mmc_set_embedded_sdio_data(mmc,
5985 &plat->embedded_sdio->cis,
5986 &plat->embedded_sdio->cccr,
5987 plat->embedded_sdio->funcs,
5988 plat->embedded_sdio->num_funcs);
5989#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005990
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305991 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5992 (unsigned long)host);
5993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005994 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5995 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305996 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005997 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305998 ret = msmsdcc_init_dma(host);
5999 if (ret)
6000 goto ioremap_free;
6001 } else {
6002 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07006003 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05306004 }
San Mehat9d2bd732009-09-22 16:44:22 -07006005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006006 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306007 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006008 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306009 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
6010 if (!IS_ERR_OR_NULL(host->bus_clk)) {
6011 /* Vote for max. clk rate for max. performance */
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05306012 ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306013 if (ret)
6014 goto bus_clk_put;
6015 ret = clk_prepare_enable(host->bus_clk);
6016 if (ret)
6017 goto bus_clk_put;
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05306018 host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
San Mehat9d2bd732009-09-22 16:44:22 -07006019 }
6020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006021 /*
6022 * Setup main peripheral bus clock
6023 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006024 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006025 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05306026 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006027 if (ret)
6028 goto pclk_put;
6029
6030 host->pclk_rate = clk_get_rate(host->pclk);
6031 }
6032
6033 /*
6034 * Setup SDC MMC clock
6035 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006036 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07006037 if (IS_ERR(host->clk)) {
6038 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006039 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07006040 }
6041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006042 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05306043 if (ret) {
6044 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
6045 goto clk_put;
6046 }
6047
Asutosh Dasf5298c32012-04-03 14:51:47 +05306048 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006049 if (ret)
6050 goto clk_put;
6051
San Mehat9d2bd732009-09-22 16:44:22 -07006052 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306053 if (!host->clk_rate)
6054 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05306055
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306056 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05306057 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306058
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306059 /*
6060 * Set the register write delay according to min. clock frequency
6061 * supported and update later when the host->clk_rate changes.
6062 */
6063 host->reg_write_delay =
6064 (1 + ((3 * USEC_PER_SEC) /
6065 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006066
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306067 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05306068 /* Apply Hard reset to SDCC to put it in power on default state */
6069 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006070
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006071#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306072 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006073 if (host->plat->cpu_dma_latency)
6074 host->cpu_dma_latency = host->plat->cpu_dma_latency;
6075 else
6076 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
6077 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306078 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
6079
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306080 ret = msmsdcc_msm_bus_register(host);
6081 if (ret)
6082 goto pm_qos_remove;
6083
6084 if (host->msm_bus_vote.client_handle)
6085 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
6086 msmsdcc_msm_bus_work);
6087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006088 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07006089 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006090 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07006091 goto clk_disable;
6092 }
6093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006094
6095 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306096 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006097 /* Initialize SPS */
6098 ret = msmsdcc_sps_init(host);
6099 if (ret)
6100 goto vreg_deinit;
6101 /* Initialize DML */
6102 ret = msmsdcc_dml_init(host);
6103 if (ret)
6104 goto sps_exit;
6105 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05306106 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07006107
San Mehat9d2bd732009-09-22 16:44:22 -07006108 /*
6109 * Setup MMC host structure
6110 */
6111 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006112 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
6113 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006114 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05306115 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
6116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006117 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
6118 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07006119 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05306120 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05306121 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306122 /*
6123 * If we send the CMD23 before multi block write/read command
6124 * then we need not to send CMD12 at the end of the transfer.
6125 * If we don't send the CMD12 then only way to detect the PROG_DONE
6126 * status is to use the AUTO_PROG_DONE status provided by SDCC4
6127 * controller. So let's enable the CMD23 for SDCC4 only.
6128 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306129 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306130 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07006131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006132 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05306133 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006134 /*
6135 * XPC controls the maximum current in the default speed mode of SDXC
6136 * card. XPC=0 means 100mA (max.) but speed class is not supported.
6137 * XPC=1 means 150mA (max.) and speed class is supported.
6138 */
6139 if (plat->xpc_cap)
6140 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
6141 MMC_CAP_SET_XPC_180);
6142
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02006143 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02006144 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05306145 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03006146 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03006147 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02006148 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Konstantin Dorfmana2c84222013-03-12 15:33:53 +02006149 mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
Subhash Jadavani69245882013-05-27 16:58:41 +05306150 mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
Yaniv Gardi14098552012-06-04 10:56:03 +03006151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006152 if (plat->nonremovable)
6153 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006154 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006155
6156 if (plat->is_sdio_al_client)
6157 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07006158
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306159 mmc->max_segs = msmsdcc_get_nr_sg(host);
6160 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
6161 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07006162
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306163 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07006164 mmc->max_seg_size = mmc->max_req_size;
6165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006166 writel_relaxed(0, host->base + MMCIMASK0);
6167 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05306168 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006170 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
6171 mb();
6172 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07006173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006174 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
6175 DRIVER_NAME " (cmd)", host);
6176 if (ret)
6177 goto dml_exit;
6178
6179 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
6180 DRIVER_NAME " (pio)", host);
6181 if (ret)
6182 goto irq_free;
6183
6184 /*
6185 * Enable SDCC IRQ only when host is powered on. Otherwise, this
6186 * IRQ is un-necessarily being monitored by MPM (Modem power
6187 * management block) during idle-power collapse. The MPM will be
6188 * configured to monitor the DATA1 GPIO line with level-low trigger
6189 * and thus depending on the GPIO status, it prevents TCXO shutdown
6190 * during idle-power collapse.
6191 */
6192 disable_irq(core_irqres->start);
6193 host->sdcc_irq_disabled = 1;
6194
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05306195 if (!plat->sdiowakeup_irq) {
6196 /* Check if registered as IORESOURCE_IRQ */
6197 plat->sdiowakeup_irq =
6198 platform_get_irq_byname(pdev, "sdiowakeup_irq");
6199 if (plat->sdiowakeup_irq < 0)
6200 plat->sdiowakeup_irq = 0;
6201 }
6202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006203 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006204 ret = request_irq(plat->sdiowakeup_irq,
6205 msmsdcc_platform_sdiowakeup_irq,
6206 IRQF_SHARED | IRQF_TRIGGER_LOW,
6207 DRIVER_NAME "sdiowakeup", host);
6208 if (ret) {
6209 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6210 plat->sdiowakeup_irq, ret);
6211 goto pio_irq_free;
6212 } else {
6213 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306214 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006215 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306216 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006217 }
6218 spin_unlock_irqrestore(&host->lock, flags);
6219 }
6220 }
6221
Krishna Konda1963f432013-02-19 20:28:53 -08006222 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006223 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6224 mmc_hostname(mmc));
6225 }
6226
6227 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6228 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006229 /*
6230 * Setup card detect change
6231 */
6232
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306233 if (!plat->status_gpio)
6234 plat->status_gpio = -ENOENT;
6235 if (!plat->wpswitch_gpio)
6236 plat->wpswitch_gpio = -ENOENT;
6237
6238 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306239 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006240 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306241 } else {
6242 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006243 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306244 }
Krishna Konda941604a2012-01-10 17:46:34 -08006245 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006246 }
San Mehat9d2bd732009-09-22 16:44:22 -07006247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006248 if (plat->status_irq) {
6249 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006250 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006251 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006252 DRIVER_NAME " (slot)",
6253 host);
6254 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006255 pr_err("Unable to get slot IRQ %d (%d)\n",
6256 plat->status_irq, ret);
6257 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006258 }
6259 } else if (plat->register_status_notify) {
6260 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6261 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006262 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006263 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006264
6265 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006266
6267 ret = pm_runtime_set_active(&(pdev)->dev);
6268 if (ret < 0)
6269 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6270 __func__, ret);
6271 /*
6272 * There is no notion of suspend/resume for SD/MMC/SDIO
6273 * cards. So host can be suspended/resumed with out
6274 * worrying about its children.
6275 */
6276 pm_suspend_ignore_children(&(pdev)->dev, true);
6277
6278 /*
6279 * MMC/SD/SDIO bus suspend/resume operations are defined
6280 * only for the slots that will be used for non-removable
6281 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6282 * defined. Otherwise, they simply become card removal and
6283 * insertion events during suspend and resume respectively.
6284 * Hence, enable run-time PM only for slots for which bus
6285 * suspend/resume operations are defined.
6286 */
6287#ifdef CONFIG_MMC_UNSAFE_RESUME
6288 /*
6289 * If this capability is set, MMC core will enable/disable host
6290 * for every claim/release operation on a host. We use this
6291 * notification to increment/decrement runtime pm usage count.
6292 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006293 pm_runtime_enable(&(pdev)->dev);
6294#else
6295 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006296 pm_runtime_enable(&(pdev)->dev);
6297 }
6298#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306299 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006300 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6301 (unsigned long)host);
6302
San Mehat9d2bd732009-09-22 16:44:22 -07006303 mmc_add_host(mmc);
6304
Sujit Reddy Thumma97a35d22012-10-31 22:45:45 +05306305 mmc->clk_scaling.up_threshold = 35;
6306 mmc->clk_scaling.down_threshold = 5;
6307 mmc->clk_scaling.polling_delay_ms = 100;
6308 mmc->caps2 |= MMC_CAP2_CLK_SCALE;
6309
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006310 pr_info("%s: Qualcomm MSM SDCC-core %pr %pr,%d dma %d dmacrcri %d\n",
6311 mmc_hostname(mmc), core_memres, core_irqres,
Krishna Konda25786ec2011-07-25 16:21:36 -07006312 (unsigned int) plat->status_irq, host->dma.channel,
6313 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006314
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306315 pr_info("%s: Controller capabilities: 0x%.8x\n",
6316 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006317 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6318 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6319 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6320 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6321 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6322 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6323 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6324 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6325 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6326 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6327 host->eject);
6328 pr_info("%s: Power save feature enable = %d\n",
6329 mmc_hostname(mmc), msmsdcc_pwrsave);
6330
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306331 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006332 && host->dma.crci != -1) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006333 pr_info("%s: DM non-cached buffer at %p, dma_addr: %pa\n",
6334 mmc_hostname(mmc), host->dma.nc, &host->dma.nc_busaddr);
6335 pr_info("%s: DM cmd busaddr: %pa, cmdptr busaddr: %pa\n",
6336 mmc_hostname(mmc), &host->dma.cmd_busaddr,
6337 &host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306338 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006339 pr_info("%s: SPS-BAM data transfer mode available\n",
6340 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006341 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006342 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006344#if defined(CONFIG_DEBUG_FS)
6345 msmsdcc_dbg_createhost(host);
6346#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306347
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306348 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6349 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6350 sysfs_attr_init(&host->max_bus_bw.attr);
6351 host->max_bus_bw.attr.name = "max_bus_bw";
6352 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6353 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306354 if (ret)
6355 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306356
6357 if (!plat->status_irq) {
6358 host->polling.show = show_polling;
6359 host->polling.store = store_polling;
6360 sysfs_attr_init(&host->polling.attr);
6361 host->polling.attr.name = "polling";
6362 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6363 ret = device_create_file(&pdev->dev, &host->polling);
6364 if (ret)
6365 goto remove_max_bus_bw_file;
6366 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306367 host->idle_timeout.show = show_idle_timeout;
6368 host->idle_timeout.store = store_idle_timeout;
6369 sysfs_attr_init(&host->idle_timeout.attr);
6370 host->idle_timeout.attr.name = "idle_timeout";
6371 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6372 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6373 if (ret)
6374 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306375
6376 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306377 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306378
6379 /* Sysfs entry for AUTO CMD19 control */
6380 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6381 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6382 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6383 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6384 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6385 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6386 if (ret)
6387 goto remove_idle_timeout_file;
6388
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306389 add_auto_cmd21_atrr:
6390 if (!is_auto_cmd21(host))
6391 goto exit;
6392
6393 /* Sysfs entry for AUTO CMD21 control */
6394 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6395 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6396 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6397 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6398 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6399 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6400 if (ret)
6401 goto remove_auto_cmd19_attr_file;
6402
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306403 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006404 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006405
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306406 remove_auto_cmd19_attr_file:
6407 if (is_auto_cmd19(host))
6408 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306409 remove_idle_timeout_file:
6410 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306411 remove_polling_file:
6412 if (!plat->status_irq)
6413 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306414 remove_max_bus_bw_file:
6415 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006416 platform_irq_free:
6417 del_timer_sync(&host->req_tout_timer);
6418 pm_runtime_disable(&(pdev)->dev);
6419 pm_runtime_set_suspended(&(pdev)->dev);
6420
6421 if (plat->status_irq)
6422 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306423 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006424 sdiowakeup_irq_free:
Krishna Konda1963f432013-02-19 20:28:53 -08006425 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6426 wake_lock_destroy(&host->sdio_wlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006427 wake_lock_destroy(&host->sdio_suspend_wlock);
6428 if (plat->sdiowakeup_irq)
6429 free_irq(plat->sdiowakeup_irq, host);
6430 pio_irq_free:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006431 free_irq(core_irqres->start, host);
6432 irq_free:
6433 free_irq(core_irqres->start, host);
6434 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306435 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006436 msmsdcc_dml_exit(host);
6437 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306438 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006439 msmsdcc_sps_exit(host);
6440 vreg_deinit:
6441 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006442 clk_disable:
Krishna Konda7dd56c22012-11-08 17:52:32 -08006443 clk_disable_unprepare(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306444 msmsdcc_msm_bus_unregister(host);
6445 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006446 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306447 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006448 clk_put:
6449 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006450 pclk_disable:
6451 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306452 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006453 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006454 if (!IS_ERR(host->pclk))
6455 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306456 if (!IS_ERR_OR_NULL(host->bus_clk))
6457 clk_disable_unprepare(host->bus_clk);
6458 bus_clk_put:
6459 if (!IS_ERR_OR_NULL(host->bus_clk))
6460 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306461 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006462 if (host->dmares)
6463 dma_free_coherent(NULL,
6464 sizeof(struct msmsdcc_nc_dmadata),
6465 host->dma.nc, host->dma.nc_busaddr);
6466 }
6467 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306468 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006469 host_free:
6470 mmc_free_host(mmc);
6471 out:
6472 return ret;
6473}
6474
Pratibhasagar V713817b2012-09-07 11:28:30 +05306475#ifdef CONFIG_DEBUG_FS
6476static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6477{
6478 debugfs_remove_recursive(host->debugfs_host_dir);
6479 host->debugfs_host_dir = NULL;
6480}
6481#else
6482static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6483#endif
6484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006485static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006486{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006487 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6488 struct mmc_platform_data *plat;
6489 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006491 if (!mmc)
6492 return -ENXIO;
6493
6494 if (pm_runtime_suspended(&(pdev)->dev))
6495 pm_runtime_resume(&(pdev)->dev);
6496
6497 host = mmc_priv(mmc);
6498
6499 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6500 plat = host->plat;
6501
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306502 if (is_auto_cmd19(host))
6503 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306504 if (is_auto_cmd21(host))
6505 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306506 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006507 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306508 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306509 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006510
Pratibhasagar V713817b2012-09-07 11:28:30 +05306511 msmsdcc_remove_debugfs(host);
6512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006513 del_timer_sync(&host->req_tout_timer);
6514 tasklet_kill(&host->dma_tlet);
6515 tasklet_kill(&host->sps.tlet);
6516 mmc_remove_host(mmc);
6517
6518 if (plat->status_irq)
6519 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306520 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006521
6522 wake_lock_destroy(&host->sdio_suspend_wlock);
6523 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006524 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6525 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006526 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006527
Krishna Konda1963f432013-02-19 20:28:53 -08006528 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6529 wake_lock_destroy(&host->sdio_wlock);
6530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006531 free_irq(host->core_irqres->start, host);
6532 free_irq(host->core_irqres->start, host);
6533
6534 clk_put(host->clk);
6535 if (!IS_ERR(host->pclk))
6536 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306537 if (!IS_ERR_OR_NULL(host->bus_clk))
6538 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006539
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006540 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306541 pm_qos_remove_request(&host->pm_qos_req_dma);
6542
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306543 if (host->msm_bus_vote.client_handle) {
6544 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6545 msmsdcc_msm_bus_unregister(host);
6546 }
6547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006548 msmsdcc_vreg_init(host, false);
6549
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306550 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006551 if (host->dmares)
6552 dma_free_coherent(NULL,
6553 sizeof(struct msmsdcc_nc_dmadata),
6554 host->dma.nc, host->dma.nc_busaddr);
6555 }
6556
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306557 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006558 msmsdcc_dml_exit(host);
6559 msmsdcc_sps_exit(host);
6560 }
6561
6562 iounmap(host->base);
6563 mmc_free_host(mmc);
6564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006565 pm_runtime_disable(&(pdev)->dev);
6566 pm_runtime_set_suspended(&(pdev)->dev);
6567
6568 return 0;
6569}
6570
6571#ifdef CONFIG_MSM_SDIO_AL
6572int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6573{
6574 struct msmsdcc_host *host = mmc_priv(mmc);
6575 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306576 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006577
Asutosh Dasf5298c32012-04-03 14:51:47 +05306578 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006579 spin_lock_irqsave(&host->lock, flags);
6580 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6581 enable ? "En" : "Dis");
6582
6583 if (enable) {
6584 if (!host->sdcc_irq_disabled) {
6585 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306586 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006587 host->sdcc_irq_disabled = 1;
6588 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306589 rc = msmsdcc_setup_clocks(host, false);
6590 if (rc)
6591 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006592
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306593 if (host->plat->sdio_lpm_gpio_setup &&
6594 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006595 spin_unlock_irqrestore(&host->lock, flags);
6596 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6597 spin_lock_irqsave(&host->lock, flags);
6598 host->sdio_gpio_lpm = 1;
6599 }
6600
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306601 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006602 msmsdcc_enable_irq_wake(host);
6603 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306604 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006605 }
6606 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306607 rc = msmsdcc_setup_clocks(host, true);
6608 if (rc)
6609 goto out;
6610
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306611 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006612 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306613 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006614 msmsdcc_disable_irq_wake(host);
6615 }
6616
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306617 if (host->plat->sdio_lpm_gpio_setup &&
6618 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006619 spin_unlock_irqrestore(&host->lock, flags);
6620 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6621 spin_lock_irqsave(&host->lock, flags);
6622 host->sdio_gpio_lpm = 0;
6623 }
6624
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306625 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006626 writel_relaxed(host->mci_irqenable,
6627 host->base + MMCIMASK0);
6628 mb();
6629 enable_irq(host->core_irqres->start);
6630 host->sdcc_irq_disabled = 0;
6631 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006632 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306633out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006634 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306635 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306636 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006637}
6638#else
6639int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6640{
6641 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006642}
6643#endif
6644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006645#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306646#ifdef CONFIG_MMC_CLKGATE
6647static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6648{
6649 struct mmc_host *mmc = host->mmc;
6650 unsigned long flags;
6651
6652 mmc_host_clk_hold(mmc);
6653 spin_lock_irqsave(&mmc->clk_lock, flags);
6654 mmc->clk_old = mmc->ios.clock;
6655 mmc->ios.clock = 0;
6656 mmc->clk_gated = true;
6657 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6658 mmc_set_ios(mmc);
6659 mmc_host_clk_release(mmc);
6660}
6661
6662static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6663{
6664 struct mmc_host *mmc = host->mmc;
6665
6666 mmc_host_clk_hold(mmc);
6667 mmc->ios.clock = host->clk_rate;
6668 mmc_set_ios(mmc);
6669 mmc_host_clk_release(mmc);
6670}
6671#else
6672static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6673{
6674 struct mmc_host *mmc = host->mmc;
6675
6676 mmc->ios.clock = 0;
6677 mmc_set_ios(mmc);
6678}
6679
6680static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6681{
6682 struct mmc_host *mmc = host->mmc;
6683
6684 mmc->ios.clock = host->clk_rate;
6685 mmc_set_ios(mmc);
6686}
6687#endif
6688
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306689#if CONFIG_DEBUG_FS
6690static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306691 const char *func, int err)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306692{
6693 ktime_t diff;
6694
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306695 if (host->print_pm_stats && !err) {
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306696 diff = ktime_sub(ktime_get(), start);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306697 pr_info("%s: %s: Completed in %llu usec\n",
6698 mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306699 }
6700}
6701#else
6702static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306703 const char *func, int err) {}
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306704#endif
6705
San Mehat9d2bd732009-09-22 16:44:22 -07006706static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006707msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006708{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006709 struct mmc_host *mmc = dev_get_drvdata(dev);
6710 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006711 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306712 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306713 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006714
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306715 if (host->plat->is_sdio_al_client) {
6716 rc = 0;
6717 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006718 }
San Mehat9d2bd732009-09-22 16:44:22 -07006719
Sahitya Tummala7661a452011-07-18 13:28:35 +05306720 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006721 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006722 host->sdcc_suspending = 1;
6723 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006725 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006726 * MMC core thinks that host is disabled by now since
6727 * runtime suspend is scheduled after msmsdcc_disable()
6728 * is called. Thus, MMC core will try to enable the host
6729 * while suspending it. This results in a synchronous
6730 * runtime resume request while in runtime suspending
6731 * context and hence inorder to complete this resume
6732 * requet, it will wait for suspend to be complete,
6733 * but runtime suspend also can not proceed further
6734 * until the host is resumed. Thus, it leads to a hang.
6735 * Hence, increase the pm usage count before suspending
6736 * the host so that any resume requests after this will
6737 * simple become pm usage counter increment operations.
6738 */
6739 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306740 /* If there is pending detect work abort runtime suspend */
6741 if (unlikely(work_busy(&mmc->detect.work)))
6742 rc = -EAGAIN;
6743 else
6744 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006745 pm_runtime_put_noidle(dev);
6746
6747 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306748 spin_lock_irqsave(&host->lock, flags);
6749 host->sdcc_suspended = true;
6750 spin_unlock_irqrestore(&host->lock, flags);
6751 if (mmc->card && mmc_card_sdio(mmc->card) &&
6752 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006753 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306754 * If SDIO function driver doesn't want
6755 * to power off the card, atleast turn off
6756 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006757 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306758 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006759 }
6760 }
6761 host->sdcc_suspending = 0;
6762 mmc->suspend_task = NULL;
6763 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6764 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006765 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306766 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306767out:
6768 /* set bus bandwidth to 0 immediately */
6769 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306770 msmsdcc_print_pm_stats(host, start, __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07006771 return rc;
6772}
6773
6774static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006775msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006776{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006777 struct mmc_host *mmc = dev_get_drvdata(dev);
6778 struct msmsdcc_host *host = mmc_priv(mmc);
6779 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306780 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006782 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306783 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006784
Sahitya Tummala7661a452011-07-18 13:28:35 +05306785 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006786 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306787 if (mmc->card && mmc_card_sdio(mmc->card) &&
6788 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306789 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306790 }
San Mehat9d2bd732009-09-22 16:44:22 -07006791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006792 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006794 /*
6795 * FIXME: Clearing of flags must be handled in clients
6796 * resume handler.
6797 */
6798 spin_lock_irqsave(&host->lock, flags);
6799 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306800 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006801 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006803 /*
6804 * After resuming the host wait for sometime so that
6805 * the SDIO work will be processed.
6806 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306807 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306808 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006809 host->plat->sdiowakeup_irq) &&
6810 wake_lock_active(&host->sdio_wlock))
6811 wake_lock_timeout(&host->sdio_wlock, 1);
6812 }
6813
6814 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006815 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306816 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306817 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306818out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306819 msmsdcc_print_pm_stats(host, start, __func__, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07006820 return 0;
6821}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006822
6823static int msmsdcc_runtime_idle(struct device *dev)
6824{
6825 struct mmc_host *mmc = dev_get_drvdata(dev);
6826 struct msmsdcc_host *host = mmc_priv(mmc);
6827
6828 if (host->plat->is_sdio_al_client)
6829 return 0;
6830
6831 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306832 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006833
6834 return -EAGAIN;
6835}
6836
6837static int msmsdcc_pm_suspend(struct device *dev)
6838{
6839 struct mmc_host *mmc = dev_get_drvdata(dev);
6840 struct msmsdcc_host *host = mmc_priv(mmc);
6841 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306842 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006843
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306844 if (host->plat->is_sdio_al_client) {
6845 rc = 0;
6846 goto out;
6847 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306848 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006849 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306850 msmsdcc_disable_status_gpio(host);
6851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006852
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306853 /*
6854 * If system comes out of suspend, msmsdcc_pm_resume() sets the
6855 * host->pending_resume flag if the SDCC wasn't runtime suspended.
6856 * Now if the system again goes to suspend without any SDCC activity
6857 * then host->pending_resume flag will remain set which may cause
6858 * the SDCC resume to happen first and then suspend.
6859 * To avoid this unnecessary resume/suspend, make sure that
6860 * pending_resume flag is cleared before calling the
6861 * msmsdcc_runtime_suspend().
6862 */
6863 if (!pm_runtime_suspended(dev) && !host->pending_resume)
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006864 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306865 out:
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306866 /* This flag must not be set if system is entering into suspend */
6867 host->pending_resume = false;
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306868 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006869 return rc;
6870}
6871
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306872static int msmsdcc_suspend_noirq(struct device *dev)
6873{
6874 struct mmc_host *mmc = dev_get_drvdata(dev);
6875 struct msmsdcc_host *host = mmc_priv(mmc);
6876 int rc = 0;
6877
6878 /*
6879 * After platform suspend there may be active request
6880 * which might have enabled clocks. For example, in SDIO
6881 * case, ksdioirq thread might have scheduled after sdcc
6882 * suspend but before system freeze. In that case abort
6883 * suspend and retry instead of keeping the clocks on
6884 * during suspend and not allowing TCXO.
6885 */
6886
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306887 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306888 pr_warn("%s: clocks are on after suspend, aborting system "
6889 "suspend\n", mmc_hostname(mmc));
6890 rc = -EAGAIN;
6891 }
6892
6893 return rc;
6894}
6895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006896static int msmsdcc_pm_resume(struct device *dev)
6897{
6898 struct mmc_host *mmc = dev_get_drvdata(dev);
6899 struct msmsdcc_host *host = mmc_priv(mmc);
6900 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306901 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006902
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306903 if (host->plat->is_sdio_al_client) {
6904 rc = 0;
6905 goto out;
6906 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006907 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306908 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306909 /*
6910 * As runtime PM is enabled before calling the device's platform resume
6911 * callback, we use the pm_runtime_suspended API to know if SDCC is
6912 * really runtime suspended or not and set the pending_resume flag only
6913 * if its not runtime suspended.
6914 */
6915 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006916 host->pending_resume = true;
6917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006918 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306919 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006920 msmsdcc_check_status((unsigned long)host);
6921 enable_irq(host->plat->status_irq);
6922 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306923out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306924 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006925 return rc;
6926}
6927
Daniel Walker08ecfde2010-06-23 12:32:20 -07006928#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006929static int msmsdcc_runtime_suspend(struct device *dev)
6930{
6931 return 0;
6932}
6933static int msmsdcc_runtime_idle(struct device *dev)
6934{
6935 return 0;
6936}
6937static int msmsdcc_pm_suspend(struct device *dev)
6938{
6939 return 0;
6940}
6941static int msmsdcc_pm_resume(struct device *dev)
6942{
6943 return 0;
6944}
6945static int msmsdcc_suspend_noirq(struct device *dev)
6946{
6947 return 0;
6948}
6949static int msmsdcc_runtime_resume(struct device *dev)
6950{
6951 return 0;
6952}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006953#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006954
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006955static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6956 .runtime_suspend = msmsdcc_runtime_suspend,
6957 .runtime_resume = msmsdcc_runtime_resume,
6958 .runtime_idle = msmsdcc_runtime_idle,
6959 .suspend = msmsdcc_pm_suspend,
6960 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306961 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006962};
6963
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306964static const struct of_device_id msmsdcc_dt_match[] = {
6965 {.compatible = "qcom,msm-sdcc"},
6966
6967};
6968MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6969
San Mehat9d2bd732009-09-22 16:44:22 -07006970static struct platform_driver msmsdcc_driver = {
6971 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006972 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006973 .driver = {
6974 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006975 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306976 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006977 },
6978};
6979
6980static int __init msmsdcc_init(void)
6981{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006982#if defined(CONFIG_DEBUG_FS)
6983 int ret = 0;
6984 ret = msmsdcc_dbg_init();
6985 if (ret) {
6986 pr_err("Failed to create debug fs dir \n");
6987 return ret;
6988 }
6989#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006990 return platform_driver_register(&msmsdcc_driver);
6991}
San Mehat9d2bd732009-09-22 16:44:22 -07006992
San Mehat9d2bd732009-09-22 16:44:22 -07006993static void __exit msmsdcc_exit(void)
6994{
6995 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006996
6997#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006998 debugfs_remove(debugfs_dir);
6999#endif
San Mehat9d2bd732009-09-22 16:44:22 -07007000}
7001
7002module_init(msmsdcc_init);
7003module_exit(msmsdcc_exit);
7004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007005MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07007006MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007007
7008#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05307009static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007010{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307011 struct msmsdcc_host *host = data;
7012
7013 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007014 return 0;
7015}
7016
Pratibhasagar V713817b2012-09-07 11:28:30 +05307017static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007018{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307019 struct msmsdcc_host *host = data;
7020 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007021
Pratibhasagar V713817b2012-09-07 11:28:30 +05307022 spin_lock_irqsave(&host->lock, flags);
7023 host->idle_tout = (u32)val * 1000;
7024 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007025
Pratibhasagar V713817b2012-09-07 11:28:30 +05307026 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007027}
7028
Pratibhasagar V713817b2012-09-07 11:28:30 +05307029DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
7030 msmsdcc_dbg_idle_tout_get,
7031 msmsdcc_dbg_idle_tout_set,
7032 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007033
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307034static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
7035{
7036 struct msmsdcc_host *host = data;
7037
7038 *val = (u64) host->enforce_pio_mode;
7039 return 0;
7040}
7041
7042static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
7043{
7044 struct msmsdcc_host *host = data;
7045 unsigned long flags;
7046
7047 spin_lock_irqsave(&host->lock, flags);
7048 host->enforce_pio_mode = !!val;
7049 spin_unlock_irqrestore(&host->lock, flags);
7050
7051 return 0;
7052}
7053
7054DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
7055 msmsdcc_dbg_pio_mode_get,
7056 msmsdcc_dbg_pio_mode_set,
7057 "%llu\n");
7058
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307059static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
7060{
7061 struct msmsdcc_host *host = data;
7062
7063 *val = !!host->print_pm_stats;
7064 return 0;
7065}
7066
7067static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
7068{
7069 struct msmsdcc_host *host = data;
7070 unsigned long flags;
7071
7072 spin_lock_irqsave(&host->lock, flags);
7073 host->print_pm_stats = !!val;
7074 spin_unlock_irqrestore(&host->lock, flags);
7075
7076 return 0;
7077}
7078
7079DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
7080 msmsdcc_dbg_pm_stats_get,
7081 msmsdcc_dbg_pm_stats_set,
7082 "%llu\n");
7083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007084static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
7085{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307086 int err = 0;
7087
7088 if (!debugfs_dir)
7089 return;
7090
7091 host->debugfs_host_dir = debugfs_create_dir(
7092 mmc_hostname(host->mmc), debugfs_dir);
7093 if (IS_ERR(host->debugfs_host_dir)) {
7094 err = PTR_ERR(host->debugfs_host_dir);
7095 host->debugfs_host_dir = NULL;
7096 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
7097 mmc_hostname(host->mmc), err);
7098 return;
7099 }
7100
7101 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
7102 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7103 &msmsdcc_dbg_idle_tout_ops);
7104
7105 if (IS_ERR(host->debugfs_idle_tout)) {
7106 err = PTR_ERR(host->debugfs_idle_tout);
7107 host->debugfs_idle_tout = NULL;
7108 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
7109 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007110 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307111
7112 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
7113 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7114 &msmsdcc_dbg_pio_mode_ops);
7115
7116 if (IS_ERR(host->debugfs_pio_mode)) {
7117 err = PTR_ERR(host->debugfs_pio_mode);
7118 host->debugfs_pio_mode = NULL;
7119 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
7120 mmc_hostname(host->mmc), err);
7121 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307122
7123 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
7124 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7125 &msmsdcc_dbg_pm_stats_ops);
7126 if (IS_ERR(host->debugfs_pm_stats)) {
7127 err = PTR_ERR(host->debugfs_pm_stats);
7128 host->debugfs_pm_stats = NULL;
7129 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
7130 mmc_hostname(host->mmc), err);
7131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007132}
7133
7134static int __init msmsdcc_dbg_init(void)
7135{
7136 int err;
7137
Pratibhasagar V713817b2012-09-07 11:28:30 +05307138 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007139 if (IS_ERR(debugfs_dir)) {
7140 err = PTR_ERR(debugfs_dir);
7141 debugfs_dir = NULL;
7142 return err;
7143 }
7144
7145 return 0;
7146}
7147#endif