blob: b3862661abfed09e49dce9b58ee94fbb973078a4 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Sujit Reddy Thumma1f2ae7c2013-01-10 09:33:57 +05306 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07007 *
San Mehat9d2bd732009-09-22 16:44:22 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Based on mmci.c
14 *
15 * Author: San Mehat (san@android.com)
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/init.h>
22#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053023#include <linux/of.h>
Sujit Reddy Thumma38459152012-06-26 00:07:59 +053024#include <linux/of_gpio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070025#include <linux/device.h>
26#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070028#include <linux/delay.h>
29#include <linux/err.h>
30#include <linux/highmem.h>
31#include <linux/log2.h>
32#include <linux/mmc/host.h>
33#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080035#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070036#include <linux/clk.h>
37#include <linux/scatterlist.h>
38#include <linux/platform_device.h>
39#include <linux/dma-mapping.h>
40#include <linux/debugfs.h>
41#include <linux/io.h>
42#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043#include <linux/pm_runtime.h>
44#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053045#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#include <linux/regulator/consumer.h>
47#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070048#include <linux/pm_qos.h>
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -080049#include <linux/iopoll.h>
San Mehat9d2bd732009-09-22 16:44:22 -070050
51#include <asm/cacheflush.h>
52#include <asm/div64.h>
53#include <asm/sizes.h>
54
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070056#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053057#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053060#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053061#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070062
San Mehat9d2bd732009-09-22 16:44:22 -070063#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070065
66#define DRIVER_NAME "msm-sdcc"
67
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068#define DBG(host, fmt, args...) \
69 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
70
71#define IRQ_DEBUG 0
72#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
73#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
74#define SPS_CONS_PERIPHERAL 0
75#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053076/* Use SPS only if transfer size is more than this macro */
77#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053079#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +053080#define INVALID_TUNING_PHASE -1
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082#if defined(CONFIG_DEBUG_FS)
83static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
84static struct dentry *debugfs_dir;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085static int msmsdcc_dbg_init(void);
86#endif
87
Asutosh Dasaccacd42012-03-08 14:33:17 +053088static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
89 *data);
90
Subhash Jadavani8766e352011-11-30 11:30:32 +053091static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070092static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094static struct mmc_command dummy52cmd;
95static struct mmc_request dummy52mrq = {
96 .cmd = &dummy52cmd,
97 .data = NULL,
98 .stop = NULL,
99};
100static struct mmc_command dummy52cmd = {
101 .opcode = SD_IO_RW_DIRECT,
102 .flags = MMC_RSP_PRESENT,
103 .data = NULL,
104 .mrq = &dummy52mrq,
105};
106/*
107 * An array holding the Tuning pattern to compare with when
108 * executing a tuning cycle.
109 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530110static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
112 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
113 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
114 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
115};
San Mehat9d2bd732009-09-22 16:44:22 -0700116
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530117static const u32 tuning_block_128[] = {
118 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
119 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
120 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
121 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
122 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
123 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
124 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
125 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
126};
San Mehat865c8062009-11-13 13:42:06 -0800127
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -0800128static int disable_slots;
129module_param(disable_slots, int, 0);
130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131#if IRQ_DEBUG == 1
132static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
133 "dattimeout", "txunderrun", "rxoverrun",
134 "cmdrespend", "cmdsent", "dataend", NULL,
135 "datablkend", "cmdactive", "txactive",
136 "rxactive", "txhalfempty", "rxhalffull",
137 "txfifofull", "rxfifofull", "txfifoempty",
138 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
139 "sdiointr", "progdone", "atacmdcompl",
140 "sdiointrope", "ccstimeout", NULL, NULL,
141 NULL, NULL, NULL };
142
143static void
144msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800145{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
149 for (i = 0; i < 32; i++) {
150 if (status & (1 << i))
151 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800154}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155#endif
San Mehat865c8062009-11-13 13:42:06 -0800156
San Mehat9d2bd732009-09-22 16:44:22 -0700157static void
158msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
159 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530160static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530161static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530162static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800163static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800164static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700165static int msmsdcc_runtime_resume(struct device *dev);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530166static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
167 u32 **out_array, int *len, int size);
Subhash Jadavani355df542012-10-09 19:06:49 +0530168static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode);
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530169static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
170 struct mmc_request *mrq);
171static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
172 struct mmc_request *mrq);
San Mehat9d2bd732009-09-22 16:44:22 -0700173
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530174static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530175{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530176 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530177
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530178 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530179 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530180 } else { /* DMA or PIO mode */
181 if (NR_SG > MAX_NR_SG_DMA_PIO)
182 ret = MAX_NR_SG_DMA_PIO;
183 }
184
185 return ret;
186}
187
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530188/* Prevent idle power collapse(pc) while operating in peripheral mode */
189static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
190{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700191 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530192 return;
193
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530194 if (vote)
195 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700196 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530197 else
198 pm_qos_update_request(&host->pm_qos_req_dma,
199 PM_QOS_DEFAULT_VALUE);
200}
201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
203static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
204 struct msmsdcc_sps_ep_conn_data *ep);
205static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep);
207#else
208static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
209 struct msmsdcc_sps_ep_conn_data *ep,
210 bool is_producer) { return 0; }
211static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
212 struct msmsdcc_sps_ep_conn_data *ep) { }
213static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
214 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530215{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 return 0;
217}
218static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
219 struct msmsdcc_sps_ep_conn_data *ep)
220{
221 return 0;
222}
223static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
224static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
225#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227/**
Krishna Konda3ca90f02012-08-29 16:29:21 -0700228 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530229 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700230 * This function resets SPS BAM and DML cores.
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530231 *
232 * This function should be called to recover from error
233 * conditions encountered during CMD/DATA tranfsers with card.
234 *
235 * @host - Pointer to driver's host structure
236 *
237 */
Krishna Konda3ca90f02012-08-29 16:29:21 -0700238static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530239{
240 int rc;
241
242 /* Reset all SDCC BAM pipes */
243 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700244 if (rc) {
245 pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530246 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700247 goto out;
248 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530249
Krishna Konda3ca90f02012-08-29 16:29:21 -0700250 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
251 if (rc) {
252 pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
Krishna Konda5af8f972012-05-14 16:15:24 -0700253 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700254 goto out;
255 }
256
257 /* Reset BAM */
258 rc = sps_device_reset(host->sps.bam_handle);
259 if (rc) {
260 pr_err("%s: sps_device_reset error=%d\n",
261 mmc_hostname(host->mmc), rc);
262 goto out;
Krishna Konda5af8f972012-05-14 16:15:24 -0700263 }
264
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530265 memset(host->sps.prod.config.desc.base, 0x00,
266 host->sps.prod.config.desc.size);
267 memset(host->sps.cons.config.desc.base, 0x00,
268 host->sps.cons.config.desc.size);
269
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530270 /* Restore all BAM pipes connections */
271 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700272 if (rc) {
273 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530274 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700275 goto out;
276 }
277
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530278 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530279 if (rc) {
Krishna Konda3ca90f02012-08-29 16:29:21 -0700280 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530281 mmc_hostname(host->mmc), rc);
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530282 goto out;
283 }
284
285 /* Reset and init DML */
286 rc = msmsdcc_dml_init(host);
287 if (rc)
288 pr_err("%s: msmsdcc_dml_init error=%d\n",
289 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700290
291out:
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530292 if (!rc)
293 host->sps.reset_bam = false;
Krishna Konda3ca90f02012-08-29 16:29:21 -0700294 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530295}
296
297/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 * Apply soft reset
299 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700300 * This function applies soft reset to SDCC core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301 *
302 * This function should be called to recover from error
303 * conditions encountered with CMD/DATA tranfsers with card.
304 *
305 * Soft reset should only be used with SDCC controller v4.
306 *
307 * @host - Pointer to driver's host structure
308 *
309 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530310static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530313 * Reset controller state machines without resetting
314 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530316 if (is_sw_reset_save_config(host)) {
317 ktime_t start;
Krishna Kondabb97f922012-10-23 20:41:04 -0700318 uint32_t dll_config = 0;
319
320
321 if (is_sw_reset_save_config_broken(host))
322 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530323
324 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
325 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
326 msmsdcc_sync_reg_wr(host);
327
328 start = ktime_get();
329 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
330 /*
331 * SW reset can take upto 10HCLK + 15MCLK cycles.
332 * Calculating based on min clk rates (hclk = 27MHz,
333 * mclk = 400KHz) it comes to ~40us. Let's poll for
334 * max. 1ms for reset completion.
335 */
336 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
337 pr_err("%s: %s failed\n",
338 mmc_hostname(host->mmc), __func__);
339 BUG();
340 }
341 }
Krishna Kondabb97f922012-10-23 20:41:04 -0700342
343 if (is_sw_reset_save_config_broken(host)) {
344 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
345 mb();
346 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530347 } else {
348 writel_relaxed(0, host->base + MMCICOMMAND);
349 msmsdcc_sync_reg_wr(host);
350 writel_relaxed(0, host->base + MMCIDATACTRL);
351 msmsdcc_sync_reg_wr(host);
352 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530353}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530354
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530355static void msmsdcc_hard_reset(struct msmsdcc_host *host)
356{
357 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530358
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530359 /*
360 * Reset SDCC controller to power on default state.
361 * Don't issue a reset request to clock control block if
362 * SDCC controller itself can support hard reset.
363 */
364 if (is_sw_hard_reset(host)) {
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800365 u32 pwr;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530366
367 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
368 | MCI_SW_RST, host->base + MMCIPOWER);
369 msmsdcc_sync_reg_wr(host);
370
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800371 /*
372 * See comment in msmsdcc_soft_reset() on choosing 1ms
373 * poll timeout.
374 */
375 ret = readl_poll_timeout_noirq(host->base + MMCIPOWER,
376 pwr, !(pwr & MCI_SW_RST), 100, 10);
377
378 if (ret) {
379 pr_err("%s: %s failed (%d)\n",
380 mmc_hostname(host->mmc), __func__, ret);
381 BUG();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530382 }
383 } else {
384 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
385 if (ret)
386 pr_err("%s: Clock assert failed at %u Hz" \
387 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530388 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530389
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530390 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
391 if (ret)
392 pr_err("%s: Clock deassert failed at %u Hz" \
393 " with err %d\n", mmc_hostname(host->mmc),
394 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530395
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530396 mb();
397 /* Give some delay for clock reset to propogate to controller */
398 msmsdcc_delay(host);
399 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530400}
401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
403{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530404 if (is_soft_reset(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530405 msmsdcc_soft_reset(host);
406
407 pr_debug("%s: Applied soft reset to Controller\n",
408 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 } else {
410 /* Give Clock reset (hard reset) to controller */
411 u32 mci_clk = 0;
412 u32 mci_mask0 = 0;
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530413 u32 dll_config = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414
415 /* Save the controller state */
416 mci_clk = readl_relaxed(host->base + MMCICLOCK);
417 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530418 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530419 if (host->tuning_needed)
420 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530423 msmsdcc_hard_reset(host);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530424 pr_debug("%s: Applied hard reset to controller\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 mmc_hostname(host->mmc));
426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 /* Restore the contoller state */
428 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530429 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530431 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530433 if (host->tuning_needed)
434 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530435 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530437
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530438 if (is_sps_mode(host))
439 /*
440 * delay the SPS BAM reset in thread context as
441 * sps_connect/sps_disconnect APIs can be called
442 * only from non-atomic context.
443 */
444 host->sps.reset_bam = true;
445
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700446 if (host->dummy_52_needed)
447 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448}
449
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530450static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
451{
452 struct mmc_request *mrq = host->curr.mrq;
453
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530454 if (!mrq || !mrq->cmd || !mrq->data)
455 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530456
457 /*
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530458 * If we have not waited for the prog done for write transfer then
459 * perform the DPSM reset without polling for TXACTIVE.
460 * Otherwise, we poll here unnecessarily as TXACTIVE will not be
461 * deasserted until DAT0 (Busy line) goes high.
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530462 */
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530463 if (mrq->data->flags & MMC_DATA_WRITE) {
464 if (!msmsdcc_is_wait_for_prog_done(host, mrq)) {
465 if (is_wait_for_tx_rx_active(host) &&
466 !is_auto_prog_done(host))
467 pr_warning("%s: %s: AUTO_PROG_DONE capability is must\n",
468 mmc_hostname(host->mmc), __func__);
469 goto no_polling;
470 }
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530471 }
472
473 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
474 if (is_wait_for_tx_rx_active(host)) {
475 ktime_t start = ktime_get();
476
477 while (readl_relaxed(host->base + MMCISTATUS) &
478 (MCI_TXACTIVE | MCI_RXACTIVE)) {
479 /*
480 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
481 * cycles (~11us) after data transfer due to clock mux
482 * switching delays. Let's poll for 1ms and panic if
483 * still active.
484 */
485 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
486 pr_err("%s: %s still active\n",
487 mmc_hostname(host->mmc),
488 readl_relaxed(host->base + MMCISTATUS)
489 & MCI_TXACTIVE ? "TX" : "RX");
490 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530491 msmsdcc_reset_and_restore(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530492 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530493 }
494 }
495 }
496
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530497no_polling:
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530498 writel_relaxed(0, host->base + MMCIDATACTRL);
499 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530500out:
501 return;
502}
503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504static int
San Mehat9d2bd732009-09-22 16:44:22 -0700505msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
506{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 int retval = 0;
508
San Mehat9d2bd732009-09-22 16:44:22 -0700509 BUG_ON(host->curr.data);
510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700512
513 if (mrq->data)
514 mrq->data->bytes_xfered = host->curr.data_xfered;
515 if (mrq->cmd->error == -ETIMEDOUT)
516 mdelay(5);
517
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530518 msmsdcc_reset_dpsm(host);
519
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530520 /* Clear current request information as current request has ended */
521 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
522
San Mehat9d2bd732009-09-22 16:44:22 -0700523 /*
524 * Need to drop the host lock here; mmc_request_done may call
525 * back into the driver...
526 */
527 spin_unlock(&host->lock);
528 mmc_request_done(host->mmc, mrq);
529 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530
531 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700532}
533
534static void
535msmsdcc_stop_data(struct msmsdcc_host *host)
536{
San Mehat9d2bd732009-09-22 16:44:22 -0700537 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530538 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530539 host->curr.wait_for_auto_prog_done = false;
540 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700541}
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700544{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 return host->core_memres->start + MMCIFIFO;
546}
547
548static inline unsigned int msmsdcc_get_min_sup_clk_rate(
549 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530550
Subhash Jadavanidd432952012-03-28 11:25:56 +0530551static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552{
553 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530554 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530555 udelay(host->reg_write_delay);
556 else if (readl_relaxed(host->base + MCI_STATUS2) &
557 MCI_MCLK_REG_WR_ACTIVE) {
558 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530559
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530560 start = ktime_get();
561 while (readl_relaxed(host->base + MCI_STATUS2) &
562 MCI_MCLK_REG_WR_ACTIVE) {
563 diff = ktime_sub(ktime_get(), start);
564 /* poll for max. 1 ms */
565 if (ktime_to_us(diff) > 1000) {
566 pr_warning("%s: previous reg. write is"
567 " still active\n",
568 mmc_hostname(host->mmc));
569 break;
570 }
571 }
572 }
San Mehat9d2bd732009-09-22 16:44:22 -0700573}
574
Subhash Jadavanidd432952012-03-28 11:25:56 +0530575static inline void msmsdcc_delay(struct msmsdcc_host *host)
576{
577 udelay(host->reg_write_delay);
578
San Mehat9d2bd732009-09-22 16:44:22 -0700579}
580
San Mehat56a8b5b2009-11-21 12:29:46 -0800581static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
583{
584 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530586 /*
587 * As after sending the command, we don't write any of the
588 * controller registers and just wait for the
589 * CMD_RESPOND_END/CMD_SENT/Command failure notication
590 * from Controller.
591 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800593}
594
595static void
596msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
597{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
601 writel_relaxed((unsigned int)host->curr.xfer_size,
602 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530604 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800605
San Mehat6ac9ea62009-12-02 17:24:58 -0800606 if (host->cmd_cmd) {
607 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800609 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800610}
611
San Mehat9d2bd732009-09-22 16:44:22 -0700612static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530613msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700614{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530615 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700616 unsigned long flags;
617 struct mmc_request *mrq;
618
619 spin_lock_irqsave(&host->lock, flags);
620 mrq = host->curr.mrq;
621 BUG_ON(!mrq);
622
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530623 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700624 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700625 goto out;
626 }
627
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530628 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700629 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700631 } else {
632 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530633 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700634 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530635 mmc_hostname(host->mmc), host->dma.result);
636 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700637 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530638 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530639 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 host->dma.err.flush[0], host->dma.err.flush[1],
641 host->dma.err.flush[2], host->dma.err.flush[3],
642 host->dma.err.flush[4],
643 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530644 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700645 if (!mrq->data->error)
646 mrq->data->error = -EIO;
647 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530648 if (!mrq->data->host_cookie)
649 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
650 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 if (host->curr.user_pages) {
653 struct scatterlist *sg = host->dma.sg;
654 int i;
655
656 for (i = 0; i < host->dma.num_ents; i++, sg++)
657 flush_dcache_page(sg_page(sg));
658 }
San Mehat9d2bd732009-09-22 16:44:22 -0700659
San Mehat9d2bd732009-09-22 16:44:22 -0700660 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800661 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700662
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530663 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
664 (host->curr.wait_for_auto_prog_done &&
665 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700666 /*
667 * If we've already gotten our DATAEND / DATABLKEND
668 * for this request, then complete it through here.
669 */
San Mehat9d2bd732009-09-22 16:44:22 -0700670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700672 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673 host->curr.xfer_remain -= host->curr.xfer_size;
674 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700675 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700676 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700677 host->dummy_52_sent = 1;
678 msmsdcc_start_command(host, &dummy52cmd,
679 MCI_CPSM_PROGENA);
680 goto out;
681 }
682 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530683 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530684 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700685 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530686 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530688 /*
689 * Clear current request information as current
690 * request has ended
691 */
692 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700693 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694
San Mehat9d2bd732009-09-22 16:44:22 -0700695 mmc_request_done(host->mmc, mrq);
696 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530697 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
698 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700699 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530700 }
San Mehat9d2bd732009-09-22 16:44:22 -0700701 }
702
703out:
704 spin_unlock_irqrestore(&host->lock, flags);
705 return;
706}
707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
709/**
710 * Callback notification from SPS driver
711 *
712 * This callback function gets triggered called from
713 * SPS driver when requested SPS data transfer is
714 * completed.
715 *
716 * SPS driver invokes this callback in BAM irq context so
717 * SDCC driver schedule a tasklet for further processing
718 * this callback notification at later point of time in
719 * tasklet context and immediately returns control back
720 * to SPS driver.
721 *
722 * @nofity - Pointer to sps event notify sturcture
723 *
724 */
725static void
726msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
727{
728 struct msmsdcc_host *host =
729 (struct msmsdcc_host *)
730 ((struct sps_event_notify *)notify)->user;
731
732 host->sps.notify = *notify;
733 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
734 mmc_hostname(host->mmc), __func__, notify->event_id,
735 notify->data.transfer.iovec.addr,
736 notify->data.transfer.iovec.size,
737 notify->data.transfer.iovec.flags);
738 /* Schedule a tasklet for completing data transfer */
739 tasklet_schedule(&host->sps.tlet);
740}
741
742/**
743 * Tasklet handler for processing SPS callback event
744 *
745 * This function processing SPS event notification and
746 * checks if the SPS transfer is completed or not and
747 * then accordingly notifies status to MMC core layer.
748 *
749 * This function is called in tasklet context.
750 *
751 * @data - Pointer to sdcc driver data
752 *
753 */
754static void msmsdcc_sps_complete_tlet(unsigned long data)
755{
756 unsigned long flags;
757 int i, rc;
758 u32 data_xfered = 0;
759 struct mmc_request *mrq;
760 struct sps_iovec iovec;
761 struct sps_pipe *sps_pipe_handle;
762 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
763 struct sps_event_notify *notify = &host->sps.notify;
764
765 spin_lock_irqsave(&host->lock, flags);
766 if (host->sps.dir == DMA_FROM_DEVICE)
767 sps_pipe_handle = host->sps.prod.pipe_handle;
768 else
769 sps_pipe_handle = host->sps.cons.pipe_handle;
770 mrq = host->curr.mrq;
771
772 if (!mrq) {
773 spin_unlock_irqrestore(&host->lock, flags);
774 return;
775 }
776
777 pr_debug("%s: %s: sps event_id=%d\n",
778 mmc_hostname(host->mmc), __func__,
779 notify->event_id);
780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 /*
782 * Got End of transfer event!!! Check if all of the data
783 * has been transferred?
784 */
785 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
786 rc = sps_get_iovec(sps_pipe_handle, &iovec);
787 if (rc) {
788 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
789 mmc_hostname(host->mmc), __func__, rc, i);
790 break;
791 }
792 data_xfered += iovec.size;
793 }
794
795 if (data_xfered == host->curr.xfer_size) {
796 host->curr.data_xfered = host->curr.xfer_size;
797 host->curr.xfer_remain -= host->curr.xfer_size;
798 pr_debug("%s: Data xfer success. data_xfered=0x%x",
799 mmc_hostname(host->mmc),
800 host->curr.xfer_size);
801 } else {
802 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
803 " xfer_size=%d", mmc_hostname(host->mmc),
804 data_xfered, host->curr.xfer_size);
805 msmsdcc_reset_and_restore(host);
806 if (!mrq->data->error)
807 mrq->data->error = -EIO;
808 }
809
810 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530811 if (!mrq->data->host_cookie)
812 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
813 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 host->sps.sg = NULL;
815 host->sps.busy = 0;
816
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530817 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
818 (host->curr.wait_for_auto_prog_done &&
819 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820 /*
821 * If we've already gotten our DATAEND / DATABLKEND
822 * for this request, then complete it through here.
823 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824
825 if (!mrq->data->error) {
826 host->curr.data_xfered = host->curr.xfer_size;
827 host->curr.xfer_remain -= host->curr.xfer_size;
828 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700829 if (host->dummy_52_needed) {
830 mrq->data->bytes_xfered = host->curr.data_xfered;
831 host->dummy_52_sent = 1;
832 msmsdcc_start_command(host, &dummy52cmd,
833 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700834 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700835 return;
836 }
837 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530838 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530839 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700840 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530841 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530843 /*
844 * Clear current request information as current
845 * request has ended
846 */
847 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 spin_unlock_irqrestore(&host->lock, flags);
849
850 mmc_request_done(host->mmc, mrq);
851 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530852 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
853 || !mrq->sbc)) {
854 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 }
856 }
857 spin_unlock_irqrestore(&host->lock, flags);
858}
859
860/**
861 * Exit from current SPS data transfer
862 *
863 * This function exits from current SPS data transfer.
864 *
865 * This function should be called when error condition
866 * is encountered during data transfer.
867 *
868 * @host - Pointer to sdcc host structure
869 *
870 */
871static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
872{
873 struct mmc_request *mrq;
874
875 mrq = host->curr.mrq;
876 BUG_ON(!mrq);
877
878 msmsdcc_reset_and_restore(host);
879 if (!mrq->data->error)
880 mrq->data->error = -EIO;
881
882 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530883 if (!mrq->data->host_cookie)
884 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
885 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886
887 host->sps.sg = NULL;
888 host->sps.busy = 0;
889 if (host->curr.data)
890 msmsdcc_stop_data(host);
891
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530892 if (!mrq->data->stop || mrq->cmd->error ||
893 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530895 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
896 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 msmsdcc_start_command(host, mrq->data->stop, 0);
898
899}
900#else
901static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
902static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
903static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
904#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
905
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530906static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530908static void
909msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
910 unsigned int result,
911 struct msm_dmov_errdata *err)
912{
913 struct msmsdcc_dma_data *dma_data =
914 container_of(cmd, struct msmsdcc_dma_data, hdr);
915 struct msmsdcc_host *host = dma_data->host;
916
917 dma_data->result = result;
918 if (err)
919 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
920
921 tasklet_schedule(&host->dma_tlet);
922}
923
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530924static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
925 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700926{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530927 bool ret = true;
928 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700929
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530930 if (host->enforce_pio_mode) {
931 ret = false;
932 goto out;
933 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530934 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530935 /*
936 * BAM Mode: Fall back on PIO if size is less
937 * than or equal to SPS_MIN_XFER_SIZE bytes.
938 */
939 if (xfer_size <= SPS_MIN_XFER_SIZE)
940 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530941 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530942 /*
943 * ADM Mode: Fall back on PIO if size is less than FIFO size
944 * or not integer multiple of FIFO size
945 */
946 if (xfer_size % MCI_FIFOSIZE)
947 ret = false;
948 } else {
949 /* PIO Mode */
950 ret = false;
951 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530952 out:
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530953 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700954}
955
956static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
957{
958 struct msmsdcc_nc_dmadata *nc;
959 dmov_box *box;
960 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700961 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530962 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700963 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530964 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700965
Krishna Konda25786ec2011-07-25 16:21:36 -0700966 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700968
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530969 BUG_ON((host->pdev->id < 1) || (host->pdev->id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700970
971 host->dma.sg = data->sg;
972 host->dma.num_ents = data->sg_len;
973
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530974 /* Prevent memory corruption */
975 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800976
San Mehat9d2bd732009-09-22 16:44:22 -0700977 nc = host->dma.nc;
978
San Mehat9d2bd732009-09-22 16:44:22 -0700979 if (data->flags & MMC_DATA_READ)
980 host->dma.dir = DMA_FROM_DEVICE;
981 else
982 host->dma.dir = DMA_TO_DEVICE;
983
Asutosh Dasaccacd42012-03-08 14:33:17 +0530984 if (!data->host_cookie) {
985 n = msmsdcc_prep_xfer(host, data);
986 if (unlikely(n < 0)) {
987 host->dma.sg = NULL;
988 host->dma.num_ents = 0;
989 return -ENOMEM;
990 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800991 }
San Mehat9d2bd732009-09-22 16:44:22 -0700992
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530993 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
994 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700995 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530996 for (i = 0; i < host->dma.num_ents; i++) {
997 len = sg_dma_len(sg);
998 offset = 0;
999
1000 do {
1001 /* Check if we can do DMA */
1002 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
1003 err = -ENOTSUPP;
1004 goto unmap;
1005 }
1006
1007 box->cmd = CMD_MODE_BOX;
1008
1009 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
1010 len = MMC_MAX_DMA_BOX_LENGTH;
1011 len -= len % data->blksz;
1012 }
1013 rows = (len % MCI_FIFOSIZE) ?
1014 (len / MCI_FIFOSIZE) + 1 :
1015 (len / MCI_FIFOSIZE);
1016
1017 if (data->flags & MMC_DATA_READ) {
1018 box->src_row_addr = msmsdcc_fifo_addr(host);
1019 box->dst_row_addr = sg_dma_address(sg) + offset;
1020 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1021 (MCI_FIFOSIZE);
1022 box->row_offset = MCI_FIFOSIZE;
1023 box->num_rows = rows * ((1 << 16) + 1);
1024 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
1025 } else {
1026 box->src_row_addr = sg_dma_address(sg) + offset;
1027 box->dst_row_addr = msmsdcc_fifo_addr(host);
1028 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1029 (MCI_FIFOSIZE);
1030 box->row_offset = (MCI_FIFOSIZE << 16);
1031 box->num_rows = rows * ((1 << 16) + 1);
1032 box->cmd |= CMD_DST_CRCI(host->dma.crci);
1033 }
1034
1035 offset += len;
1036 len = sg_dma_len(sg) - offset;
1037 box++;
1038 box_cmd_cnt++;
1039 } while (len);
1040 sg++;
1041 }
1042 /* Mark last command */
1043 box--;
1044 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001045
1046 /* location of command block must be 64 bit aligned */
1047 BUG_ON(host->dma.cmd_busaddr & 0x07);
1048
1049 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1050 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1051 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1052 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1053
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301054 /* Flush all data to memory before starting dma */
1055 mb();
1056
1057unmap:
1058 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301059 if (!data->host_cookie)
1060 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1061 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301062 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1063 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001064 }
1065
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301066 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001067}
1068
Asutosh Dasaccacd42012-03-08 14:33:17 +05301069static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1070 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001071{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301072 int rc = 0;
1073 unsigned int dir;
1074
1075 /* Prevent memory corruption */
1076 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1077
1078 if (data->flags & MMC_DATA_READ)
1079 dir = DMA_FROM_DEVICE;
1080 else
1081 dir = DMA_TO_DEVICE;
1082
1083 /* Make sg buffers DMA ready */
1084 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1085 dir);
1086
1087 if (unlikely(rc != data->sg_len)) {
1088 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1089 mmc_hostname(host->mmc), rc);
1090 rc = -ENOMEM;
1091 goto dma_map_err;
1092 }
1093
1094 pr_debug("%s: %s: %s: sg_len=%d\n",
1095 mmc_hostname(host->mmc), __func__,
1096 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1097 data->sg_len);
1098
1099 goto out;
1100
1101dma_map_err:
1102 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1103 data->flags);
1104out:
1105 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001106}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1108/**
1109 * Submits data transfer request to SPS driver
1110 *
1111 * This function make sg (scatter gather) data buffers
1112 * DMA ready and then submits them to SPS driver for
1113 * transfer.
1114 *
1115 * @host - Pointer to sdcc host structure
1116 * @data - Pointer to mmc_data structure
1117 *
1118 * @return 0 if success else negative value
1119 */
1120static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301121 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001122{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123 int rc = 0;
1124 u32 flags;
1125 int i;
1126 u32 addr, len, data_cnt;
1127 struct scatterlist *sg = data->sg;
1128 struct sps_pipe *sps_pipe_handle;
1129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 host->sps.sg = data->sg;
1131 host->sps.num_ents = data->sg_len;
1132 host->sps.xfer_req_cnt = 0;
1133 if (data->flags & MMC_DATA_READ) {
1134 host->sps.dir = DMA_FROM_DEVICE;
1135 sps_pipe_handle = host->sps.prod.pipe_handle;
1136 } else {
1137 host->sps.dir = DMA_TO_DEVICE;
1138 sps_pipe_handle = host->sps.cons.pipe_handle;
1139 }
1140
Asutosh Dasaccacd42012-03-08 14:33:17 +05301141 if (!data->host_cookie) {
1142 rc = msmsdcc_prep_xfer(host, data);
1143 if (unlikely(rc < 0)) {
1144 host->dma.sg = NULL;
1145 host->dma.num_ents = 0;
1146 goto out;
1147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 }
1149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 for (i = 0; i < data->sg_len; i++) {
1151 /*
1152 * Check if this is the last buffer to transfer?
1153 * If yes then set the INT and EOT flags.
1154 */
1155 len = sg_dma_len(sg);
1156 addr = sg_dma_address(sg);
1157 flags = 0;
1158 while (len > 0) {
1159 if (len > SPS_MAX_DESC_SIZE) {
1160 data_cnt = SPS_MAX_DESC_SIZE;
1161 } else {
1162 data_cnt = len;
1163 if (i == data->sg_len - 1)
1164 flags = SPS_IOVEC_FLAG_INT |
1165 SPS_IOVEC_FLAG_EOT;
1166 }
1167 rc = sps_transfer_one(sps_pipe_handle, addr,
1168 data_cnt, host, flags);
1169 if (rc) {
1170 pr_err("%s: sps_transfer_one() error! rc=%d,"
1171 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1172 mmc_hostname(host->mmc), rc,
1173 (u32)sps_pipe_handle, (u32)sg, i);
1174 goto dma_map_err;
1175 }
1176 addr += data_cnt;
1177 len -= data_cnt;
1178 host->sps.xfer_req_cnt++;
1179 }
1180 sg++;
1181 }
1182 goto out;
1183
1184dma_map_err:
1185 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301186 if (!data->host_cookie)
1187 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1188 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189out:
1190 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001191}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192#else
1193static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1194 struct mmc_data *data) { return 0; }
1195#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001196
1197static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001198msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1199 struct mmc_command *cmd, u32 *c)
1200{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301201 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 cmd->opcode, cmd->arg, cmd->flags);
1203
San Mehat56a8b5b2009-11-21 12:29:46 -08001204 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1205
1206 if (cmd->flags & MMC_RSP_PRESENT) {
1207 if (cmd->flags & MMC_RSP_136)
1208 *c |= MCI_CPSM_LONGRSP;
1209 *c |= MCI_CPSM_RESPONSE;
1210 }
1211
1212 if (/*interrupt*/0)
1213 *c |= MCI_CPSM_INTERRUPT;
1214
Asutosh Das05049132012-05-09 12:38:15 +05301215 /* DAT_CMD bit should be set for all ADTC */
1216 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001217 *c |= MCI_CSPM_DATCMD;
1218
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301219 /* Check if AUTO CMD19/CMD21 is required or not? */
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301220 if (host->tuning_needed && (cmd->mrq->data &&
1221 (cmd->mrq->data->flags & MMC_DATA_READ)) &&
1222 (host->en_auto_cmd19 || host->en_auto_cmd21)) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301223 /*
1224 * For open ended block read operation (without CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301225 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1226 * the READ command.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301227 * For close ended block read operation (with CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301228 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1229 * CMD23.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301230 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301231 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1232 host->curr.mrq->cmd->opcode ==
1233 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301234 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301235 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301236 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1237 cmd->opcode == SD_IO_RW_EXTENDED))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301238 msmsdcc_enable_cdr_cm_sdc4_dll(host);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05301239 if (host->en_auto_cmd19 &&
1240 host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
1241 *c |= MCI_CSPM_AUTO_CMD19;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301242 else if (host->en_auto_cmd21 &&
1243 host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
1244 *c |= MCI_CSPM_AUTO_CMD21;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301245 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 }
1247
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301248 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1249 writel_relaxed((readl_relaxed(host->base +
1250 MCI_DLL_CONFIG) | MCI_CDR_EN),
1251 host->base + MCI_DLL_CONFIG);
1252 else
1253 /* Clear CDR_EN bit for non read operations */
1254 writel_relaxed((readl_relaxed(host->base +
1255 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1256 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301257
Subhash Jadavani56fd4512012-12-19 19:05:02 +05301258 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301259 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301261 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001262 if (cmd == cmd->mrq->stop)
1263 *c |= MCI_CSPM_MCIABORT;
1264
San Mehat56a8b5b2009-11-21 12:29:46 -08001265 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301266 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001268 }
1269 host->curr.cmd = cmd;
1270}
1271
1272static void
1273msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1274 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001275{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301276 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001277 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001279 unsigned int pio_irqmask = 0;
1280
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301281 BUG_ON(!data->sg);
1282 BUG_ON(!data->sg_len);
1283
San Mehat9d2bd732009-09-22 16:44:22 -07001284 host->curr.data = data;
1285 host->curr.xfer_size = data->blksz * data->blocks;
1286 host->curr.xfer_remain = host->curr.xfer_size;
1287 host->curr.data_xfered = 0;
1288 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301289 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001290
San Mehat9d2bd732009-09-22 16:44:22 -07001291 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1292
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301293 if (host->curr.wait_for_auto_prog_done)
1294 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001295
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301296 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301297 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301299 } else if (is_sps_mode(host)) {
Krishna Konda7a05d532012-08-19 11:16:39 -07001300 if (!msmsdcc_sps_start_xfer(host, data)) {
1301 /* Now kick start DML transfer */
1302 mb();
1303 msmsdcc_dml_start_xfer(host, data);
1304 datactrl |= MCI_DPSM_DMAENABLE;
1305 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 }
1307 }
1308 }
1309
1310 /* Is data transfer in PIO mode required? */
1311 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001312 if (data->flags & MMC_DATA_READ) {
1313 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1314 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1315 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1316 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1318 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001319
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001320 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001321 }
1322
1323 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301324 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301325 else if (host->curr.use_wr_data_pend)
1326 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001327
Subhash Jadavanicfa14072013-01-30 16:47:07 +05301328 if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
1329 clks = (unsigned long long)data->timeout_ns *
1330 (host->clk_rate / 2);
1331 else
1332 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
1333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001335 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301336 WARN(!timeout,
1337 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1338 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001339
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301340 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 /* Use ADM (Application Data Mover) HW for Data transfer */
1342 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001343 host->cmd_timeout = timeout;
1344 host->cmd_pio_irqmask = pio_irqmask;
1345 host->cmd_datactrl = datactrl;
1346 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1349 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001350 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001351
1352 if (cmd) {
1353 msmsdcc_start_command_deferred(host, cmd, &c);
1354 host->cmd_c = c;
1355 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1357 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1358 host->base + MMCIMASK0);
1359 mb();
1360 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001361 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1368 (~(MCI_IRQ_PIO))) | pio_irqmask,
1369 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001371
1372 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301373 /* Delay between data/command */
1374 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001375 /* Daisy-chain the command if requested */
1376 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301377 } else {
1378 /*
1379 * We don't need delay after writing to DATA_CTRL
1380 * register if we are not writing to CMD register
1381 * immediately after this. As we already have delay
1382 * before sending the command, we just need mb() here.
1383 */
1384 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001385 }
San Mehat9d2bd732009-09-22 16:44:22 -07001386 }
1387}
1388
1389static void
1390msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1391{
San Mehat56a8b5b2009-11-21 12:29:46 -08001392 msmsdcc_start_command_deferred(host, cmd, &c);
1393 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001394}
1395
1396static void
1397msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1398 unsigned int status)
1399{
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301400 if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
1401 u32 opcode = data->mrq->cmd->opcode;
1402
1403 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1404 || (opcode == MMC_BUS_TEST_R) ||
1405 (host->tuning_in_progress &&
1406 (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
1407 opcode == MMC_SEND_TUNING_BLOCK)))) {
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301408 /* Execute full tuning in case of CRC/timeout errors */
1409 host->saved_tuning_phase = INVALID_TUNING_PHASE;
1410
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301411 if (status & MCI_DATACRCFAIL) {
1412 pr_err("%s: Data CRC error\n",
1413 mmc_hostname(host->mmc));
1414 pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
1415 pr_err("%s: blksz %d, blocks %d\n", __func__,
1416 data->blksz, data->blocks);
1417 } else {
1418 pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
1419 mmc_hostname(host->mmc), opcode,
1420 (readl_relaxed(host->base
1421 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
1422 msmsdcc_dump_sdcc_state(host);
1423 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 }
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301425
1426 /*
1427 * CRC is optional for the bus test commands, not all
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 * cards respond back with CRC. However controller
1429 * waits for the CRC and times out. Hence ignore the
1430 * data timeouts during the Bustest.
1431 */
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301432 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1433 || (opcode == MMC_BUS_TEST_R))) {
1434 if (status & MCI_DATACRCFAIL)
1435 data->error = -EILSEQ;
1436 else
1437 data->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 }
Subhash Jadavani355df542012-10-09 19:06:49 +05301439 /* In case of DATA CRC/timeout error, execute tuning again */
1440 if (host->tuning_needed && !host->tuning_in_progress)
1441 host->tuning_done = false;
1442
San Mehat9d2bd732009-09-22 16:44:22 -07001443 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001444 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001445 data->error = -EIO;
1446 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001447 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001448 data->error = -EIO;
1449 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001450 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001452 data->error = -EIO;
1453 }
San Mehat9d2bd732009-09-22 16:44:22 -07001454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001456 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 host->dummy_52_needed = 0;
1458}
San Mehat9d2bd732009-09-22 16:44:22 -07001459
1460static int
1461msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1462{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001464 uint32_t *ptr = (uint32_t *) buffer;
1465 int count = 0;
1466
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301467 if (remain % 4)
1468 remain = ((remain >> 2) + 1) << 2;
1469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1471
1472 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001473 ptr++;
1474 count += sizeof(uint32_t);
1475
1476 remain -= sizeof(uint32_t);
1477 if (remain == 0)
1478 break;
1479 }
1480 return count;
1481}
1482
1483static int
1484msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001486{
1487 void __iomem *base = host->base;
1488 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 while (readl_relaxed(base + MMCISTATUS) &
1492 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1493 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001494
San Mehat9d2bd732009-09-22 16:44:22 -07001495 count = min(remain, maxcnt);
1496
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301497 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1498 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001499 ptr += count;
1500 remain -= count;
1501
1502 if (remain == 0)
1503 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 }
1505 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001506
1507 return ptr - buffer;
1508}
1509
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001510/*
1511 * Copy up to a word (4 bytes) between a scatterlist
1512 * and a temporary bounce buffer when the word lies across
1513 * two pages. The temporary buffer can then be read to/
1514 * written from the FIFO once.
1515 */
1516static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001517{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001518 struct msmsdcc_pio_data *pio = &host->pio;
1519 unsigned int bytes_avail;
1520
1521 if (host->curr.data->flags & MMC_DATA_READ)
1522 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1523 pio->bounce_buf_len);
1524 else
1525 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1526 pio->bounce_buf_len);
1527
1528 while (pio->bounce_buf_len != 4) {
1529 if (!sg_miter_next(&pio->sg_miter))
1530 break;
1531 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1532 4 - pio->bounce_buf_len);
1533 if (host->curr.data->flags & MMC_DATA_READ)
1534 memcpy(pio->sg_miter.addr,
1535 &pio->bounce_buf[pio->bounce_buf_len],
1536 bytes_avail);
1537 else
1538 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1539 pio->sg_miter.addr, bytes_avail);
1540
1541 pio->sg_miter.consumed = bytes_avail;
1542 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001543 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001544}
1545
1546/*
1547 * Use sg_miter_next to return as many 4-byte aligned
1548 * chunks as possible, using a temporary 4 byte buffer
1549 * for alignment if necessary
1550 */
1551static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1552{
1553 struct msmsdcc_pio_data *pio = &host->pio;
1554 unsigned int length, rlength;
1555 char *buffer;
1556
1557 if (!sg_miter_next(&pio->sg_miter))
1558 return 0;
1559
1560 buffer = pio->sg_miter.addr;
1561 length = pio->sg_miter.length;
1562
1563 if (length < host->curr.xfer_remain) {
1564 rlength = round_down(length, 4);
1565 if (rlength) {
1566 /*
1567 * We have a 4-byte aligned chunk.
1568 * The rounding will be reflected by
1569 * a call to msmsdcc_sg_consumed
1570 */
1571 length = rlength;
1572 goto sg_next_end;
1573 }
1574 /*
1575 * We have a length less than 4 bytes. Check to
1576 * see if more buffer is available, and combine
1577 * to make 4 bytes if possible.
1578 */
1579 pio->bounce_buf_len = length;
1580 memset(pio->bounce_buf, 0, 4);
1581
1582 /*
1583 * On a read, get 4 bytes from FIFO, and distribute
1584 * (4-bouce_buf_len) bytes into consecutive
1585 * sgl buffers when msmsdcc_sg_consumed is called
1586 */
1587 if (host->curr.data->flags & MMC_DATA_READ) {
1588 buffer = pio->bounce_buf;
1589 length = 4;
1590 goto sg_next_end;
1591 } else {
1592 _msmsdcc_sg_consume_word(host);
1593 buffer = pio->bounce_buf;
1594 length = pio->bounce_buf_len;
1595 }
1596 }
1597
1598sg_next_end:
1599 *buf = buffer;
1600 *len = length;
1601 return 1;
1602}
1603
1604/*
1605 * Update sg_miter.consumed based on how many bytes were
1606 * consumed. If the bounce buffer was used to read from FIFO,
1607 * redistribute into sgls.
1608 */
1609static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1610 unsigned int length)
1611{
1612 struct msmsdcc_pio_data *pio = &host->pio;
1613
1614 if (host->curr.data->flags & MMC_DATA_READ) {
1615 if (length > pio->sg_miter.consumed)
1616 /*
1617 * consumed 4 bytes, but sgl
1618 * describes < 4 bytes
1619 */
1620 _msmsdcc_sg_consume_word(host);
1621 else
1622 pio->sg_miter.consumed = length;
1623 } else
1624 if (length < pio->sg_miter.consumed)
1625 pio->sg_miter.consumed = length;
1626}
1627
1628static void msmsdcc_sg_start(struct msmsdcc_host *host)
1629{
1630 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1631
1632 host->pio.bounce_buf_len = 0;
1633
1634 if (host->curr.data->flags & MMC_DATA_READ)
1635 sg_miter_flags |= SG_MITER_TO_SG;
1636 else
1637 sg_miter_flags |= SG_MITER_FROM_SG;
1638
1639 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1640 host->curr.data->sg_len, sg_miter_flags);
1641}
1642
1643static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1644{
1645 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001646}
1647
San Mehat1cd22962010-02-03 12:59:29 -08001648static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001649msmsdcc_pio_irq(int irq, void *dev_id)
1650{
1651 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001653 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001654 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001655 unsigned int remain;
1656 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001657
Murali Palnati36448a42011-09-02 15:06:18 +05301658 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301659
Oluwafemi Adeyemi0bcb1332012-12-07 16:21:22 -08001660 if (!atomic_read(&host->clks_on)) {
1661 spin_unlock(&host->lock);
1662 return IRQ_NONE;
1663 }
1664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301668 (MCI_IRQ_PIO)) == 0) {
1669 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301670 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301671 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672#if IRQ_DEBUG
1673 msmsdcc_print_status(host, "irq1-r", status);
1674#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001675 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001676
1677 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001678 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1681 | MCI_RXDATAAVLBL)))
1682 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001683
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001684 if (!msmsdcc_sg_next(host, &buffer, &remain))
1685 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001686
San Mehat9d2bd732009-09-22 16:44:22 -07001687 len = 0;
1688 if (status & MCI_RXACTIVE)
1689 len = msmsdcc_pio_read(host, buffer, remain);
1690 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001692
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301693 /* len might have aligned to 32bits above */
1694 if (len > remain)
1695 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001696
San Mehat9d2bd732009-09-22 16:44:22 -07001697 host->curr.xfer_remain -= len;
1698 host->curr.data_xfered += len;
1699 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001700 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 if (remain) /* Done with this page? */
1703 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001706 } while (1);
1707
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001708 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001709 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1712 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1713 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1714 host->base + MMCIMASK0);
1715 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301716 /*
1717 * back to back write to MASK0 register don't need
1718 * synchronization delay.
1719 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1721 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1722 }
1723 mb();
1724 } else if (!host->curr.xfer_remain) {
1725 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1726 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1727 mb();
1728 }
San Mehat9d2bd732009-09-22 16:44:22 -07001729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001731
1732 return IRQ_HANDLED;
1733}
1734
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735static void
1736msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1737
1738static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1739 struct mmc_data *data)
1740{
1741 u32 loop_cnt = 0;
1742
1743 /*
1744 * For read commands with data less than fifo size, it is possible to
1745 * get DATAEND first and RXDATA_AVAIL might be set later because of
1746 * synchronization delay through the asynchronous RX FIFO. Thus, for
1747 * such cases, even after DATAEND interrupt is received software
1748 * should poll for RXDATA_AVAIL until the requested data is read out
1749 * of FIFO. This change is needed to get around this abnormal but
1750 * sometimes expected behavior of SDCC3 controller.
1751 *
1752 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1753 * after the data is loaded into RX FIFO. This would amount to less
1754 * than a microsecond and thus looping for 1000 times is good enough
1755 * for that delay.
1756 */
1757 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1758 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1759 spin_unlock(&host->lock);
1760 msmsdcc_pio_irq(1, host);
1761 spin_lock(&host->lock);
1762 }
1763 }
1764 if (loop_cnt == 1000) {
1765 pr_info("%s: Timed out while polling for Rx Data\n",
1766 mmc_hostname(host->mmc));
1767 data->error = -ETIMEDOUT;
1768 msmsdcc_reset_and_restore(host);
1769 }
1770}
1771
San Mehat9d2bd732009-09-22 16:44:22 -07001772static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1773{
1774 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001775
1776 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301777 if (mmc_resp_type(cmd))
1778 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1779 /*
1780 * Read rest of the response registers only if
1781 * long response is expected for this command
1782 */
1783 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1784 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1785 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1786 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1787 }
San Mehat9d2bd732009-09-22 16:44:22 -07001788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301790 pr_debug("%s: CMD%d: Command timeout\n",
1791 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001792 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301794 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301795 pr_err("%s: CMD%d: Command CRC error\n",
1796 mmc_hostname(host->mmc), cmd->opcode);
1797 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301798 /* Execute full tuning in case of CRC errors */
1799 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Subhash Jadavani355df542012-10-09 19:06:49 +05301800 if (host->tuning_needed)
1801 host->tuning_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001802 cmd->error = -EILSEQ;
1803 }
1804
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301805 if (!cmd->error) {
1806 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1807 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1808 mod_timer(&host->req_tout_timer, (jiffies +
1809 msecs_to_jiffies(host->curr.req_tout_ms)));
1810 }
1811 }
1812
San Mehat9d2bd732009-09-22 16:44:22 -07001813 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301815 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001816 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301818 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 /* Stop current SPS transfer */
1820 msmsdcc_sps_exit_curr_xfer(host);
1821 }
San Mehat9d2bd732009-09-22 16:44:22 -07001822 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301823 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001824 msmsdcc_stop_data(host);
1825 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301826 } else { /* host->data == NULL */
1827 if (!cmd->error && host->prog_enable) {
1828 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301830 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301832 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301833 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301834 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301835 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001836 if (host->dummy_52_needed)
1837 host->dummy_52_needed = 0;
1838 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301840 msmsdcc_request_end(host, cmd->mrq);
1841 }
1842 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301843 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301844 if (cmd == host->curr.mrq->sbc)
1845 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1846 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1847 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301848 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001849 }
1850}
1851
San Mehat9d2bd732009-09-22 16:44:22 -07001852static irqreturn_t
1853msmsdcc_irq(int irq, void *dev_id)
1854{
1855 struct msmsdcc_host *host = dev_id;
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301856 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001857 u32 status;
1858 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001860
1861 spin_lock(&host->lock);
1862
1863 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 struct mmc_command *cmd;
1865 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 if (timer) {
1868 timer = 0;
1869 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001870 }
San Mehat9d2bd732009-09-22 16:44:22 -07001871
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301872 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 pr_debug("%s: %s: SDIO async irq received\n",
1874 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301875
1876 /*
1877 * Only async interrupt can come when clocks are off,
1878 * disable further interrupts and enable them when
1879 * clocks are on.
1880 */
1881 if (!host->sdcc_irq_disabled) {
1882 disable_irq_nosync(irq);
1883 host->sdcc_irq_disabled = 1;
1884 }
1885
1886 /*
1887 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1888 * will take care of signaling sdio irq during
1889 * mmc_sdio_resume().
1890 */
Krishna Konda1963f432013-02-19 20:28:53 -08001891 if (host->sdcc_suspended &&
1892 (host->plat->mpm_sdiowakeup_int ||
1893 host->plat->sdiowakeup_irq)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301894 /*
1895 * This is a wakeup interrupt so hold wakelock
1896 * until SDCC resume is handled.
1897 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301899 } else {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301900 if (!mmc->card || (mmc->card &&
1901 !mmc_card_sdio(mmc->card))) {
1902 pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1903 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301904 ret = 1;
1905 break;
1906 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301907 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301908 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301909 spin_lock(&host->lock);
1910 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301911 ret = 1;
1912 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913 }
1914
1915 status = readl_relaxed(host->base + MMCISTATUS);
1916
1917 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1918 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001919 break;
1920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921#if IRQ_DEBUG
1922 msmsdcc_print_status(host, "irq0-r", status);
1923#endif
1924 status &= readl_relaxed(host->base + MMCIMASK0);
1925 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301926 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301927 if (host->clk_rate <=
1928 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301929 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930#if IRQ_DEBUG
1931 msmsdcc_print_status(host, "irq0-p", status);
1932#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934 if (status & MCI_SDIOINTROPE) {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301935 if (!mmc->card || (mmc->card &&
1936 !mmc_card_sdio(mmc->card))) {
1937 pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
1938 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301939 ret = 1;
1940 break;
1941 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 if (host->sdcc_suspending)
1943 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301944 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301946 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001947 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001948 data = host->curr.data;
1949
1950 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1952 MCI_CMDTIMEOUT)) {
1953 if (status & MCI_CMDTIMEOUT)
1954 pr_debug("%s: dummy CMD52 timeout\n",
1955 mmc_hostname(host->mmc));
1956 if (status & MCI_CMDCRCFAIL)
1957 pr_debug("%s: dummy CMD52 CRC failed\n",
1958 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001959 host->dummy_52_sent = 0;
1960 host->dummy_52_needed = 0;
1961 if (data) {
1962 msmsdcc_stop_data(host);
1963 msmsdcc_request_end(host, data->mrq);
1964 }
1965 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 spin_unlock(&host->lock);
1967 return IRQ_HANDLED;
1968 }
1969 break;
1970 }
1971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 /*
1973 * Check for proper command response
1974 */
1975 cmd = host->curr.cmd;
1976 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1977 MCI_CMDTIMEOUT | MCI_PROGDONE |
1978 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1979 msmsdcc_do_cmdirq(host, status);
1980 }
1981
Subhash Jadavani2d7980f2013-01-09 16:18:08 +05301982 if (data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 /* Check for data errors */
1984 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1985 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1986 msmsdcc_data_err(host, data, status);
1987 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301988 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001989 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301990 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 /* Stop current SPS transfer */
1992 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301993 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 msmsdcc_reset_and_restore(host);
1995 if (host->curr.data)
1996 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301997 if (!data->stop || (host->curr.mrq->sbc
1998 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 timer |=
2000 msmsdcc_request_end(host,
2001 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302002 else if ((host->curr.mrq->sbc
2003 && data->error) ||
2004 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 msmsdcc_start_command(host,
2006 data->stop,
2007 0);
2008 timer = 1;
2009 }
2010 }
2011 }
2012
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302013 /* Check for prog done */
2014 if (host->curr.wait_for_auto_prog_done &&
2015 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302016 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 /* Check for data done */
2019 if (!host->curr.got_dataend && (status & MCI_DATAEND))
2020 host->curr.got_dataend = 1;
2021
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302022 if (host->curr.got_dataend &&
2023 (!host->curr.wait_for_auto_prog_done ||
2024 (host->curr.wait_for_auto_prog_done &&
2025 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 /*
2027 * If DMA is still in progress, we complete
2028 * via the completion handler
2029 */
2030 if (!host->dma.busy && !host->sps.busy) {
2031 /*
2032 * There appears to be an issue in the
2033 * controller where if you request a
2034 * small block transfer (< fifo size),
2035 * you may get your DATAEND/DATABLKEND
2036 * irq without the PIO data irq.
2037 *
2038 * Check to see if theres still data
2039 * to be read, and simulate a PIO irq.
2040 */
2041 if (data->flags & MMC_DATA_READ)
2042 msmsdcc_wait_for_rxdata(host,
2043 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 if (!data->error) {
2045 host->curr.data_xfered =
2046 host->curr.xfer_size;
2047 host->curr.xfer_remain -=
2048 host->curr.xfer_size;
2049 }
2050
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002051 if (!host->dummy_52_needed) {
2052 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302053 if (!data->stop ||
2054 (host->curr.mrq->sbc
2055 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002056 msmsdcc_request_end(
2057 host,
2058 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302059 else if ((host->curr.mrq->sbc
2060 && data->error) ||
2061 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002062 msmsdcc_start_command(
2063 host,
2064 data->stop, 0);
2065 timer = 1;
2066 }
2067 } else {
2068 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002070 &dummy52cmd,
2071 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 }
2073 }
2074 }
2075 }
2076
San Mehat9d2bd732009-09-22 16:44:22 -07002077 ret = 1;
2078 } while (status);
2079
2080 spin_unlock(&host->lock);
2081
San Mehat9d2bd732009-09-22 16:44:22 -07002082 return IRQ_RETVAL(ret);
2083}
2084
2085static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302086msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2087 bool is_first_request)
2088{
2089 struct msmsdcc_host *host = mmc_priv(mmc);
2090 struct mmc_data *data = mrq->data;
2091 int rc = 0;
2092
2093 if (unlikely(!data)) {
2094 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2095 __func__);
2096 return;
2097 }
2098 if (unlikely(data->host_cookie)) {
2099 /* Very wrong */
2100 data->host_cookie = 0;
2101 pr_err("%s: %s Request reposted for prepare\n",
2102 mmc_hostname(mmc), __func__);
2103 return;
2104 }
2105
2106 if (!msmsdcc_is_dma_possible(host, data))
2107 return;
2108
2109 rc = msmsdcc_prep_xfer(host, data);
2110 if (unlikely(rc < 0)) {
2111 data->host_cookie = 0;
2112 return;
2113 }
2114
2115 data->host_cookie = 1;
2116}
2117
2118static void
2119msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2120{
2121 struct msmsdcc_host *host = mmc_priv(mmc);
2122 unsigned int dir;
2123 struct mmc_data *data = mrq->data;
2124
2125 if (unlikely(!data)) {
2126 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2127 __func__);
2128 return;
2129 }
2130 if (data->flags & MMC_DATA_READ)
2131 dir = DMA_FROM_DEVICE;
2132 else
2133 dir = DMA_TO_DEVICE;
2134
2135 if (data->host_cookie)
2136 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2137 data->sg_len, dir);
2138
2139 data->host_cookie = 0;
2140}
2141
2142static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2144{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302145 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302147 if ((mrq->data->flags & MMC_DATA_READ) ||
2148 host->curr.use_wr_data_pend)
2149 msmsdcc_start_data(host, mrq->data,
2150 mrq->sbc ? mrq->sbc : mrq->cmd,
2151 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302152 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302153 msmsdcc_start_command(host,
2154 mrq->sbc ? mrq->sbc : mrq->cmd,
2155 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 } else {
2157 msmsdcc_start_command(host, mrq->cmd, 0);
2158 }
2159}
2160
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302161/*
2162 * This function returns true if AUTO_PROG_DONE feature of host is
2163 * applicable for current request, returns "false" otherwise.
2164 *
2165 * NOTE: Caller should call this function only for data write operations.
2166 */
2167static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2168 struct mmc_request *mrq)
2169{
2170 /*
2171 * Auto-prog done will be enabled for following cases:
2172 * mrq->sbc | mrq->stop
2173 * _____________|________________
2174 * True | Don't care
2175 * False | False (CMD24, ACMD25 use case)
2176 */
2177 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2178 return true;
2179
2180 return false;
2181}
2182
2183/*
2184 * This function returns true if controller can wait for prog done
2185 * for current request, returns "false" otherwise.
2186 *
2187 * NOTE: Caller should call this function only for data write operations.
2188 */
2189static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2190 struct mmc_request *mrq)
2191{
2192 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2193 return true;
2194
2195 return false;
2196}
2197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198static void
San Mehat9d2bd732009-09-22 16:44:22 -07002199msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2200{
2201 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302202 unsigned long flags;
Krishna Konda3d47c822013-02-21 18:28:11 -08002203 unsigned int error = 0;
Krishna Konda3ca90f02012-08-29 16:29:21 -07002204 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 /*
2207 * Get the SDIO AL client out of LPM.
2208 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002209 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 if (host->plat->is_sdio_al_client)
2211 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002212
Krishna Konda3d47c822013-02-21 18:28:11 -08002213 /*
2214 * Don't start the request if SDCC is not in proper state to handle it
2215 * BAM state is checked below if applicable
2216 */
2217 if (!host->pwr || !atomic_read(&host->clks_on) ||
2218 host->sdcc_irq_disabled) {
2219 WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
2220 mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
2221 error = EIO;
2222 goto bad_state;
2223 }
2224
Krishna Konda3ca90f02012-08-29 16:29:21 -07002225 /* check if sps bam needs to be reset */
2226 if (is_sps_mode(host) && host->sps.reset_bam) {
2227 while (retries) {
2228 if (!msmsdcc_bam_dml_reset_and_restore(host))
2229 break;
2230 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2231 mmc_hostname(host->mmc), --retries);
2232 }
Krishna Konda3d47c822013-02-21 18:28:11 -08002233
2234 /* check if BAM reset succeeded or not */
2235 if (host->sps.reset_bam) {
2236 pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
2237 mmc_hostname(host->mmc), mrq->cmd->opcode);
2238 error = EAGAIN;
2239 goto bad_state;
2240 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302241 }
San Mehat9d2bd732009-09-22 16:44:22 -07002242
Subhash Jadavani355df542012-10-09 19:06:49 +05302243 /*
2244 * Check if DLL retuning is required? If yes, perform it here before
2245 * starting new request.
2246 */
2247 if (host->tuning_needed && !host->tuning_in_progress &&
2248 !host->tuning_done) {
2249 pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
2250 mmc_hostname(mmc), __func__, host->mmc->ios.timing);
2251 if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
2252 msmsdcc_execute_tuning(mmc,
2253 MMC_SEND_TUNING_BLOCK);
2254 else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
2255 msmsdcc_execute_tuning(mmc,
2256 MMC_SEND_TUNING_BLOCK_HS200);
2257 }
2258
San Mehat9d2bd732009-09-22 16:44:22 -07002259 if (host->eject) {
Krishna Konda3d47c822013-02-21 18:28:11 -08002260 error = ENOMEDIUM;
2261 goto card_ejected;
subhashjf181c292012-05-02 13:07:40 +05302262 }
2263
2264 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2265 " other request (CMD%d) is in progress\n",
2266 mmc_hostname(host->mmc), __func__,
2267 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2268
Krishna Konda3d47c822013-02-21 18:28:11 -08002269 spin_lock_irqsave(&host->lock, flags);
2270
subhashjf181c292012-05-02 13:07:40 +05302271 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302272 * Set timeout value to 10 secs (or more in case of buggy cards)
2273 */
2274 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302275 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302276 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302277 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302278 /*
2279 * Kick the software request timeout timer here with the timeout
2280 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302281 */
2282 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302283 (jiffies +
2284 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002285
San Mehat9d2bd732009-09-22 16:44:22 -07002286 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302287 if (mrq->sbc) {
2288 mrq->sbc->mrq = mrq;
2289 mrq->sbc->data = mrq->data;
2290 }
2291
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302292 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302293 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2294 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302295 } else {
2296 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2297 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 host->dummy_52_needed = 1;
2299 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302300
Subhash Jadavanif5277752011-10-12 16:47:52 +05302301 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
Subhash Jadavanicf58e6f2012-10-05 20:45:54 +05302302 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
2303 ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
2304 is_data_pend_for_cmd53(host)))
Subhash Jadavanif5277752011-10-12 16:47:52 +05302305 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002306 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302307
Subhash Jadavanif5277752011-10-12 16:47:52 +05302308 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002309 spin_unlock_irqrestore(&host->lock, flags);
Krishna Konda3d47c822013-02-21 18:28:11 -08002310 return;
2311
2312bad_state:
2313 msmsdcc_dump_sdcc_state(host);
2314card_ejected:
2315 mrq->cmd->error = -error;
2316 if (mrq->data) {
2317 mrq->data->error = -error;
2318 mrq->data->bytes_xfered = 0;
2319 }
2320 mmc_request_done(mmc, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002321}
2322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2324 int min_uV, int max_uV)
2325{
2326 int rc = 0;
2327
2328 if (vreg->set_voltage_sup) {
2329 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2330 if (rc) {
2331 pr_err("%s: regulator_set_voltage(%s) failed."
2332 " min_uV=%d, max_uV=%d, rc=%d\n",
2333 __func__, vreg->name, min_uV, max_uV, rc);
2334 }
2335 }
2336
2337 return rc;
2338}
2339
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302340static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2341{
2342 int rc = 0;
2343
2344 rc = regulator_get_voltage(vreg->reg);
2345 if (rc < 0)
2346 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2347 __func__, vreg->name, rc);
2348
2349 return rc;
2350}
2351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2353 int uA_load)
2354{
2355 int rc = 0;
2356
Krishna Kondafea60182011-11-01 16:01:34 -07002357 /* regulators that do not support regulator_set_voltage also
2358 do not support regulator_set_optimum_mode */
2359 if (vreg->set_voltage_sup) {
2360 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2361 if (rc < 0)
2362 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2363 "uA_load=%d) failed. rc=%d\n", __func__,
2364 vreg->name, uA_load, rc);
2365 else
2366 /* regulator_set_optimum_mode() can return non zero
2367 * value even for success case.
2368 */
2369 rc = 0;
2370 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371
2372 return rc;
2373}
2374
2375static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2376 struct device *dev)
2377{
2378 int rc = 0;
2379
2380 /* check if regulator is already initialized? */
2381 if (vreg->reg)
2382 goto out;
2383
2384 /* Get the regulator handle */
2385 vreg->reg = regulator_get(dev, vreg->name);
2386 if (IS_ERR(vreg->reg)) {
2387 rc = PTR_ERR(vreg->reg);
2388 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2389 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002390 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002392
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302393 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002394 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302395 /* sanity check */
2396 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2397 pr_err("%s: %s invalid constraints specified\n",
2398 __func__, vreg->name);
2399 rc = -EINVAL;
2400 }
2401 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403out:
2404 return rc;
2405}
2406
2407static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2408{
2409 if (vreg->reg)
2410 regulator_put(vreg->reg);
2411}
2412
2413/* This init function should be called only once for each SDCC slot */
2414static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2415{
2416 int rc = 0;
2417 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302418 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 struct device *dev = mmc_dev(host->mmc);
2420
2421 curr_slot = host->plat->vreg_data;
2422 if (!curr_slot)
2423 goto out;
2424
2425 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302426 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427
2428 if (is_init) {
2429 /*
2430 * Get the regulator handle from voltage regulator framework
2431 * and then try to set the voltage level for the regulator
2432 */
2433 if (curr_vdd_reg) {
2434 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2435 if (rc)
2436 goto out;
2437 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302438 if (curr_vdd_io_reg) {
2439 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440 if (rc)
2441 goto vdd_reg_deinit;
2442 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002443 rc = msmsdcc_vreg_reset(host);
2444 if (rc)
2445 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302446 host->pdev->id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 goto out;
2448 } else {
2449 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302450 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302452vdd_io_reg_deinit:
2453 if (curr_vdd_io_reg)
2454 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455vdd_reg_deinit:
2456 if (curr_vdd_reg)
2457 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2458out:
2459 return rc;
2460}
2461
2462static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2463{
2464 int rc = 0;
2465
Subhash Jadavanicc922692011-08-01 23:05:01 +05302466 /* Put regulator in HPM (high power mode) */
2467 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2468 if (rc < 0)
2469 goto out;
2470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 if (!vreg->is_enabled) {
2472 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302473 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2474 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 if (rc)
2476 goto out;
2477
2478 rc = regulator_enable(vreg->reg);
2479 if (rc) {
2480 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2481 __func__, vreg->name, rc);
2482 goto out;
2483 }
2484 vreg->is_enabled = true;
2485 }
2486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487out:
2488 return rc;
2489}
2490
Krishna Konda3c4142d2012-06-27 11:01:56 -07002491static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492{
2493 int rc = 0;
2494
2495 /* Never disable regulator marked as always_on */
2496 if (vreg->is_enabled && !vreg->always_on) {
2497 rc = regulator_disable(vreg->reg);
2498 if (rc) {
2499 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2500 __func__, vreg->name, rc);
2501 goto out;
2502 }
2503 vreg->is_enabled = false;
2504
2505 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2506 if (rc < 0)
2507 goto out;
2508
2509 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302510 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511 if (rc)
2512 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002513 } else if (vreg->is_enabled && vreg->always_on) {
2514 if (!is_init && vreg->lpm_sup) {
2515 /* Put always_on regulator in LPM (low power mode) */
2516 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2517 if (rc < 0)
2518 goto out;
2519 } else if (is_init && vreg->reset_at_init) {
2520 /**
2521 * The regulator might not actually be disabled if it
2522 * is shared and in use by other drivers.
2523 */
2524 rc = regulator_disable(vreg->reg);
2525 if (rc) {
2526 pr_err("%s: regulator_disable(%s) failed at " \
2527 "bootup. rc=%d\n", __func__,
2528 vreg->name, rc);
2529 goto out;
2530 }
2531 vreg->is_enabled = false;
2532 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002533 }
2534out:
2535 return rc;
2536}
2537
Krishna Konda3c4142d2012-06-27 11:01:56 -07002538static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2539 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540{
2541 int rc = 0, i;
2542 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302543 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544
2545 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302546 if (!curr_slot) {
Asutosh Dasd5902bf2012-10-03 18:28:20 +05302547 pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
2548 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302550 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551
Subhash Jadavani937c7502012-06-01 15:34:46 +05302552 vreg_table[0] = curr_slot->vdd_data;
2553 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554
2555 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2556 if (vreg_table[i]) {
2557 if (enable)
2558 rc = msmsdcc_vreg_enable(vreg_table[i]);
2559 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002560 rc = msmsdcc_vreg_disable(vreg_table[i],
2561 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562 if (rc)
2563 goto out;
2564 }
2565 }
2566out:
2567 return rc;
2568}
2569
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002570/*
2571 * Reset vreg by ensuring it is off during probe. A call
2572 * to enable vreg is needed to balance disable vreg
2573 */
2574static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2575{
2576 int rc;
2577
Krishna Konda3c4142d2012-06-27 11:01:56 -07002578 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002579 if (rc)
2580 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002581 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002582 return rc;
2583}
2584
Subhash Jadavani937c7502012-06-01 15:34:46 +05302585enum vdd_io_level {
2586 /* set vdd_io_data->low_vol_level */
2587 VDD_IO_LOW,
2588 /* set vdd_io_data->high_vol_level */
2589 VDD_IO_HIGH,
2590 /*
2591 * set whatever there in voltage_level (third argument) of
2592 * msmsdcc_set_vdd_io_vol() function.
2593 */
2594 VDD_IO_SET_LEVEL,
2595};
2596
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302597/*
2598 * This function returns the current VDD IO voltage level.
2599 * Returns negative value if it fails to read the voltage level
2600 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2601 * regulator were not defined for host.
2602 */
2603static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2604{
2605 int rc = 0;
2606
2607 if (host->plat->vreg_data) {
2608 struct msm_mmc_reg_data *io_reg =
2609 host->plat->vreg_data->vdd_io_data;
2610
2611 /*
2612 * If vdd_io is not defined, then we can consider that
2613 * IO voltage is same as VDD.
2614 */
2615 if (!io_reg)
2616 io_reg = host->plat->vreg_data->vdd_data;
2617
2618 if (io_reg && io_reg->is_enabled)
2619 rc = msmsdcc_vreg_get_voltage(io_reg);
2620 }
2621
2622 return rc;
2623}
2624
2625/*
2626 * This function updates the IO pad power switch bit in MCI_CLK register
2627 * based on currrent IO pad voltage level.
2628 * NOTE: This function assumes that host lock was not taken by caller.
2629 */
2630static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2631{
2632 int rc = 0;
2633 unsigned long flags;
2634
2635 if (!is_io_pad_pwr_switch(host))
2636 return;
2637
2638 rc = msmsdcc_get_vdd_io_vol(host);
2639
2640 spin_lock_irqsave(&host->lock, flags);
2641 /*
2642 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2643 * the SDCC instances support the dual voltage pads.
2644 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2645 * bit before using the pads in 1.8V mode.
2646 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2647 * IO_PAD_PWR_SWITCH bit is a don't care.
2648 * But we don't have an option to know (by reading some SDCC register)
2649 * that a particular SDCC instance supports dual voltage pads or not,
2650 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2651 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2652 * is anyway ignored.
2653 */
2654 if (rc > 0 && rc < 2700000)
2655 host->io_pad_pwr_switch = 1;
2656 else
2657 host->io_pad_pwr_switch = 0;
2658
2659 if (atomic_read(&host->clks_on)) {
2660 if (host->io_pad_pwr_switch)
2661 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2662 IO_PAD_PWR_SWITCH),
2663 host->base + MMCICLOCK);
2664 else
2665 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2666 ~IO_PAD_PWR_SWITCH),
2667 host->base + MMCICLOCK);
2668 msmsdcc_sync_reg_wr(host);
2669 }
2670 spin_unlock_irqrestore(&host->lock, flags);
2671}
2672
Subhash Jadavani937c7502012-06-01 15:34:46 +05302673static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2674 enum vdd_io_level level,
2675 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676{
2677 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302678 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002679
2680 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302681 struct msm_mmc_reg_data *vdd_io_reg =
2682 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683
Subhash Jadavani937c7502012-06-01 15:34:46 +05302684 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2685 switch (level) {
2686 case VDD_IO_LOW:
2687 set_level = vdd_io_reg->low_vol_level;
2688 break;
2689 case VDD_IO_HIGH:
2690 set_level = vdd_io_reg->high_vol_level;
2691 break;
2692 case VDD_IO_SET_LEVEL:
2693 set_level = voltage_level;
2694 break;
2695 default:
2696 pr_err("%s: %s: invalid argument level = %d",
2697 mmc_hostname(host->mmc), __func__,
2698 level);
2699 rc = -EINVAL;
2700 goto out;
2701 }
2702 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2703 set_level, set_level);
2704 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 }
2706
Subhash Jadavani937c7502012-06-01 15:34:46 +05302707out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302708 return rc;
2709}
2710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2712{
2713 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2714 return 1;
2715 return 0;
2716}
2717
Asutosh Dasf5298c32012-04-03 14:51:47 +05302718/*
2719 * Any function calling msmsdcc_setup_clocks must
2720 * acquire clk_mutex. May sleep.
2721 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302722static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302724 int rc = 0;
2725
2726 if (enable && !atomic_read(&host->clks_on)) {
2727 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2728 rc = clk_prepare_enable(host->bus_clk);
2729 if (rc) {
2730 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2731 mmc_hostname(host->mmc), __func__, rc);
2732 goto out;
2733 }
2734 }
2735 if (!IS_ERR(host->pclk)) {
2736 rc = clk_prepare_enable(host->pclk);
2737 if (rc) {
2738 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2739 mmc_hostname(host->mmc), __func__, rc);
2740 goto disable_bus;
2741 }
2742 }
2743 rc = clk_prepare_enable(host->clk);
2744 if (rc) {
2745 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2746 mmc_hostname(host->mmc), __func__, rc);
2747 goto disable_pclk;
2748 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302749 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302750 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302751 atomic_set(&host->clks_on, 1);
2752 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302753 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302754 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302755 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302757 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302758 if (!IS_ERR_OR_NULL(host->bus_clk))
2759 clk_disable_unprepare(host->bus_clk);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302760 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302762 goto out;
2763
2764disable_pclk:
2765 if (!IS_ERR_OR_NULL(host->pclk))
2766 clk_disable_unprepare(host->pclk);
2767disable_bus:
2768 if (!IS_ERR_OR_NULL(host->bus_clk))
2769 clk_disable_unprepare(host->bus_clk);
2770out:
2771 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772}
2773
2774static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2775 unsigned int req_clk)
2776{
2777 unsigned int sel_clk = -1;
2778
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302779 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2780 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2781 goto out;
2782 }
2783
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2785 unsigned char cnt;
2786
2787 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2788 if (host->plat->sup_clk_table[cnt] > req_clk)
2789 break;
2790 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2791 sel_clk = host->plat->sup_clk_table[cnt];
2792 break;
2793 } else
2794 sel_clk = host->plat->sup_clk_table[cnt];
2795 }
2796 } else {
2797 if ((req_clk < host->plat->msmsdcc_fmax) &&
2798 (req_clk > host->plat->msmsdcc_fmid))
2799 sel_clk = host->plat->msmsdcc_fmid;
2800 else
2801 sel_clk = req_clk;
2802 }
2803
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302804out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 return sel_clk;
2806}
2807
2808static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2809 struct msmsdcc_host *host)
2810{
2811 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2812 return host->plat->sup_clk_table[0];
2813 else
2814 return host->plat->msmsdcc_fmin;
2815}
2816
2817static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2818 struct msmsdcc_host *host)
2819{
2820 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2821 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2822 else
2823 return host->plat->msmsdcc_fmax;
2824}
2825
2826static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302827{
2828 struct msm_mmc_gpio_data *curr;
2829 int i, rc = 0;
2830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302832 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302833 if (!gpio_is_valid(curr->gpio[i].no)) {
2834 rc = -EINVAL;
2835 pr_err("%s: Invalid gpio = %d\n",
2836 mmc_hostname(host->mmc), curr->gpio[i].no);
2837 goto free_gpios;
2838 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302839 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 if (curr->gpio[i].is_always_on &&
2841 curr->gpio[i].is_enabled)
2842 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302843 rc = gpio_request(curr->gpio[i].no,
2844 curr->gpio[i].name);
2845 if (rc) {
2846 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2847 mmc_hostname(host->mmc),
2848 curr->gpio[i].no,
2849 curr->gpio[i].name, rc);
2850 goto free_gpios;
2851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302853 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 if (curr->gpio[i].is_always_on)
2855 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302856 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002857 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302858 }
2859 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302861
2862free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302863 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302864 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865 curr->gpio[i].is_enabled = false;
2866 }
2867out:
2868 return rc;
2869}
2870
2871static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2872{
2873 struct msm_mmc_pad_data *curr;
2874 int i;
2875
2876 curr = host->plat->pin_data->pad_data;
2877 for (i = 0; i < curr->drv->size; i++) {
2878 if (enable)
2879 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2880 curr->drv->on[i].val);
2881 else
2882 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2883 curr->drv->off[i].val);
2884 }
2885
2886 for (i = 0; i < curr->pull->size; i++) {
2887 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002888 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 curr->pull->on[i].val);
2890 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002891 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 curr->pull->off[i].val);
2893 }
2894
2895 return 0;
2896}
2897
2898static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2899{
2900 int rc = 0;
2901
2902 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2903 return 0;
2904
2905 if (host->plat->pin_data->is_gpio)
2906 rc = msmsdcc_setup_gpio(host, enable);
2907 else
2908 rc = msmsdcc_setup_pad(host, enable);
2909
2910 if (!rc)
2911 host->plat->pin_data->cfg_sts = enable;
2912
2913 return rc;
2914}
2915
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302916static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2917 unsigned mode)
2918{
2919 int ret = 0;
2920 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2921
2922 if (!pin)
2923 return 0;
2924
2925 switch (mode) {
2926 case SDC_DAT1_DISABLE:
2927 ret = msm_mpm_enable_pin(pin, 0);
2928 break;
2929 case SDC_DAT1_ENABLE:
2930 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2931 ret = msm_mpm_enable_pin(pin, 1);
2932 break;
2933 case SDC_DAT1_ENWAKE:
2934 ret = msm_mpm_set_pin_wake(pin, 1);
2935 break;
2936 case SDC_DAT1_DISWAKE:
2937 ret = msm_mpm_set_pin_wake(pin, 0);
2938 break;
2939 default:
2940 ret = -EINVAL;
2941 break;
2942 }
2943
2944 return ret;
2945}
2946
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302947static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2948{
2949 u32 pwr = 0;
2950 int ret = 0;
2951 struct mmc_host *mmc = host->mmc;
2952
2953 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2954 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2955 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002956 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302957
2958 if (ret) {
2959 pr_err("%s: Failed to setup voltage regulators\n",
2960 mmc_hostname(host->mmc));
2961 goto out;
2962 }
2963
2964 switch (ios->power_mode) {
2965 case MMC_POWER_OFF:
2966 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302967 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302968 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302969 * If VDD IO rail is always on, set low voltage for VDD
2970 * IO rail when slot is not in use (like when card is not
2971 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302972 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302973 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302974 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302975 msmsdcc_setup_pins(host, false);
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05302976 /*
2977 * Reset the mask to prevent hitting any pending interrupts
2978 * after powering up the card again.
2979 */
2980 if (atomic_read(&host->clks_on)) {
2981 writel_relaxed(0, host->base + MMCIMASK0);
2982 mb();
2983 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302984 break;
2985 case MMC_POWER_UP:
2986 /* writing PWR_UP bit is redundant */
2987 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302988 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302989
Subhash Jadavani937c7502012-06-01 15:34:46 +05302990 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302991 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302992 msmsdcc_setup_pins(host, true);
2993 break;
2994 case MMC_POWER_ON:
2995 pwr = MCI_PWR_ON;
2996 break;
2997 }
2998
2999out:
3000 return pwr;
3001}
3002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
3004{
3005 unsigned int wakeup_irq;
3006
3007 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3008 host->plat->sdiowakeup_irq :
3009 host->core_irqres->start;
3010
3011 if (!host->irq_wake_enabled) {
3012 enable_irq_wake(wakeup_irq);
3013 host->irq_wake_enabled = true;
3014 }
3015}
3016
3017static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
3018{
3019 unsigned int wakeup_irq;
3020
3021 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3022 host->plat->sdiowakeup_irq :
3023 host->core_irqres->start;
3024
3025 if (host->irq_wake_enabled) {
3026 disable_irq_wake(wakeup_irq);
3027 host->irq_wake_enabled = false;
3028 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05303029}
3030
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303031/* Returns required bandwidth in Bytes per Sec */
3032static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
3033 struct mmc_ios *ios)
3034{
3035 unsigned int bw;
3036
3037 bw = host->clk_rate;
3038 /*
3039 * For DDR mode, SDCC controller clock will be at
3040 * the double rate than the actual clock that goes to card.
3041 */
3042 if (ios->bus_width == MMC_BUS_WIDTH_4)
3043 bw /= 2;
3044 else if (ios->bus_width == MMC_BUS_WIDTH_1)
3045 bw /= 8;
3046
3047 return bw;
3048}
3049
3050static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
3051 unsigned int bw)
3052{
3053 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
3054 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
3055 int i;
3056
3057 if (host->msm_bus_vote.is_max_bw_needed && bw)
3058 return host->msm_bus_vote.max_bw_vote;
3059
3060 for (i = 0; i < size; i++) {
3061 if (bw <= table[i])
3062 break;
3063 }
3064
3065 if (i && (i == size))
3066 i--;
3067
3068 return i;
3069}
3070
3071static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
3072{
3073 int rc = 0;
3074 struct msm_bus_scale_pdata *use_cases;
3075
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303076 if (host->pdev->dev.of_node) {
3077 struct msm_mmc_bus_voting_data *data;
3078 struct device *dev = &host->pdev->dev;
3079
3080 data = devm_kzalloc(dev,
3081 sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
3082 if (!data) {
3083 dev_err(&host->pdev->dev,
3084 "%s: failed to allocate memory\n", __func__);
3085 rc = -ENOMEM;
3086 goto out;
3087 }
3088
3089 rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
3090 &data->bw_vecs, &data->bw_vecs_size, 0);
3091 if (!rc) {
3092 data->use_cases = msm_bus_cl_get_pdata(host->pdev);
3093 host->plat->msm_bus_voting_data = data;
3094 }
3095 }
3096
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303097 if (host->plat->msm_bus_voting_data &&
3098 host->plat->msm_bus_voting_data->use_cases &&
3099 host->plat->msm_bus_voting_data->bw_vecs &&
3100 host->plat->msm_bus_voting_data->bw_vecs_size) {
3101 use_cases = host->plat->msm_bus_voting_data->use_cases;
3102 host->msm_bus_vote.client_handle =
3103 msm_bus_scale_register_client(use_cases);
3104 } else {
3105 return 0;
3106 }
3107
3108 if (!host->msm_bus_vote.client_handle) {
3109 pr_err("%s: msm_bus_scale_register_client() failed\n",
3110 mmc_hostname(host->mmc));
3111 rc = -EFAULT;
3112 } else {
3113 /* cache the vote index for minimum and maximum bandwidth */
3114 host->msm_bus_vote.min_bw_vote =
3115 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3116 host->msm_bus_vote.max_bw_vote =
3117 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3118 }
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303119out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303120 return rc;
3121}
3122
3123static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3124{
3125 if (host->msm_bus_vote.client_handle)
3126 msm_bus_scale_unregister_client(
3127 host->msm_bus_vote.client_handle);
3128}
3129
3130/*
3131 * This function must be called with host lock acquired.
3132 * Caller of this function should also ensure that msm bus client
3133 * handle is not null.
3134 */
3135static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3136 int vote,
3137 unsigned long flags)
3138{
3139 int rc = 0;
3140
3141 if (vote != host->msm_bus_vote.curr_vote) {
3142 spin_unlock_irqrestore(&host->lock, flags);
3143 rc = msm_bus_scale_client_update_request(
3144 host->msm_bus_vote.client_handle, vote);
3145 if (rc)
3146 pr_err("%s: msm_bus_scale_client_update_request() failed."
3147 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3148 mmc_hostname(host->mmc),
3149 host->msm_bus_vote.client_handle, vote, rc);
3150 spin_lock_irqsave(&host->lock, flags);
3151 if (!rc)
3152 host->msm_bus_vote.curr_vote = vote;
3153 }
3154
3155 return rc;
3156}
3157
3158/*
3159 * Internal work. Work to set 0 bandwidth for msm bus.
3160 */
3161static void msmsdcc_msm_bus_work(struct work_struct *work)
3162{
3163 struct msmsdcc_host *host = container_of(work,
3164 struct msmsdcc_host,
3165 msm_bus_vote.vote_work.work);
3166 unsigned long flags;
3167
3168 if (!host->msm_bus_vote.client_handle)
3169 return;
3170
3171 spin_lock_irqsave(&host->lock, flags);
3172 /* don't vote for 0 bandwidth if any request is in progress */
3173 if (!host->curr.mrq)
3174 msmsdcc_msm_bus_set_vote(host,
3175 host->msm_bus_vote.min_bw_vote, flags);
3176 else
3177 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3178 " bus voting to 0 bandwidth\n",
3179 mmc_hostname(host->mmc), __func__);
3180 spin_unlock_irqrestore(&host->lock, flags);
3181}
3182
3183/*
3184 * This function cancels any scheduled delayed work
3185 * and sets the bus vote based on ios argument.
3186 * If "ios" argument is NULL, bandwidth required is 0 else
3187 * calculate the bandwidth based on ios parameters.
3188 */
3189static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3190 struct msmsdcc_host *host,
3191 struct mmc_ios *ios)
3192{
3193 unsigned long flags;
3194 unsigned int bw;
3195 int vote;
3196
3197 if (!host->msm_bus_vote.client_handle)
3198 return;
3199
3200 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3201
3202 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3203 spin_lock_irqsave(&host->lock, flags);
3204 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3205 msmsdcc_msm_bus_set_vote(host, vote, flags);
3206 spin_unlock_irqrestore(&host->lock, flags);
3207}
3208
3209/* This function queues a work which will set the bandwidth requiement to 0 */
3210static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3211{
3212 unsigned long flags;
3213
3214 if (!host->msm_bus_vote.client_handle)
3215 return;
3216
3217 spin_lock_irqsave(&host->lock, flags);
3218 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3219 queue_delayed_work(system_nrt_wq,
3220 &host->msm_bus_vote.vote_work,
3221 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3222 spin_unlock_irqrestore(&host->lock, flags);
3223}
3224
San Mehat9d2bd732009-09-22 16:44:22 -07003225static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303226msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3227{
3228 struct mmc_host *mmc = host->mmc;
3229
3230 /*
3231 * SDIO_AL clients has different mechanism of handling LPM through
3232 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3233 * part of that. Here, we are interested only in clients like WLAN.
3234 */
3235 if (!(mmc->card && mmc_card_sdio(mmc->card))
3236 || host->plat->is_sdio_al_client)
3237 goto out;
3238
3239 if (!host->sdcc_suspended) {
3240 /*
3241 * When MSM is not in power collapse and we
3242 * are disabling clocks, enable bit 22 in MASK0
3243 * to handle asynchronous SDIO interrupts.
3244 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303245 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303246 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303247 mb();
3248 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303249 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303250 msmsdcc_sync_reg_wr(host);
3251 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303252 goto out;
3253 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3254 /*
3255 * Wakeup MSM only if SDIO function drivers set
3256 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3257 */
3258 goto out;
3259 }
3260
3261 if (enable_wakeup_irq) {
3262 if (!host->plat->sdiowakeup_irq) {
3263 /*
3264 * When there is no gpio line that can be configured
3265 * as wakeup interrupt handle it by configuring
3266 * asynchronous sdio interrupts and DAT1 line.
3267 */
3268 writel_relaxed(MCI_SDIOINTMASK,
3269 host->base + MMCIMASK0);
3270 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303271 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303272 /* configure sdcc core interrupt as wakeup interrupt */
3273 msmsdcc_enable_irq_wake(host);
3274 } else {
3275 /* Let gpio line handle wakeup interrupt */
3276 writel_relaxed(0, host->base + MMCIMASK0);
3277 mb();
3278 if (host->sdio_wakeupirq_disabled) {
3279 host->sdio_wakeupirq_disabled = 0;
3280 /* configure gpio line as wakeup interrupt */
3281 msmsdcc_enable_irq_wake(host);
3282 enable_irq(host->plat->sdiowakeup_irq);
3283 }
3284 }
3285 } else {
3286 if (!host->plat->sdiowakeup_irq) {
3287 /*
3288 * We may not have cleared bit 22 in the interrupt
3289 * handler as the clocks might be off at that time.
3290 */
3291 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303292 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303293 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303294 msmsdcc_disable_irq_wake(host);
3295 } else if (!host->sdio_wakeupirq_disabled) {
3296 disable_irq_nosync(host->plat->sdiowakeup_irq);
3297 msmsdcc_disable_irq_wake(host);
3298 host->sdio_wakeupirq_disabled = 1;
3299 }
3300 }
3301out:
3302 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003303}
3304
3305static void
3306msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3307{
3308 struct msmsdcc_host *host = mmc_priv(mmc);
3309 u32 clk = 0, pwr = 0;
3310 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003311 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003313
Sahitya Tummala7a892482011-01-18 11:22:49 +05303314
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303315 /*
3316 * Disable SDCC core interrupt until set_ios is completed.
3317 * This avoids any race conditions with interrupt raised
3318 * when turning on/off the clocks. One possible
3319 * scenario is SDIO operational interrupt while the clock
3320 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303321 * host->lock is being released intermittently below.
3322 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303323 */
3324
Asutosh Dasf5298c32012-04-03 14:51:47 +05303325 mutex_lock(&host->clk_mutex);
3326 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003327 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303328 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303329 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303330 host->sdcc_irq_disabled = 1;
3331 }
San Mehatd0719e52009-12-03 10:58:54 -08003332 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003333
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303334 /* Make sure sdcc core irq is synchronized */
3335 synchronize_irq(host->core_irqres->start);
3336
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303337 pwr = msmsdcc_setup_pwr(host, ios);
3338
3339 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003340 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303341 spin_unlock_irqrestore(&host->lock, flags);
3342 rc = msmsdcc_setup_clocks(host, true);
3343 if (rc)
3344 goto out;
3345 spin_lock_irqsave(&host->lock, flags);
3346 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3347 mb();
3348 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303350
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003351 /*
3352 * For DDR50 mode, controller needs clock rate to be
3353 * double than what is required on the SD card CLK pin.
Subhash Jadavani2877d912012-10-09 20:01:56 +05303354 *
3355 * Setting DDR timing mode in controller before setting the
3356 * clock rate will make sure that card don't see the double
3357 * clock rate even for very small duration. Some eMMC
3358 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303360 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2877d912012-10-09 20:01:56 +05303361 u32 clk;
3362
3363 clk = readl_relaxed(host->base + MMCICLOCK);
3364 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3365 clk |= (3 << 14); /* set DDR timing mode */
3366 writel_relaxed(clk, host->base + MMCICLOCK);
3367 msmsdcc_sync_reg_wr(host);
3368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 /*
3370 * Make sure that we don't double the clock if
3371 * doubled clock rate is already set
3372 */
3373 if (!host->ddr_doubled_clk_rate ||
3374 (host->ddr_doubled_clk_rate &&
3375 (host->ddr_doubled_clk_rate != ios->clock))) {
3376 host->ddr_doubled_clk_rate =
3377 msmsdcc_get_sup_clk_rate(
3378 host, (ios->clock * 2));
3379 clock = host->ddr_doubled_clk_rate;
3380 }
3381 } else {
3382 host->ddr_doubled_clk_rate = 0;
3383 }
3384
3385 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303386 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003387 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303388 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003389 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303390 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391 mmc_hostname(mmc), clock);
3392 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303393 host->reg_write_delay =
3394 (1 + ((3 * USEC_PER_SEC) /
3395 (host->clk_rate ? host->clk_rate :
3396 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 }
3398 /*
3399 * give atleast 2 MCLK cycles delay for clocks
3400 * and SDCC core to stabilize
3401 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303402 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003404 clk |= MCI_CLK_ENABLE;
3405 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 if (ios->bus_width == MMC_BUS_WIDTH_8)
3407 clk |= MCI_CLK_WIDEBUS_8;
3408 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3409 clk |= MCI_CLK_WIDEBUS_4;
3410 else
3411 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003413 if (msmsdcc_is_pwrsave(host))
3414 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003416 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003418 host->tuning_needed = 0;
3419 /*
3420 * Select the controller timing mode according
3421 * to current bus speed mode
3422 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303423 if (host->clk_rate > (100 * 1000 * 1000) &&
3424 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3425 ios->timing == MMC_TIMING_MMC_HS200)) {
3426 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427 clk |= (4 << 14);
3428 host->tuning_needed = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003429 } else {
Subhash Jadavani355df542012-10-09 19:06:49 +05303430 if (ios->timing == MMC_TIMING_UHS_DDR50)
3431 clk |= (3 << 14);
3432 else
3433 clk |= (2 << 14); /* feedback clock */
3434
3435 host->tuning_done = false;
3436 if (atomic_read(&host->clks_on)) {
3437 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3438 writel_relaxed((readl_relaxed(host->base +
3439 MCI_DLL_CONFIG) | MCI_DLL_RST),
3440 host->base + MCI_DLL_CONFIG);
3441
3442 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3443 writel_relaxed((readl_relaxed(host->base +
3444 MCI_DLL_CONFIG) | MCI_DLL_PDN),
3445 host->base + MCI_DLL_CONFIG);
3446 }
San Mehat9d2bd732009-09-22 16:44:22 -07003447 }
3448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3450 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452 if (host->io_pad_pwr_switch)
3453 clk |= IO_PAD_PWR_SWITCH;
3454
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303455 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303456 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303457 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3458 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303459 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003460 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303461 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3462 host->pwr = pwr;
3463 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303464 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 }
San Mehat9d2bd732009-09-22 16:44:22 -07003466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303468 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303469 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303470 spin_unlock_irqrestore(&host->lock, flags);
3471 /*
3472 * May get a wake-up interrupt the instant we disable the
3473 * clocks. This would disable the wake-up interrupt.
3474 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303476 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303478
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303479 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303480 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303481 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303482
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303483 /* Let interrupts be disabled if the host is powered off */
3484 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3485 enable_irq(host->core_irqres->start);
3486 host->sdcc_irq_disabled = 0;
3487 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003488 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303489out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303490 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003491}
3492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3494{
3495 struct msmsdcc_host *host = mmc_priv(mmc);
3496 u32 clk;
3497
3498 clk = readl_relaxed(host->base + MMCICLOCK);
3499 pr_debug("Changing to pwr_save=%d", pwrsave);
3500 if (pwrsave && msmsdcc_is_pwrsave(host))
3501 clk |= MCI_CLK_PWRSAVE;
3502 else
3503 clk &= ~MCI_CLK_PWRSAVE;
3504 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303505 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003506
3507 return 0;
3508}
3509
3510static int msmsdcc_get_ro(struct mmc_host *mmc)
3511{
3512 int status = -ENOSYS;
3513 struct msmsdcc_host *host = mmc_priv(mmc);
3514
3515 if (host->plat->wpswitch) {
3516 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303517 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 status = gpio_request(host->plat->wpswitch_gpio,
3519 "SD_WP_Switch");
3520 if (status) {
3521 pr_err("%s: %s: Failed to request GPIO %d\n",
3522 mmc_hostname(mmc), __func__,
3523 host->plat->wpswitch_gpio);
3524 } else {
3525 status = gpio_direction_input(
3526 host->plat->wpswitch_gpio);
3527 if (!status) {
3528 /*
3529 * Wait for atleast 300ms as debounce
3530 * time for GPIO input to stabilize.
3531 */
3532 msleep(300);
3533 status = gpio_get_value_cansleep(
3534 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303535 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 }
3537 gpio_free(host->plat->wpswitch_gpio);
3538 }
3539 }
3540
3541 if (status < 0)
3542 status = -ENOSYS;
3543 pr_debug("%s: Card read-only status %d\n", __func__, status);
3544
3545 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003546}
3547
3548static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3549{
3550 struct msmsdcc_host *host = mmc_priv(mmc);
3551 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303553 /*
3554 * We may come here with clocks turned off in that case don't
3555 * attempt to write into MASK0 register. While turning on the
3556 * clocks mci_irqenable will be written to MASK0 register.
3557 */
San Mehat9d2bd732009-09-22 16:44:22 -07003558
3559 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303562 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303563 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303565 mb();
3566 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567 } else {
3568 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303569 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303570 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003571 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303572 mb();
3573 }
San Mehat9d2bd732009-09-22 16:44:22 -07003574 }
3575 spin_unlock_irqrestore(&host->lock, flags);
3576}
3577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303579static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003580{
subhashj245831e2012-04-30 18:46:17 +05303581 struct device *dev = mmc_dev(host->mmc);
3582
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303583 pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
Subhash Jadavani386ad802012-08-16 18:46:57 +05303584 mmc_hostname(host->mmc), host->sdcc_suspended,
3585 host->pending_resume, host->sdcc_suspending);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303586 pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
subhashj245831e2012-04-30 18:46:17 +05303587 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3588 " request_pending=%d, request=%d\n",
3589 mmc_hostname(host->mmc), dev->power.runtime_status,
3590 atomic_read(&dev->power.usage_count),
3591 dev->power.is_suspended, dev->power.disable_depth,
3592 dev->power.runtime_error, dev->power.request_pending,
3593 dev->power.request);
3594}
3595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003596static int msmsdcc_enable(struct mmc_host *mmc)
3597{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003598 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003599 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003600 struct msmsdcc_host *host = mmc_priv(mmc);
3601
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303602 msmsdcc_pm_qos_update_latency(host, 1);
3603
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003604 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303605 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606
Subhash Jadavani386ad802012-08-16 18:46:57 +05303607 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003608 host->pending_resume = false;
3609 pm_runtime_get_noresume(dev);
3610 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303611 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003612 }
3613
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303614 if (dev->power.runtime_status == RPM_SUSPENDING) {
3615 if (mmc->suspend_task == current) {
3616 pm_runtime_get_noresume(dev);
3617 goto out;
3618 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303619 } else if (dev->power.runtime_status == RPM_RESUMING) {
3620 pm_runtime_get_noresume(dev);
3621 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303622 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003623
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303624 rc = pm_runtime_get_sync(dev);
3625
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303626skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303627 if (rc < 0) {
Subhash Jadavani386ad802012-08-16 18:46:57 +05303628 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3629 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303630 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303631 return rc;
3632 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303633out:
3634 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303635 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636}
3637
Steve Mucklef132c6c2012-06-06 18:30:57 -07003638static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639{
3640 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303641 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003642
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303643 msmsdcc_pm_qos_update_latency(host, 0);
3644
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303645 if (mmc->card && mmc_card_sdio(mmc->card)) {
3646 rc = 0;
3647 goto out;
3648 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303649
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303650 if (host->plat->disable_runtime_pm)
3651 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652
3653 rc = pm_runtime_put_sync(mmc->parent);
3654
Subhash Jadavani386ad802012-08-16 18:46:57 +05303655 if (rc < 0) {
3656 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3657 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303658 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003659 return rc;
3660 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303661
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303662out:
3663 msmsdcc_msm_bus_queue_work(host);
3664 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003665}
3666#else
subhashj245831e2012-04-30 18:46:17 +05303667static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3668
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303669static int msmsdcc_enable(struct mmc_host *mmc)
3670{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003671 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303672 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303673 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303674
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303675 msmsdcc_pm_qos_update_latency(host, 1);
3676
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303677 if (mmc->card && mmc_card_sdio(mmc->card)) {
3678 rc = 0;
3679 goto out;
3680 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003681
3682 if (host->sdcc_suspended && host->pending_resume) {
3683 host->pending_resume = false;
3684 rc = msmsdcc_runtime_resume(dev);
3685 goto out;
3686 }
3687
Asutosh Dasf5298c32012-04-03 14:51:47 +05303688 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303689 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303690 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303691
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003692out:
3693 if (rc < 0) {
3694 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3695 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303696 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003697 return rc;
3698 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303699 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303700 return 0;
3701}
3702
Steve Mucklef132c6c2012-06-06 18:30:57 -07003703static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303704{
3705 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303706 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303707
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303708 msmsdcc_pm_qos_update_latency(host, 0);
3709
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303710 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303711 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303712
Asutosh Dasf5298c32012-04-03 14:51:47 +05303713 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303714 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303715 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303716
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303717 if (rc) {
3718 msmsdcc_pm_qos_update_latency(host, 1);
3719 return rc;
3720 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303721out:
3722 msmsdcc_msm_bus_queue_work(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303723 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303724}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725#endif
3726
Subhash Jadavani937c7502012-06-01 15:34:46 +05303727static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3728 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003729{
3730 struct msmsdcc_host *host = mmc_priv(mmc);
3731 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303732 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733
Subhash Jadavani937c7502012-06-01 15:34:46 +05303734 switch (ios->signal_voltage) {
3735 case MMC_SIGNAL_VOLTAGE_330:
3736 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3737 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303738 if (!rc)
3739 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303740 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303741 case MMC_SIGNAL_VOLTAGE_180:
3742 break;
3743 case MMC_SIGNAL_VOLTAGE_120:
3744 /*
3745 * For eMMC cards, VDD_IO voltage range must be changed
3746 * only if it operates in HS200 SDR 1.2V mode or in
3747 * DDR 1.2V mode.
3748 */
3749 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303750 if (!rc)
3751 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303753 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003754 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303755 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003756 goto out;
3757 }
San Mehat9d2bd732009-09-22 16:44:22 -07003758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759 /*
3760 * If we are here means voltage switch from high voltage to
3761 * low voltage is required
3762 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303763 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764
3765 /*
3766 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3767 * register until they become all zeros.
3768 */
3769 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303770 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3772 mmc_hostname(mmc), __func__);
3773 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003774 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775
3776 /* Stop SD CLK output. */
3777 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3778 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303779 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003780 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781
3782 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303783 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3784 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303786 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303787 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003788 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303790 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791
3792 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3793 usleep_range(5000, 5500);
3794
3795 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303796 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003797 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3798 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303799 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003800 spin_unlock_irqrestore(&host->lock, flags);
3801
3802 /*
3803 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3804 * don't become all ones within 1 ms then a Voltage Switch
3805 * sequence has failed and a power cycle to the card is required.
3806 * Otherwise Voltage Switch sequence is completed successfully.
3807 */
3808 usleep_range(1000, 1500);
3809
3810 spin_lock_irqsave(&host->lock, flags);
3811 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3812 != (0xF << 1)) {
3813 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3814 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303815 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816 goto out_unlock;
3817 }
3818
3819out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303820 /* Enable PWRSAVE */
3821 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3822 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303823 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 spin_unlock_irqrestore(&host->lock, flags);
3825out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303826 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003827}
3828
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303829static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003831 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003832
3833 /* Program the MCLK value to MCLK_FREQ bit field */
3834 if (host->clk_rate <= 112000000)
3835 mclk_freq = 0;
3836 else if (host->clk_rate <= 125000000)
3837 mclk_freq = 1;
3838 else if (host->clk_rate <= 137000000)
3839 mclk_freq = 2;
3840 else if (host->clk_rate <= 150000000)
3841 mclk_freq = 3;
3842 else if (host->clk_rate <= 162000000)
3843 mclk_freq = 4;
3844 else if (host->clk_rate <= 175000000)
3845 mclk_freq = 5;
3846 else if (host->clk_rate <= 187000000)
3847 mclk_freq = 6;
3848 else if (host->clk_rate <= 200000000)
3849 mclk_freq = 7;
3850
3851 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3852 & ~(7 << 24)) | (mclk_freq << 24)),
3853 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854}
3855
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303856/* Initialize the DLL (Programmable Delay Line ) */
3857static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303860 unsigned long flags;
3861 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303863 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003864 /*
3865 * Make sure that clock is always enabled when DLL
3866 * tuning is in progress. Keeping PWRSAVE ON may
3867 * turn off the clock. So let's disable the PWRSAVE
3868 * here and re-enable it once tuning is completed.
3869 */
3870 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3871 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303872 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303873
3874 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3875 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3876 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3877
3878 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3879 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3880 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3881
3882 msmsdcc_cm_sdc4_dll_set_freq(host);
3883
3884 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3885 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3886 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3887
3888 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3889 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3890 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3891
3892 /* Set DLL_EN bit to 1. */
3893 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3894 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3895
3896 /* Set CK_OUT_EN bit to 1. */
3897 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3898 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3899
3900 wait_cnt = 50;
3901 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3902 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3903 /* max. wait for 50us sec for LOCK bit to be set */
3904 if (--wait_cnt == 0) {
3905 pr_err("%s: %s: DLL failed to LOCK\n",
3906 mmc_hostname(host->mmc), __func__);
3907 rc = -ETIMEDOUT;
3908 goto out;
3909 }
3910 /* wait for 1us before polling again */
3911 udelay(1);
3912 }
3913
3914out:
3915 /* re-enable PWRSAVE */
3916 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3917 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303918 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303919 spin_unlock_irqrestore(&host->lock, flags);
3920
3921 return rc;
3922}
3923
3924static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3925 u8 poll)
3926{
3927 int rc = 0;
3928 u32 wait_cnt = 50;
3929 u8 ck_out_en = 0;
3930
3931 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3932 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3933 MCI_CK_OUT_EN);
3934
3935 while (ck_out_en != poll) {
3936 if (--wait_cnt == 0) {
3937 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3938 mmc_hostname(host->mmc), __func__, poll);
3939 rc = -ETIMEDOUT;
3940 goto out;
3941 }
3942 udelay(1);
3943
3944 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3945 MCI_CK_OUT_EN);
3946 }
3947out:
3948 return rc;
3949}
3950
3951/*
3952 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3953 * calibration sequence. This function should be called before
3954 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3955 * commands (CMD17/CMD18).
3956 *
3957 * This function gets called when host spinlock acquired.
3958 */
3959static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3960{
3961 int rc = 0;
3962 u32 config;
3963
3964 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3965 config |= MCI_CDR_EN;
3966 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3967 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3968
3969 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3970 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3971 if (rc)
3972 goto err_out;
3973
3974 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3975 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3976 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3977
3978 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3979 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3980 if (rc)
3981 goto err_out;
3982
3983 goto out;
3984
3985err_out:
3986 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3987out:
3988 return rc;
3989}
3990
3991static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3992 u8 phase)
3993{
3994 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303995 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3996 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3997 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303998 unsigned long flags;
3999 u32 config;
4000
4001 spin_lock_irqsave(&host->lock, flags);
4002
4003 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4004 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
4005 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
4006 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4007
4008 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
4009 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
4010 if (rc)
4011 goto err_out;
4012
4013 /*
4014 * Write the selected DLL clock output phase (0 ... 15)
4015 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
4016 */
4017 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
4018 & ~(0xF << 20))
4019 | (grey_coded_phase_table[phase] << 20)),
4020 host->base + MCI_DLL_CONFIG);
4021
4022 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4023 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4024 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4025
4026 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4027 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4028 if (rc)
4029 goto err_out;
4030
4031 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4032 config |= MCI_CDR_EN;
4033 config &= ~MCI_CDR_EXT_EN;
4034 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4035 goto out;
4036
4037err_out:
4038 pr_err("%s: %s: Failed to set DLL phase: %d\n",
4039 mmc_hostname(host->mmc), __func__, phase);
4040out:
4041 spin_unlock_irqrestore(&host->lock, flags);
4042 return rc;
4043}
4044
4045/*
4046 * Find out the greatest range of consecuitive selected
4047 * DLL clock output phases that can be used as sampling
4048 * setting for SD3.0 UHS-I card read operation (in SDR104
4049 * timing mode) or for eMMC4.5 card read operation (in HS200
4050 * timing mode).
4051 * Select the 3/4 of the range and configure the DLL with the
4052 * selected DLL clock output phase.
4053*/
Subhash Jadavani34187042012-03-02 10:59:49 +05304054static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304055 u8 *phase_table, u8 total_phases)
4056{
Subhash Jadavani6159c622012-03-15 19:05:55 +05304057 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05304058 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05304059 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
4060 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304061 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304062 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
4063 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304064
Subhash Jadavani6159c622012-03-15 19:05:55 +05304065 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304066 pr_err("%s: %s: invalid argument: total_phases=%d\n",
4067 mmc_hostname(host->mmc), __func__, total_phases);
4068 return -EINVAL;
4069 }
4070
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304071 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304072 ranges[row_index][col_index] = phase_table[cnt];
4073 phases_per_row[row_index] += 1;
4074 col_index++;
4075
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304076 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304077 continue;
4078 /* check if next phase in phase_table is consecutive or not */
4079 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
4080 row_index++;
4081 col_index = 0;
4082 }
4083 }
4084
Subhash Jadavani6159c622012-03-15 19:05:55 +05304085 if (row_index >= MAX_PHASES)
4086 return -EINVAL;
4087
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304088 /* Check if phase-0 is present in first valid window? */
4089 if (!ranges[0][0]) {
4090 phase_0_found = true;
4091 phase_0_raw_index = 0;
4092 /* Check if cycle exist between 2 valid windows */
4093 for (cnt = 1; cnt <= row_index; cnt++) {
4094 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05304095 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304096 if (ranges[cnt][i] == 15) {
4097 phase_15_found = true;
4098 phase_15_raw_index = cnt;
4099 break;
4100 }
4101 }
4102 }
4103 }
4104 }
4105
4106 /* If 2 valid windows form cycle then merge them as single window */
4107 if (phase_0_found && phase_15_found) {
4108 /* number of phases in raw where phase 0 is present */
4109 u8 phases_0 = phases_per_row[phase_0_raw_index];
4110 /* number of phases in raw where phase 15 is present */
4111 u8 phases_15 = phases_per_row[phase_15_raw_index];
4112
Subhash Jadavani6159c622012-03-15 19:05:55 +05304113 if (phases_0 + phases_15 >= MAX_PHASES)
4114 /*
4115 * If there are more than 1 phase windows then total
4116 * number of phases in both the windows should not be
4117 * more than or equal to MAX_PHASES.
4118 */
4119 return -EINVAL;
4120
4121 /* Merge 2 cyclic windows */
4122 i = phases_15;
4123 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304124 ranges[phase_15_raw_index][i] =
4125 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304126 if (++i >= MAX_PHASES)
4127 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304128 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304129
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304130 phases_per_row[phase_0_raw_index] = 0;
4131 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4132 }
4133
4134 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304135 if (phases_per_row[cnt] > curr_max) {
4136 curr_max = phases_per_row[cnt];
4137 selected_row_index = cnt;
4138 }
4139 }
4140
Subhash Jadavani6159c622012-03-15 19:05:55 +05304141 i = ((curr_max * 3) / 4);
4142 if (i)
4143 i--;
4144
Subhash Jadavani34187042012-03-02 10:59:49 +05304145 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304146
Subhash Jadavani6159c622012-03-15 19:05:55 +05304147 if (ret >= MAX_PHASES) {
4148 ret = -EINVAL;
4149 pr_err("%s: %s: invalid phase selected=%d\n",
4150 mmc_hostname(host->mmc), __func__, ret);
4151 }
4152
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304153 return ret;
4154}
4155
Girish K Sa3f41692012-02-29 12:00:09 +05304156static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304157{
4158 int rc = 0;
4159 struct msmsdcc_host *host = mmc_priv(mmc);
4160 unsigned long flags;
4161 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304162 const u32 *tuning_block_pattern = tuning_block_64;
4163 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304164 bool is_tuning_all_phases;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304165
4166 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4167
4168 /* Tuning is only required for SDR104 modes */
4169 if (!host->tuning_needed) {
4170 rc = 0;
4171 goto exit;
4172 }
4173
4174 spin_lock_irqsave(&host->lock, flags);
4175 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304176 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304177 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4178
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304179 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304180 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4181 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4182 tuning_block_pattern = tuning_block_128;
4183 size = sizeof(tuning_block_128);
4184 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304185 spin_unlock_irqrestore(&host->lock, flags);
4186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 /* first of all reset the tuning block */
4188 rc = msmsdcc_init_cm_sdc4_dll(host);
4189 if (rc)
4190 goto out;
4191
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304192 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193 if (!data_buf) {
4194 rc = -ENOMEM;
4195 goto out;
4196 }
4197
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304198 is_tuning_all_phases = !(host->mmc->card &&
4199 (host->saved_tuning_phase != INVALID_TUNING_PHASE));
4200retry:
4201 if (is_tuning_all_phases)
4202 phase = 0; /* start from phase 0 during init */
4203 else
4204 phase = (u8)host->saved_tuning_phase;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004205 do {
4206 struct mmc_command cmd = {0};
4207 struct mmc_data data = {0};
4208 struct mmc_request mrq = {
4209 .cmd = &cmd,
4210 .data = &data
4211 };
4212 struct scatterlist sg;
4213
4214 /* set the phase in delay line hw block */
4215 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4216 if (rc)
4217 goto kfree;
4218
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304219 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4221
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304222 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 data.blocks = 1;
4224 data.flags = MMC_DATA_READ;
4225 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4226
4227 data.sg = &sg;
4228 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304229 sg_init_one(&sg, data_buf, size);
4230 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 mmc_wait_for_req(mmc, &mrq);
4232
4233 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304234 !memcmp(data_buf, tuning_block_pattern, size)) {
4235 /* tuning is successful at this tuning point */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304236 if (!is_tuning_all_phases)
4237 goto kfree;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304239 pr_debug("%s: %s: found good phase = %d\n",
4240 mmc_hostname(mmc), __func__, phase);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304241 } else if (!is_tuning_all_phases) {
4242 pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
4243 mmc_hostname(mmc), (u32)phase);
4244 is_tuning_all_phases = true;
4245 goto retry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004246 }
4247 } while (++phase < 16);
4248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304250 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304251 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304252 if (rc < 0)
4253 goto kfree;
4254 else
4255 phase = (u8)rc;
4256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004257 /*
4258 * Finally set the selected phase in delay
4259 * line hw block.
4260 */
4261 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4262 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304263 goto kfree;
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304264 else
4265 host->saved_tuning_phase = phase;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304266 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4267 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004268 } else {
4269 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304270 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004271 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304272 msmsdcc_dump_sdcc_state(host);
4273 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004274 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275
4276kfree:
4277 kfree(data_buf);
4278out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304279 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304280 host->tuning_in_progress = 0;
Subhash Jadavani355df542012-10-09 19:06:49 +05304281 if (!rc)
4282 host->tuning_done = true;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304283 spin_unlock_irqrestore(&host->lock, flags);
4284exit:
4285 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004286 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004287}
4288
Asutosh Dasebd7d092012-07-09 19:08:26 +05304289/*
4290 * Work around of the unavailability of a power_reset functionality in SD cards
4291 * by turning the OFF & back ON the regulators supplying the SD card.
4292 */
4293void msmsdcc_hw_reset(struct mmc_host *mmc)
4294{
4295 struct mmc_card *card = mmc->card;
4296 struct msmsdcc_host *host = mmc_priv(mmc);
4297 int rc;
4298
4299 /* Write-protection bits would be lost on a hardware reset in emmc */
4300 if (!card || !mmc_card_sd(card))
4301 return;
4302
Pratibhasagar V1aa03dc2012-11-29 12:48:17 +05304303 pr_debug("%s: Starting h/w reset\n", mmc_hostname(host->mmc));
4304
4305 if (host->plat->translate_vdd || host->plat->vreg_data) {
4306
4307 /* Disable the regulators */
4308 if (host->plat->translate_vdd)
4309 rc = host->plat->translate_vdd(mmc_dev(mmc), 0);
4310 else if (host->plat->vreg_data)
4311 rc = msmsdcc_setup_vreg(host, false, false);
4312
4313 if (rc) {
4314 pr_err("%s: Failed to disable voltage regulator\n",
4315 mmc_hostname(host->mmc));
4316 BUG_ON(rc);
4317 }
4318
4319 /* 10ms delay for supply to reach the desired voltage level */
4320 usleep_range(10000, 12000);
4321
4322 /* Enable the regulators */
4323 if (host->plat->translate_vdd)
4324 rc = host->plat->translate_vdd(mmc_dev(mmc), 1);
4325 else if (host->plat->vreg_data)
4326 rc = msmsdcc_setup_vreg(host, true, false);
4327
4328 if (rc) {
4329 pr_err("%s: Failed to enable voltage regulator\n",
4330 mmc_hostname(host->mmc));
4331 BUG_ON(rc);
4332 }
4333
4334 /* 10ms delay for supply to reach the desired voltage level */
4335 usleep_range(10000, 12000);
Asutosh Dasebd7d092012-07-09 19:08:26 +05304336 }
Asutosh Dasebd7d092012-07-09 19:08:26 +05304337}
4338
Subhash Jadavanid076af72013-02-17 23:36:03 +02004339/**
4340 * msmsdcc_stop_request - stops ongoing request
4341 * @mmc: MMC host, running the request
4342 *
4343 * Stops currently running request synchronously. All relevant request
4344 * information is cleared.
4345 */
4346int msmsdcc_stop_request(struct mmc_host *mmc)
4347{
4348 struct msmsdcc_host *host = mmc_priv(mmc);
4349 struct mmc_request *mrq;
4350 unsigned long flags;
4351 int rc = 0;
4352
4353 spin_lock_irqsave(&host->lock, flags);
4354 mrq = host->curr.mrq;
4355 if (mrq) {
4356 msmsdcc_reset_and_restore(host);
4357 /*
4358 * Note: We are just taking care of SPS. We may also
4359 * need to think about ADM (and PIO?) later if required.
4360 */
4361 if (host->sps.sg && is_sps_mode(host)) {
4362 if (!mrq->data->host_cookie)
4363 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
4364 host->sps.num_ents, host->sps.dir);
4365 host->sps.sg = NULL;
4366 host->sps.busy = 0;
4367 }
4368
4369 /*
4370 * Clear current request information as current
4371 * request has ended
4372 */
4373 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
4374 del_timer(&host->req_tout_timer);
4375 } else {
4376 rc = -EINVAL;
4377 }
4378 spin_unlock_irqrestore(&host->lock, flags);
4379
4380 return rc;
4381}
4382
4383/**
4384 * msmsdcc_get_xfer_remain - returns number of bytes passed on bus
4385 * @mmc: MMC host, running the request
4386 *
4387 * Returns the number of bytes passed for SPS transfer. 0 - for non-SPS
4388 * transfer.
4389 */
4390unsigned int msmsdcc_get_xfer_remain(struct mmc_host *mmc)
4391{
4392 struct msmsdcc_host *host = mmc_priv(mmc);
4393 u32 data_cnt = 0;
4394
4395 /* Currently, we don't support to stop the non-SPS transfer */
4396 if (host->sps.busy && atomic_read(&host->clks_on))
4397 data_cnt = readl_relaxed(host->base + MMCIDATACNT);
4398
4399 return data_cnt;
4400}
4401
San Mehat9d2bd732009-09-22 16:44:22 -07004402static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004403 .enable = msmsdcc_enable,
4404 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304405 .pre_req = msmsdcc_pre_req,
4406 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004407 .request = msmsdcc_request,
4408 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004409 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004410 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304411 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304412 .execute_tuning = msmsdcc_execute_tuning,
4413 .hw_reset = msmsdcc_hw_reset,
Subhash Jadavanid076af72013-02-17 23:36:03 +02004414 .stop_request = msmsdcc_stop_request,
4415 .get_xfer_remain = msmsdcc_get_xfer_remain,
San Mehat9d2bd732009-09-22 16:44:22 -07004416};
4417
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304418static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4419{
4420 unsigned int gpio_no = host->plat->status_gpio;
4421 int status;
4422
4423 if (!gpio_is_valid(gpio_no))
4424 return;
4425
4426 status = gpio_request(gpio_no, "SD_HW_Detect");
4427 if (status)
4428 pr_err("%s: %s: gpio_request(%d) failed\n",
4429 mmc_hostname(host->mmc), __func__, gpio_no);
4430}
4431
4432static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4433{
4434 if (gpio_is_valid(host->plat->status_gpio))
4435 gpio_free(host->plat->status_gpio);
4436}
4437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004438static unsigned int
4439msmsdcc_slot_status(struct msmsdcc_host *host)
4440{
4441 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004442
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304443 status = gpio_get_value_cansleep(host->plat->status_gpio);
4444 if (host->plat->is_status_gpio_active_low)
4445 status = !status;
4446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447 return status;
4448}
4449
San Mehat9d2bd732009-09-22 16:44:22 -07004450static void
4451msmsdcc_check_status(unsigned long data)
4452{
4453 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4454 unsigned int status;
4455
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304456 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004457 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004458 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004459 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004460 status = msmsdcc_slot_status(host);
4461
Krishna Konda941604a2012-01-10 17:46:34 -08004462 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004464 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004465 if (host->plat->status)
4466 pr_info("%s: Slot status change detected "
4467 "(%d -> %d)\n",
4468 mmc_hostname(host->mmc),
4469 host->oldstat, status);
4470 else if (host->plat->is_status_gpio_active_low)
4471 pr_info("%s: Slot status change detected "
4472 "(%d -> %d) and the card detect GPIO"
4473 " is ACTIVE_LOW\n",
4474 mmc_hostname(host->mmc),
4475 host->oldstat, status);
4476 else
4477 pr_info("%s: Slot status change detected "
4478 "(%d -> %d) and the card detect GPIO"
4479 " is ACTIVE_HIGH\n",
4480 mmc_hostname(host->mmc),
4481 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004482 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483 }
4484 host->oldstat = status;
4485 } else {
4486 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004487 }
San Mehat9d2bd732009-09-22 16:44:22 -07004488}
4489
4490static irqreturn_t
4491msmsdcc_platform_status_irq(int irq, void *dev_id)
4492{
4493 struct msmsdcc_host *host = dev_id;
4494
Girish K Sa3c76eb2011-10-11 11:44:09 +05304495 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004496 msmsdcc_check_status((unsigned long) host);
4497 return IRQ_HANDLED;
4498}
4499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004500static irqreturn_t
4501msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4502{
4503 struct msmsdcc_host *host = dev_id;
4504
4505 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4506 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304507 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304509 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 wake_lock(&host->sdio_wlock);
4511 msmsdcc_disable_irq_wake(host);
4512 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304513 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 }
4515 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004516 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304517 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304518 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304519 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004520 }
4521 spin_unlock(&host->lock);
4522
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304523out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 return IRQ_HANDLED;
4525}
4526
San Mehat9d2bd732009-09-22 16:44:22 -07004527static void
4528msmsdcc_status_notify_cb(int card_present, void *dev_id)
4529{
4530 struct msmsdcc_host *host = dev_id;
4531
Girish K Sa3c76eb2011-10-11 11:44:09 +05304532 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004533 card_present);
4534 msmsdcc_check_status((unsigned long) host);
4535}
4536
San Mehat9d2bd732009-09-22 16:44:22 -07004537static int
4538msmsdcc_init_dma(struct msmsdcc_host *host)
4539{
4540 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4541 host->dma.host = host;
4542 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004543 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004544
4545 if (!host->dmares)
4546 return -ENODEV;
4547
4548 host->dma.nc = dma_alloc_coherent(NULL,
4549 sizeof(struct msmsdcc_nc_dmadata),
4550 &host->dma.nc_busaddr,
4551 GFP_KERNEL);
4552 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004553 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004554 return -ENOMEM;
4555 }
4556 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4557 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4558 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4559 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4560 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004561 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004562
4563 return 0;
4564}
4565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4567/**
4568 * Allocate and Connect a SDCC peripheral's SPS endpoint
4569 *
4570 * This function allocates endpoint context and
4571 * connect it with memory endpoint by calling
4572 * appropriate SPS driver APIs.
4573 *
4574 * Also registers a SPS callback function with
4575 * SPS driver
4576 *
4577 * This function should only be called once typically
4578 * during driver probe.
4579 *
4580 * @host - Pointer to sdcc host structure
4581 * @ep - Pointer to sps endpoint data structure
4582 * @is_produce - 1 means Producer endpoint
4583 * 0 means Consumer endpoint
4584 *
4585 * @return - 0 if successful else negative value.
4586 *
4587 */
4588static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4589 struct msmsdcc_sps_ep_conn_data *ep,
4590 bool is_producer)
4591{
4592 int rc = 0;
4593 struct sps_pipe *sps_pipe_handle;
4594 struct sps_connect *sps_config = &ep->config;
4595 struct sps_register_event *sps_event = &ep->event;
4596
4597 /* Allocate endpoint context */
4598 sps_pipe_handle = sps_alloc_endpoint();
4599 if (!sps_pipe_handle) {
4600 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4601 mmc_hostname(host->mmc), is_producer);
4602 rc = -ENOMEM;
4603 goto out;
4604 }
4605
4606 /* Get default connection configuration for an endpoint */
4607 rc = sps_get_config(sps_pipe_handle, sps_config);
4608 if (rc) {
4609 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4610 " rc=%d", mmc_hostname(host->mmc),
4611 (u32)sps_pipe_handle, rc);
4612 goto get_config_err;
4613 }
4614
4615 /* Modify the default connection configuration */
4616 if (is_producer) {
4617 /*
4618 * For SDCC producer transfer, source should be
4619 * SDCC peripheral where as destination should
4620 * be system memory.
4621 */
4622 sps_config->source = host->sps.bam_handle;
4623 sps_config->destination = SPS_DEV_HANDLE_MEM;
4624 /* Producer pipe will handle this connection */
4625 sps_config->mode = SPS_MODE_SRC;
4626 sps_config->options =
4627 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4628 } else {
4629 /*
4630 * For SDCC consumer transfer, source should be
4631 * system memory where as destination should
4632 * SDCC peripheral
4633 */
4634 sps_config->source = SPS_DEV_HANDLE_MEM;
4635 sps_config->destination = host->sps.bam_handle;
4636 sps_config->mode = SPS_MODE_DEST;
4637 sps_config->options =
4638 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4639 }
4640
4641 /* Producer pipe index */
4642 sps_config->src_pipe_index = host->sps.src_pipe_index;
4643 /* Consumer pipe index */
4644 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4645 /*
4646 * This event thresold value is only significant for BAM-to-BAM
4647 * transfer. It's ignored for BAM-to-System mode transfer.
4648 */
4649 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304650
4651 /* Allocate maximum descriptor fifo size */
4652 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4653 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004654 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4655 sps_config->desc.size,
4656 &sps_config->desc.phys_base,
4657 GFP_KERNEL);
4658
Pratibhasagar V00b94332011-10-18 14:57:27 +05304659 if (!sps_config->desc.base) {
4660 rc = -ENOMEM;
4661 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4662 , mmc_hostname(host->mmc));
4663 goto get_config_err;
4664 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4666
4667 /* Establish connection between peripheral and memory endpoint */
4668 rc = sps_connect(sps_pipe_handle, sps_config);
4669 if (rc) {
4670 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4671 " rc=%d", mmc_hostname(host->mmc),
4672 (u32)sps_pipe_handle, rc);
4673 goto sps_connect_err;
4674 }
4675
4676 sps_event->mode = SPS_TRIGGER_CALLBACK;
4677 sps_event->options = SPS_O_EOT;
4678 sps_event->callback = msmsdcc_sps_complete_cb;
4679 sps_event->xfer_done = NULL;
4680 sps_event->user = (void *)host;
4681
4682 /* Register callback event for EOT (End of transfer) event. */
4683 rc = sps_register_event(sps_pipe_handle, sps_event);
4684 if (rc) {
4685 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4686 " rc=%d", mmc_hostname(host->mmc),
4687 (u32)sps_pipe_handle, rc);
4688 goto reg_event_err;
4689 }
4690 /* Now save the sps pipe handle */
4691 ep->pipe_handle = sps_pipe_handle;
4692 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4693 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4694 __func__, is_producer ? "READ" : "WRITE",
4695 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4696 goto out;
4697
4698reg_event_err:
4699 sps_disconnect(sps_pipe_handle);
4700sps_connect_err:
4701 dma_free_coherent(mmc_dev(host->mmc),
4702 sps_config->desc.size,
4703 sps_config->desc.base,
4704 sps_config->desc.phys_base);
4705get_config_err:
4706 sps_free_endpoint(sps_pipe_handle);
4707out:
4708 return rc;
4709}
4710
4711/**
4712 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4713 *
4714 * This function disconnect endpoint and deallocates
4715 * endpoint context.
4716 *
4717 * This function should only be called once typically
4718 * during driver remove.
4719 *
4720 * @host - Pointer to sdcc host structure
4721 * @ep - Pointer to sps endpoint data structure
4722 *
4723 */
4724static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4725 struct msmsdcc_sps_ep_conn_data *ep)
4726{
4727 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4728 struct sps_connect *sps_config = &ep->config;
4729 struct sps_register_event *sps_event = &ep->event;
4730
4731 sps_event->xfer_done = NULL;
4732 sps_event->callback = NULL;
4733 sps_register_event(sps_pipe_handle, sps_event);
4734 sps_disconnect(sps_pipe_handle);
4735 dma_free_coherent(mmc_dev(host->mmc),
4736 sps_config->desc.size,
4737 sps_config->desc.base,
4738 sps_config->desc.phys_base);
4739 sps_free_endpoint(sps_pipe_handle);
4740}
4741
4742/**
4743 * Reset SDCC peripheral's SPS endpoint
4744 *
4745 * This function disconnects an endpoint.
4746 *
4747 * This function should be called for reseting
4748 * SPS endpoint when data transfer error is
4749 * encountered during data transfer. This
4750 * can be considered as soft reset to endpoint.
4751 *
4752 * This function should only be called if
4753 * msmsdcc_sps_init() is already called.
4754 *
4755 * @host - Pointer to sdcc host structure
4756 * @ep - Pointer to sps endpoint data structure
4757 *
4758 * @return - 0 if successful else negative value.
4759 */
4760static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4761 struct msmsdcc_sps_ep_conn_data *ep)
4762{
4763 int rc = 0;
4764 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4765
4766 rc = sps_disconnect(sps_pipe_handle);
4767 if (rc) {
4768 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4769 " rc=%d", mmc_hostname(host->mmc), __func__,
4770 (u32)sps_pipe_handle, rc);
4771 goto out;
4772 }
4773 out:
4774 return rc;
4775}
4776
4777/**
4778 * Restore SDCC peripheral's SPS endpoint
4779 *
4780 * This function connects an endpoint.
4781 *
4782 * This function should be called for restoring
4783 * SPS endpoint after data transfer error is
4784 * encountered during data transfer. This
4785 * can be considered as soft reset to endpoint.
4786 *
4787 * This function should only be called if
4788 * msmsdcc_sps_reset_ep() is called before.
4789 *
4790 * @host - Pointer to sdcc host structure
4791 * @ep - Pointer to sps endpoint data structure
4792 *
4793 * @return - 0 if successful else negative value.
4794 */
4795static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4796 struct msmsdcc_sps_ep_conn_data *ep)
4797{
4798 int rc = 0;
4799 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4800 struct sps_connect *sps_config = &ep->config;
4801 struct sps_register_event *sps_event = &ep->event;
4802
4803 /* Establish connection between peripheral and memory endpoint */
4804 rc = sps_connect(sps_pipe_handle, sps_config);
4805 if (rc) {
4806 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4807 " rc=%d", mmc_hostname(host->mmc), __func__,
4808 (u32)sps_pipe_handle, rc);
4809 goto out;
4810 }
4811
4812 /* Register callback event for EOT (End of transfer) event. */
4813 rc = sps_register_event(sps_pipe_handle, sps_event);
4814 if (rc) {
4815 pr_err("%s: %s: sps_register_event() failed!!!"
4816 " pipe_handle=0x%x, rc=%d",
4817 mmc_hostname(host->mmc), __func__,
4818 (u32)sps_pipe_handle, rc);
4819 goto reg_event_err;
4820 }
4821 goto out;
4822
4823reg_event_err:
4824 sps_disconnect(sps_pipe_handle);
4825out:
4826 return rc;
4827}
4828
4829/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004830 * Handle BAM device's global error condition
4831 *
4832 * This is an error handler for the SDCC bam device
4833 *
4834 * This function is registered as a callback with SPS-BAM
4835 * driver and will called in case there are an errors for
4836 * the SDCC BAM deivce. Any error conditions in the BAM
4837 * device are global and will be result in this function
4838 * being called once per device.
4839 *
4840 * This function will be called from the sps driver's
4841 * interrupt context.
4842 *
4843 * @sps_cb_case - indicates what error it is
4844 * @user - Pointer to sdcc host structure
4845 */
4846static void
4847msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4848{
4849 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4850 struct mmc_request *mrq;
4851 unsigned long flags;
4852 int32_t error = 0;
4853
4854 BUG_ON(!host);
4855 BUG_ON(!is_sps_mode(host));
4856
4857 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004858 /* Reset all endpoints along with resetting bam. */
4859 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004860
4861 pr_err("%s: BAM Global ERROR IRQ happened\n",
4862 mmc_hostname(host->mmc));
4863 error = EAGAIN;
4864 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4865 /**
4866 * This means that there was an AHB access error and
4867 * the address we are trying to read/write is something
4868 * we dont have priviliges to do so.
4869 */
4870 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4871 mmc_hostname(host->mmc));
4872 error = EACCES;
4873 } else {
4874 /**
4875 * This should not have happened ideally. If this happens
4876 * there is some seriously wrong.
4877 */
4878 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4879 mmc_hostname(host->mmc), (u32) sps_cb_case);
4880 error = EIO;
4881 }
4882
4883 spin_lock_irqsave(&host->lock, flags);
4884
4885 mrq = host->curr.mrq;
4886
4887 if (mrq && mrq->cmd) {
4888 msmsdcc_dump_sdcc_state(host);
4889
4890 if (!mrq->cmd->error)
4891 mrq->cmd->error = -error;
4892 if (host->curr.data) {
4893 if (mrq->data && !mrq->data->error)
4894 mrq->data->error = -error;
4895 host->curr.data_xfered = 0;
4896 if (host->sps.sg && is_sps_mode(host)) {
4897 /* Stop current SPS transfer */
4898 msmsdcc_sps_exit_curr_xfer(host);
4899 } else {
4900 /* this condition should not have happened */
4901 pr_err("%s: something is seriously wrong. "\
4902 "Funtion: %s, line: %d\n",
4903 mmc_hostname(host->mmc),
4904 __func__, __LINE__);
4905 }
4906 } else {
4907 /* this condition should not have happened */
4908 pr_err("%s: something is seriously wrong. Funtion: "\
4909 "%s, line: %d\n", mmc_hostname(host->mmc),
4910 __func__, __LINE__);
4911 }
4912 }
4913 spin_unlock_irqrestore(&host->lock, flags);
4914}
4915
4916/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004917 * Initialize SPS HW connected with SDCC core
4918 *
4919 * This function register BAM HW resources with
4920 * SPS driver and then initialize 2 SPS endpoints
4921 *
4922 * This function should only be called once typically
4923 * during driver probe.
4924 *
4925 * @host - Pointer to sdcc host structure
4926 *
4927 * @return - 0 if successful else negative value.
4928 *
4929 */
4930static int msmsdcc_sps_init(struct msmsdcc_host *host)
4931{
4932 int rc = 0;
4933 struct sps_bam_props bam = {0};
4934
4935 host->bam_base = ioremap(host->bam_memres->start,
4936 resource_size(host->bam_memres));
4937 if (!host->bam_base) {
4938 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4939 " size=0x%x", mmc_hostname(host->mmc),
4940 host->bam_memres->start,
4941 (host->bam_memres->end -
4942 host->bam_memres->start));
4943 rc = -ENOMEM;
4944 goto out;
4945 }
4946
4947 bam.phys_addr = host->bam_memres->start;
4948 bam.virt_addr = host->bam_base;
4949 /*
4950 * This event thresold value is only significant for BAM-to-BAM
4951 * transfer. It's ignored for BAM-to-System mode transfer.
4952 */
4953 bam.event_threshold = 0x10; /* Pipe event threshold */
4954 /*
4955 * This threshold controls when the BAM publish
4956 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304957 * SPS HW will be used for data transfer size even
4958 * less than SDCC FIFO size. So let's set BAM summing
4959 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004960 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304961 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004962 /* SPS driver wll handle the SDCC BAM IRQ */
4963 bam.irq = (u32)host->bam_irqres->start;
4964 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004965 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4966 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004967
4968 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4969 (u32)bam.phys_addr);
4970 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4971 (u32)bam.virt_addr);
4972
4973 /* Register SDCC Peripheral BAM device to SPS driver */
4974 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4975 if (rc) {
4976 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4977 mmc_hostname(host->mmc), rc);
4978 goto reg_bam_err;
4979 }
4980 pr_info("%s: BAM device registered. bam_handle=0x%x",
4981 mmc_hostname(host->mmc), host->sps.bam_handle);
4982
4983 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4984 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4985
4986 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4987 SPS_PROD_PERIPHERAL);
4988 if (rc)
4989 goto sps_reset_err;
4990 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4991 SPS_CONS_PERIPHERAL);
4992 if (rc)
4993 goto cons_conn_err;
4994
4995 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4996 mmc_hostname(host->mmc),
4997 (unsigned long long)host->bam_memres->start,
4998 (unsigned int)host->bam_irqres->start);
4999 goto out;
5000
5001cons_conn_err:
5002 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5003sps_reset_err:
5004 sps_deregister_bam_device(host->sps.bam_handle);
5005reg_bam_err:
5006 iounmap(host->bam_base);
5007out:
5008 return rc;
5009}
5010
5011/**
5012 * De-initialize SPS HW connected with SDCC core
5013 *
5014 * This function deinitialize SPS endpoints and then
5015 * deregisters BAM resources from SPS driver.
5016 *
5017 * This function should only be called once typically
5018 * during driver remove.
5019 *
5020 * @host - Pointer to sdcc host structure
5021 *
5022 */
5023static void msmsdcc_sps_exit(struct msmsdcc_host *host)
5024{
5025 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
5026 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5027 sps_deregister_bam_device(host->sps.bam_handle);
5028 iounmap(host->bam_base);
5029}
5030#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
5031
5032static ssize_t
5033show_polling(struct device *dev, struct device_attribute *attr, char *buf)
5034{
5035 struct mmc_host *mmc = dev_get_drvdata(dev);
5036 struct msmsdcc_host *host = mmc_priv(mmc);
5037 int poll;
5038 unsigned long flags;
5039
5040 spin_lock_irqsave(&host->lock, flags);
5041 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
5042 spin_unlock_irqrestore(&host->lock, flags);
5043
5044 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
5045}
5046
5047static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305048store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005049 const char *buf, size_t count)
5050{
5051 struct mmc_host *mmc = dev_get_drvdata(dev);
5052 struct msmsdcc_host *host = mmc_priv(mmc);
5053 int value;
5054 unsigned long flags;
5055
5056 sscanf(buf, "%d", &value);
5057
5058 spin_lock_irqsave(&host->lock, flags);
5059 if (value) {
5060 mmc->caps |= MMC_CAP_NEEDS_POLL;
5061 mmc_detect_change(host->mmc, 0);
5062 } else {
5063 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5064 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 spin_unlock_irqrestore(&host->lock, flags);
5066 return count;
5067}
5068
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305069static ssize_t
5070show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
5071 char *buf)
5072{
5073 struct mmc_host *mmc = dev_get_drvdata(dev);
5074 struct msmsdcc_host *host = mmc_priv(mmc);
5075
5076 return snprintf(buf, PAGE_SIZE, "%u\n",
5077 host->msm_bus_vote.is_max_bw_needed);
5078}
5079
5080static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305081store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305082 const char *buf, size_t count)
5083{
5084 struct mmc_host *mmc = dev_get_drvdata(dev);
5085 struct msmsdcc_host *host = mmc_priv(mmc);
5086 uint32_t value;
5087 unsigned long flags;
5088
5089 if (!kstrtou32(buf, 0, &value)) {
5090 spin_lock_irqsave(&host->lock, flags);
5091 host->msm_bus_vote.is_max_bw_needed = !!value;
5092 spin_unlock_irqrestore(&host->lock, flags);
5093 }
5094
5095 return count;
5096}
5097
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305098static ssize_t
5099show_idle_timeout(struct device *dev, struct device_attribute *attr,
5100 char *buf)
5101{
5102 struct mmc_host *mmc = dev_get_drvdata(dev);
5103 struct msmsdcc_host *host = mmc_priv(mmc);
5104
5105 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05305106 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305107}
5108
5109static ssize_t
5110store_idle_timeout(struct device *dev, struct device_attribute *attr,
5111 const char *buf, size_t count)
5112{
5113 struct mmc_host *mmc = dev_get_drvdata(dev);
5114 struct msmsdcc_host *host = mmc_priv(mmc);
5115 unsigned int long flags;
5116 int timeout; /* in secs */
5117
5118 if (!kstrtou32(buf, 0, &timeout)
5119 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
5120 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05305121 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305122 spin_unlock_irqrestore(&host->lock, flags);
5123 }
5124 return count;
5125}
5126
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305127static inline void set_auto_cmd_setting(struct device *dev,
5128 const char *buf,
5129 bool is_cmd19)
5130{
5131 struct mmc_host *mmc = dev_get_drvdata(dev);
5132 struct msmsdcc_host *host = mmc_priv(mmc);
5133 unsigned int long flags;
5134 int temp;
5135
5136 if (!kstrtou32(buf, 0, &temp)) {
5137 spin_lock_irqsave(&host->lock, flags);
5138 if (is_cmd19)
5139 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305140 else
5141 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305142 spin_unlock_irqrestore(&host->lock, flags);
5143 }
5144}
5145
5146static ssize_t
5147show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5148 char *buf)
5149{
5150 struct mmc_host *mmc = dev_get_drvdata(dev);
5151 struct msmsdcc_host *host = mmc_priv(mmc);
5152
5153 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
5154}
5155
5156static ssize_t
5157store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5158 const char *buf, size_t count)
5159{
5160 set_auto_cmd_setting(dev, buf, true);
5161
5162 return count;
5163}
5164
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305165static ssize_t
5166show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5167 char *buf)
5168{
5169 struct mmc_host *mmc = dev_get_drvdata(dev);
5170 struct msmsdcc_host *host = mmc_priv(mmc);
5171
5172 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5173}
5174
5175static ssize_t
5176store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5177 const char *buf, size_t count)
5178{
5179 set_auto_cmd_setting(dev, buf, false);
5180
5181 return count;
5182}
5183
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305184static void msmsdcc_print_regs(const char *name, void __iomem *base,
5185 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305186{
5187 unsigned int i;
5188
5189 if (!base)
5190 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305191
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305192 pr_err("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305193 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305194 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305195 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305196 (u32)readl_relaxed(base + i*4),
5197 (u32)readl_relaxed(base + ((i+1)*4)),
5198 (u32)readl_relaxed(base + ((i+2)*4)),
5199 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305200 }
5201}
5202
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305203/*
5204 * This function prints the testbus debug output for all the
5205 * available SDCC controller test bus.
5206 *
5207 * Note: This function should only be called if the SDCC is clocked.
5208 */
5209static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
5210{
5211 int testbus_num;
5212
5213 if (!is_testbus_debug(host))
5214 return;
5215
5216 pr_err("== SDCC Test Bus Debug ==");
5217 for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
5218 writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
5219 | MCI_TESTBUS_ENA),
5220 host->base + MCI_TESTBUS_CONFIG);
5221 pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
5222 (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
5223 }
5224 /* Disable the test bus output */
5225 writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
5226}
5227
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305228static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5229{
5230 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305231 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305232 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305233 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305234 mmc_hostname(host->mmc),
5235 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305236 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305237 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305238 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5239
5240 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305241 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305242 msmsdcc_print_regs("SDCC-CORE", host->base,
5243 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305244 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5245 mmc_hostname(host->mmc),
5246 readl_relaxed(host->base + MCI_TEST_INPUT));
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305247 msmsdcc_print_testbus_info(host);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305248 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305249
5250 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305251 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305252 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305253 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305254 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305255 mmc_hostname(host->mmc), host->dma.busy,
5256 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305257 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305258 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305259 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5260 host->dml_memres->start,
5261 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305262 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305263 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305264 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305265
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305266 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305267 mmc_hostname(host->mmc), host->curr.xfer_size,
5268 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305269 }
5270
Krishna Konda3ca90f02012-08-29 16:29:21 -07005271 if (host->sps.reset_bam)
5272 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5273 mmc_hostname(host->mmc), host->sps.reset_bam);
5274
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305275 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305276 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5277 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5278 host->curr.got_dataend, host->prog_enable,
5279 host->curr.wait_for_auto_prog_done,
5280 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305281 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305282}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005284static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5285{
5286 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5287 struct mmc_request *mrq;
5288 unsigned long flags;
5289
5290 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005291 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005292 pr_info("%s: %s: dummy CMD52 timeout\n",
5293 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005294 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005295 }
5296
5297 mrq = host->curr.mrq;
5298
5299 if (mrq && mrq->cmd) {
Subhash Jadavani926a9cb2012-12-15 22:05:54 +05305300 if (!mrq->cmd->bkops_busy) {
5301 pr_info("%s: CMD%d: Request timeout\n",
5302 mmc_hostname(host->mmc), mrq->cmd->opcode);
5303 msmsdcc_dump_sdcc_state(host);
5304 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005306 if (!mrq->cmd->error)
5307 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305308 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005309 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005310 if (mrq->data && !mrq->data->error)
5311 mrq->data->error = -ETIMEDOUT;
5312 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305313 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005314 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305315 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005316 /* Stop current SPS transfer */
5317 msmsdcc_sps_exit_curr_xfer(host);
5318 } else {
5319 msmsdcc_reset_and_restore(host);
5320 msmsdcc_stop_data(host);
5321 if (mrq->data && mrq->data->stop)
5322 msmsdcc_start_command(host,
5323 mrq->data->stop, 0);
5324 else
5325 msmsdcc_request_end(host, mrq);
5326 }
5327 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305328 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305329 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005330 msmsdcc_reset_and_restore(host);
5331 msmsdcc_request_end(host, mrq);
5332 }
5333 }
5334 spin_unlock_irqrestore(&host->lock, flags);
5335}
5336
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305337/*
5338 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5339 *
5340 * @dev: device node from which the property value is to be read.
5341 * @prop_name: name of the property to be searched.
5342 * @out_array: filled array returned to caller
5343 * @len: filled array size returned to caller
5344 * @size: expected size of the array
5345 *
5346 * If expected "size" doesn't match with "len" an error is returned. If
5347 * expected size is zero, the length of actual array is returned provided
5348 * return value is zero.
5349 *
5350 * RETURNS:
5351 * zero on success, negative error if failed.
5352 */
5353static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5354 u32 **out_array, int *len, int size)
5355{
5356 int ret = 0;
5357 u32 *array = NULL;
5358 struct device_node *np = dev->of_node;
5359
5360 if (of_get_property(np, prop_name, len)) {
5361 size_t sz;
5362 sz = *len = *len / sizeof(*array);
5363
5364 if (sz > 0 && !(size > 0 && (sz != size))) {
5365 array = devm_kzalloc(dev, sz * sizeof(*array),
5366 GFP_KERNEL);
5367 if (!array) {
5368 dev_err(dev, "%s: no memory\n", prop_name);
5369 ret = -ENOMEM;
5370 goto out;
5371 }
5372
5373 ret = of_property_read_u32_array(np, prop_name,
5374 array, sz);
5375 if (ret < 0) {
5376 dev_err(dev, "%s: error reading array %d\n",
5377 prop_name, ret);
5378 goto out;
5379 }
5380 } else {
5381 dev_err(dev, "%s invalid size\n", prop_name);
5382 ret = -EINVAL;
5383 goto out;
5384 }
5385 } else {
5386 dev_err(dev, "%s not specified\n", prop_name);
5387 ret = -EINVAL;
5388 goto out;
5389 }
5390 *out_array = array;
5391out:
5392 if (ret)
5393 *len = 0;
5394 return ret;
5395}
5396
5397static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5398 struct msm_mmc_pad_pull_data **pad_pull_data)
5399{
5400 int ret = 0, base = 0, len, i;
5401 u32 *tmp;
5402 struct msm_mmc_pad_pull_data *pull_data;
5403 struct msm_mmc_pad_pull *pull;
5404
5405 switch (id) {
5406 case 1:
5407 base = TLMM_PULL_SDC1_CLK;
5408 break;
5409 case 2:
5410 base = TLMM_PULL_SDC2_CLK;
5411 break;
5412 case 3:
5413 base = TLMM_PULL_SDC3_CLK;
5414 break;
5415 case 4:
5416 base = TLMM_PULL_SDC4_CLK;
5417 break;
5418 default:
5419 dev_err(dev, "%s: Invalid slot id\n", __func__);
5420 ret = -EINVAL;
5421 goto err;
5422 }
5423
5424 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5425 GFP_KERNEL);
5426 if (!pull_data) {
5427 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5428 ret = -ENOMEM;
5429 goto err;
5430 }
5431 pull_data->size = 3; /* array size for clk, cmd, data */
5432
5433 /* Allocate on, off configs for clk, cmd, data */
5434 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5435 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5436 if (!pull) {
5437 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5438 ret = -ENOMEM;
5439 goto err;
5440 }
5441 pull_data->on = pull;
5442 pull_data->off = pull + pull_data->size;
5443
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005444 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305445 &tmp, &len, pull_data->size);
5446 if (!ret) {
5447 for (i = 0; i < len; i++) {
5448 pull_data->on[i].no = base + i;
5449 pull_data->on[i].val = tmp[i];
5450 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5451 i, pull_data->on[i].val);
5452 }
5453 } else {
5454 goto err;
5455 }
5456
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005457 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305458 &tmp, &len, pull_data->size);
5459 if (!ret) {
5460 for (i = 0; i < len; i++) {
5461 pull_data->off[i].no = base + i;
5462 pull_data->off[i].val = tmp[i];
5463 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5464 i, pull_data->off[i].val);
5465 }
5466 } else {
5467 goto err;
5468 }
5469
5470 *pad_pull_data = pull_data;
5471err:
5472 return ret;
5473}
5474
5475static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5476 struct msm_mmc_pad_drv_data **pad_drv_data)
5477{
5478 int ret = 0, base = 0, len, i;
5479 u32 *tmp;
5480 struct msm_mmc_pad_drv_data *drv_data;
5481 struct msm_mmc_pad_drv *drv;
5482
5483 switch (id) {
5484 case 1:
5485 base = TLMM_HDRV_SDC1_CLK;
5486 break;
5487 case 2:
5488 base = TLMM_HDRV_SDC2_CLK;
5489 break;
5490 case 3:
5491 base = TLMM_HDRV_SDC3_CLK;
5492 break;
5493 case 4:
5494 base = TLMM_HDRV_SDC4_CLK;
5495 break;
5496 default:
5497 dev_err(dev, "%s: Invalid slot id\n", __func__);
5498 ret = -EINVAL;
5499 goto err;
5500 }
5501
5502 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5503 GFP_KERNEL);
5504 if (!drv_data) {
5505 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5506 ret = -ENOMEM;
5507 goto err;
5508 }
5509 drv_data->size = 3; /* array size for clk, cmd, data */
5510
5511 /* Allocate on, off configs for clk, cmd, data */
5512 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5513 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5514 if (!drv) {
5515 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5516 ret = -ENOMEM;
5517 goto err;
5518 }
5519 drv_data->on = drv;
5520 drv_data->off = drv + drv_data->size;
5521
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005522 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305523 &tmp, &len, drv_data->size);
5524 if (!ret) {
5525 for (i = 0; i < len; i++) {
5526 drv_data->on[i].no = base + i;
5527 drv_data->on[i].val = tmp[i];
5528 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5529 i, drv_data->on[i].val);
5530 }
5531 } else {
5532 goto err;
5533 }
5534
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005535 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305536 &tmp, &len, drv_data->size);
5537 if (!ret) {
5538 for (i = 0; i < len; i++) {
5539 drv_data->off[i].no = base + i;
5540 drv_data->off[i].val = tmp[i];
5541 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5542 i, drv_data->off[i].val);
5543 }
5544 } else {
5545 goto err;
5546 }
5547
5548 *pad_drv_data = drv_data;
5549err:
5550 return ret;
5551}
5552
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305553static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5554 struct mmc_platform_data *pdata)
5555{
5556 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5557 struct device_node *np = dev->of_node;
5558
5559 pdata->status_gpio = of_get_named_gpio_flags(np,
5560 "cd-gpios", 0, &flags);
5561 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005562 struct platform_device *pdev = container_of(dev,
5563 struct platform_device, dev);
5564 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305565 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5566 }
5567
5568 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5569 "wp-gpios", 0, &flags);
5570 if (gpio_is_valid(pdata->wpswitch_gpio))
5571 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5572}
5573
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305574static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5575 struct mmc_platform_data *pdata)
5576{
5577 int ret = 0, id = 0, cnt, i;
5578 struct msm_mmc_pin_data *pin_data;
5579 struct device_node *np = dev->of_node;
5580
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305581 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5582
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305583 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5584 if (!pin_data) {
5585 dev_err(dev, "No memory for pin_data\n");
5586 ret = -ENOMEM;
5587 goto err;
5588 }
5589
5590 cnt = of_gpio_count(np);
5591 if (cnt > 0) {
5592 pin_data->is_gpio = true;
5593
5594 pin_data->gpio_data = devm_kzalloc(dev,
5595 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5596 if (!pin_data->gpio_data) {
5597 dev_err(dev, "No memory for gpio_data\n");
5598 ret = -ENOMEM;
5599 goto err;
5600 }
5601 pin_data->gpio_data->size = cnt;
5602 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5603 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5604 if (!pin_data->gpio_data->gpio) {
5605 dev_err(dev, "No memory for gpio\n");
5606 ret = -ENOMEM;
5607 goto err;
5608 }
5609
5610 for (i = 0; i < cnt; i++) {
5611 const char *name = NULL;
5612 char result[32];
5613 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5614 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005615 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305616
5617 snprintf(result, 32, "%s-%s",
5618 dev_name(dev), name ? name : "?");
5619 pin_data->gpio_data->gpio[i].name = result;
5620 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5621 pin_data->gpio_data->gpio[i].name,
5622 pin_data->gpio_data->gpio[i].no);
5623 }
5624 } else {
5625 pin_data->pad_data = devm_kzalloc(dev,
5626 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5627 if (!pin_data->pad_data) {
5628 dev_err(dev, "No memory for pin_data->pad_data\n");
5629 ret = -ENOMEM;
5630 goto err;
5631 }
5632
5633 of_property_read_u32(np, "cell-index", &id);
5634
5635 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5636 &pin_data->pad_data->pull);
5637 if (ret)
5638 goto err;
5639 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5640 &pin_data->pad_data->drv);
5641 if (ret)
5642 goto err;
5643 }
5644
5645 pdata->pin_data = pin_data;
5646err:
5647 if (ret)
5648 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5649 return ret;
5650}
5651
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305652#define MAX_PROP_SIZE 32
5653static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5654 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5655{
5656 int len, ret = 0;
5657 const __be32 *prop;
5658 char prop_name[MAX_PROP_SIZE];
5659 struct msm_mmc_reg_data *vreg;
5660 struct device_node *np = dev->of_node;
5661
5662 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5663 if (of_parse_phandle(np, prop_name, 0)) {
5664 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5665 if (!vreg) {
5666 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5667 ret = -ENOMEM;
5668 goto err;
5669 }
5670
5671 vreg->name = vreg_name;
5672
5673 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005674 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305675 if (of_get_property(np, prop_name, NULL))
5676 vreg->always_on = true;
5677
5678 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005679 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305680 if (of_get_property(np, prop_name, NULL))
5681 vreg->lpm_sup = true;
5682
5683 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005684 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305685 prop = of_get_property(np, prop_name, &len);
5686 if (!prop || (len != (2 * sizeof(__be32)))) {
5687 dev_warn(dev, "%s %s property\n",
5688 prop ? "invalid format" : "no", prop_name);
5689 } else {
5690 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5691 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5692 }
5693
5694 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005695 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305696 prop = of_get_property(np, prop_name, &len);
5697 if (!prop || (len != (2 * sizeof(__be32)))) {
5698 dev_warn(dev, "%s %s property\n",
5699 prop ? "invalid format" : "no", prop_name);
5700 } else {
5701 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5702 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5703 }
5704
5705 *vreg_data = vreg;
5706 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5707 vreg->name, vreg->always_on ? "always_on," : "",
5708 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5709 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5710 }
5711
5712err:
5713 return ret;
5714}
5715
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305716static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5717{
5718 int i, ret;
5719 struct mmc_platform_data *pdata;
5720 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305721 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005722 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305723 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305724
5725 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5726 if (!pdata) {
5727 dev_err(dev, "could not allocate memory for platform data\n");
5728 goto err;
5729 }
5730
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005731 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305732 if (bus_width == 8) {
5733 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5734 } else if (bus_width == 4) {
5735 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5736 } else {
5737 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5738 pdata->mmc_bus_width = 0;
5739 }
5740
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005741 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305742 &sup_voltages, &sup_volt_len, 0);
5743 if (!ret) {
5744 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305745 u32 mask;
5746
5747 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5748 sup_voltages[i + 1]);
5749 if (!mask)
5750 dev_err(dev, "Invalide voltage range %d\n", i);
5751 pdata->ocr_mask |= mask;
5752 }
5753 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305754 }
5755
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005756 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305757 &clk_table, &clk_table_len, 0);
5758 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305759 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305760 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305761 }
5762
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305763 pdata->vreg_data = devm_kzalloc(dev,
5764 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5765 if (!pdata->vreg_data) {
5766 dev_err(dev, "could not allocate memory for vreg_data\n");
5767 goto err;
5768 }
5769
5770 if (msmsdcc_dt_parse_vreg_info(dev,
5771 &pdata->vreg_data->vdd_data, "vdd"))
5772 goto err;
5773
5774 if (msmsdcc_dt_parse_vreg_info(dev,
5775 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5776 goto err;
5777
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305778 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5779 goto err;
5780
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005781 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305782
5783 for (i = 0; i < len; i++) {
5784 const char *name = NULL;
5785
5786 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005787 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305788 if (!name)
5789 continue;
5790
5791 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5792 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5793 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5794 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5795 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5796 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5797 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5798 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5799 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5800 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5801 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5802 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5803 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5804 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5805 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5806 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5807 | MMC_CAP_UHS_DDR50;
5808 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5809 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5810 | MMC_CAP_UHS_DDR50;
5811 }
5812
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005813 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305814 if (current_limit == 800)
5815 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5816 else if (current_limit == 600)
5817 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5818 else if (current_limit == 400)
5819 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5820 else if (current_limit == 200)
5821 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5822
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005823 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305824 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005825 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305826 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005827 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305828 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305829 of_property_read_u32(np, "qcom,dat1-mpm-int",
5830 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305831
5832 return pdata;
5833err:
5834 return NULL;
5835}
5836
San Mehat9d2bd732009-09-22 16:44:22 -07005837static int
5838msmsdcc_probe(struct platform_device *pdev)
5839{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305840 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005841 struct msmsdcc_host *host;
5842 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005843 unsigned long flags;
5844 struct resource *core_irqres = NULL;
5845 struct resource *bam_irqres = NULL;
5846 struct resource *core_memres = NULL;
5847 struct resource *dml_memres = NULL;
5848 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005849 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005850 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305851 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005852
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305853 if (pdev->dev.of_node) {
5854 plat = msmsdcc_populate_pdata(&pdev->dev);
5855 of_property_read_u32((&pdev->dev)->of_node,
5856 "cell-index", &pdev->id);
5857 } else {
5858 plat = pdev->dev.platform_data;
5859 }
San Mehat9d2bd732009-09-22 16:44:22 -07005860
5861 /* must have platform data */
5862 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005863 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005864 ret = -EINVAL;
5865 goto out;
5866 }
5867
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -08005868 if (disable_slots & (1 << (pdev->id - 1))) {
5869 pr_info("%s: Slot %d disabled\n", __func__, pdev->id);
5870 return -ENODEV;
5871 }
5872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005873 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005874 return -EINVAL;
5875
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305876 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5877 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5878 return -EINVAL;
5879 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005880
San Mehat9d2bd732009-09-22 16:44:22 -07005881 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005882 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005883 return -ENXIO;
5884 }
5885
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305886 core_memres = platform_get_resource_byname(pdev,
5887 IORESOURCE_MEM, "core_mem");
5888 bam_memres = platform_get_resource_byname(pdev,
5889 IORESOURCE_MEM, "bam_mem");
5890 dml_memres = platform_get_resource_byname(pdev,
5891 IORESOURCE_MEM, "dml_mem");
5892 core_irqres = platform_get_resource_byname(pdev,
5893 IORESOURCE_IRQ, "core_irq");
5894 bam_irqres = platform_get_resource_byname(pdev,
5895 IORESOURCE_IRQ, "bam_irq");
5896 dmares = platform_get_resource_byname(pdev,
5897 IORESOURCE_DMA, "dma_chnl");
5898 dma_crci_res = platform_get_resource_byname(pdev,
5899 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005901 if (!core_irqres || !core_memres) {
5902 pr_err("%s: Invalid sdcc core resource\n", __func__);
5903 return -ENXIO;
5904 }
5905
5906 /*
5907 * Both BAM and DML memory resource should be preset.
5908 * BAM IRQ resource should also be present.
5909 */
5910 if ((bam_memres && !dml_memres) ||
5911 (!bam_memres && dml_memres) ||
5912 ((bam_memres && dml_memres) && !bam_irqres)) {
5913 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005914 return -ENXIO;
5915 }
5916
5917 /*
5918 * Setup our host structure
5919 */
San Mehat9d2bd732009-09-22 16:44:22 -07005920 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5921 if (!mmc) {
5922 ret = -ENOMEM;
5923 goto out;
5924 }
5925
5926 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305927 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005928 host->plat = plat;
5929 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005930 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305931
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305932 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305933 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005934 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305935 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005937 host->base = ioremap(core_memres->start,
5938 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005939 if (!host->base) {
5940 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305941 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005942 }
5943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005944 host->core_irqres = core_irqres;
5945 host->bam_irqres = bam_irqres;
5946 host->core_memres = core_memres;
5947 host->dml_memres = dml_memres;
5948 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005949 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005950 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005951 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305952 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005954#ifdef CONFIG_MMC_EMBEDDED_SDIO
5955 if (plat->embedded_sdio)
5956 mmc_set_embedded_sdio_data(mmc,
5957 &plat->embedded_sdio->cis,
5958 &plat->embedded_sdio->cccr,
5959 plat->embedded_sdio->funcs,
5960 plat->embedded_sdio->num_funcs);
5961#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005962
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305963 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5964 (unsigned long)host);
5965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005966 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5967 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305968 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005969 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305970 ret = msmsdcc_init_dma(host);
5971 if (ret)
5972 goto ioremap_free;
5973 } else {
5974 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005975 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305976 }
San Mehat9d2bd732009-09-22 16:44:22 -07005977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005978 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305979 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005980 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305981 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5982 if (!IS_ERR_OR_NULL(host->bus_clk)) {
5983 /* Vote for max. clk rate for max. performance */
5984 ret = clk_set_rate(host->bus_clk, INT_MAX);
5985 if (ret)
5986 goto bus_clk_put;
5987 ret = clk_prepare_enable(host->bus_clk);
5988 if (ret)
5989 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07005990 }
5991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005992 /*
5993 * Setup main peripheral bus clock
5994 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07005995 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005996 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305997 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005998 if (ret)
5999 goto pclk_put;
6000
6001 host->pclk_rate = clk_get_rate(host->pclk);
6002 }
6003
6004 /*
6005 * Setup SDC MMC clock
6006 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006007 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07006008 if (IS_ERR(host->clk)) {
6009 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006010 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07006011 }
6012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006013 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05306014 if (ret) {
6015 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
6016 goto clk_put;
6017 }
6018
Asutosh Dasf5298c32012-04-03 14:51:47 +05306019 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006020 if (ret)
6021 goto clk_put;
6022
San Mehat9d2bd732009-09-22 16:44:22 -07006023 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306024 if (!host->clk_rate)
6025 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05306026
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306027 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05306028 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306029
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306030 /*
6031 * Set the register write delay according to min. clock frequency
6032 * supported and update later when the host->clk_rate changes.
6033 */
6034 host->reg_write_delay =
6035 (1 + ((3 * USEC_PER_SEC) /
6036 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006037
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306038 atomic_set(&host->clks_on, 1);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05306039 /* Apply Hard reset to SDCC to put it in power on default state */
6040 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006041
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006042#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306043 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006044 if (host->plat->cpu_dma_latency)
6045 host->cpu_dma_latency = host->plat->cpu_dma_latency;
6046 else
6047 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
6048 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306049 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
6050
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306051 ret = msmsdcc_msm_bus_register(host);
6052 if (ret)
6053 goto pm_qos_remove;
6054
6055 if (host->msm_bus_vote.client_handle)
6056 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
6057 msmsdcc_msm_bus_work);
6058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006059 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07006060 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006061 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07006062 goto clk_disable;
6063 }
6064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006065
6066 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306067 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006068 /* Initialize SPS */
6069 ret = msmsdcc_sps_init(host);
6070 if (ret)
6071 goto vreg_deinit;
6072 /* Initialize DML */
6073 ret = msmsdcc_dml_init(host);
6074 if (ret)
6075 goto sps_exit;
6076 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05306077 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07006078
San Mehat9d2bd732009-09-22 16:44:22 -07006079 /*
6080 * Setup MMC host structure
6081 */
6082 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006083 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
6084 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006085 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05306086 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
6087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006088 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
6089 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07006090 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05306091 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05306092 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306093 /*
6094 * If we send the CMD23 before multi block write/read command
6095 * then we need not to send CMD12 at the end of the transfer.
6096 * If we don't send the CMD12 then only way to detect the PROG_DONE
6097 * status is to use the AUTO_PROG_DONE status provided by SDCC4
6098 * controller. So let's enable the CMD23 for SDCC4 only.
6099 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306100 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306101 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07006102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05306104 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006105 /*
6106 * XPC controls the maximum current in the default speed mode of SDXC
6107 * card. XPC=0 means 100mA (max.) but speed class is not supported.
6108 * XPC=1 means 150mA (max.) and speed class is supported.
6109 */
6110 if (plat->xpc_cap)
6111 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
6112 MMC_CAP_SET_XPC_180);
6113
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02006114 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02006115 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05306116 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03006117 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03006118 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Maya Erezb7f382b2012-09-29 06:33:18 +02006119 mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02006120 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Yaniv Gardi14098552012-06-04 10:56:03 +03006121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006122 if (plat->nonremovable)
6123 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006124 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006125
6126 if (plat->is_sdio_al_client)
6127 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07006128
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306129 mmc->max_segs = msmsdcc_get_nr_sg(host);
6130 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
6131 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07006132
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306133 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07006134 mmc->max_seg_size = mmc->max_req_size;
6135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006136 writel_relaxed(0, host->base + MMCIMASK0);
6137 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05306138 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006140 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
6141 mb();
6142 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07006143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006144 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
6145 DRIVER_NAME " (cmd)", host);
6146 if (ret)
6147 goto dml_exit;
6148
6149 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
6150 DRIVER_NAME " (pio)", host);
6151 if (ret)
6152 goto irq_free;
6153
6154 /*
6155 * Enable SDCC IRQ only when host is powered on. Otherwise, this
6156 * IRQ is un-necessarily being monitored by MPM (Modem power
6157 * management block) during idle-power collapse. The MPM will be
6158 * configured to monitor the DATA1 GPIO line with level-low trigger
6159 * and thus depending on the GPIO status, it prevents TCXO shutdown
6160 * during idle-power collapse.
6161 */
6162 disable_irq(core_irqres->start);
6163 host->sdcc_irq_disabled = 1;
6164
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05306165 if (!plat->sdiowakeup_irq) {
6166 /* Check if registered as IORESOURCE_IRQ */
6167 plat->sdiowakeup_irq =
6168 platform_get_irq_byname(pdev, "sdiowakeup_irq");
6169 if (plat->sdiowakeup_irq < 0)
6170 plat->sdiowakeup_irq = 0;
6171 }
6172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006174 ret = request_irq(plat->sdiowakeup_irq,
6175 msmsdcc_platform_sdiowakeup_irq,
6176 IRQF_SHARED | IRQF_TRIGGER_LOW,
6177 DRIVER_NAME "sdiowakeup", host);
6178 if (ret) {
6179 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6180 plat->sdiowakeup_irq, ret);
6181 goto pio_irq_free;
6182 } else {
6183 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306184 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006185 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306186 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006187 }
6188 spin_unlock_irqrestore(&host->lock, flags);
6189 }
6190 }
6191
Krishna Konda1963f432013-02-19 20:28:53 -08006192 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006193 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6194 mmc_hostname(mmc));
6195 }
6196
6197 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6198 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006199 /*
6200 * Setup card detect change
6201 */
6202
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306203 if (!plat->status_gpio)
6204 plat->status_gpio = -ENOENT;
6205 if (!plat->wpswitch_gpio)
6206 plat->wpswitch_gpio = -ENOENT;
6207
6208 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306209 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006210 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306211 } else {
6212 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006213 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306214 }
Krishna Konda941604a2012-01-10 17:46:34 -08006215 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006216 }
San Mehat9d2bd732009-09-22 16:44:22 -07006217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006218 if (plat->status_irq) {
6219 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006220 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006221 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006222 DRIVER_NAME " (slot)",
6223 host);
6224 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006225 pr_err("Unable to get slot IRQ %d (%d)\n",
6226 plat->status_irq, ret);
6227 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006228 }
6229 } else if (plat->register_status_notify) {
6230 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6231 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006232 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006233 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006234
6235 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006236
6237 ret = pm_runtime_set_active(&(pdev)->dev);
6238 if (ret < 0)
6239 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6240 __func__, ret);
6241 /*
6242 * There is no notion of suspend/resume for SD/MMC/SDIO
6243 * cards. So host can be suspended/resumed with out
6244 * worrying about its children.
6245 */
6246 pm_suspend_ignore_children(&(pdev)->dev, true);
6247
6248 /*
6249 * MMC/SD/SDIO bus suspend/resume operations are defined
6250 * only for the slots that will be used for non-removable
6251 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6252 * defined. Otherwise, they simply become card removal and
6253 * insertion events during suspend and resume respectively.
6254 * Hence, enable run-time PM only for slots for which bus
6255 * suspend/resume operations are defined.
6256 */
6257#ifdef CONFIG_MMC_UNSAFE_RESUME
6258 /*
6259 * If this capability is set, MMC core will enable/disable host
6260 * for every claim/release operation on a host. We use this
6261 * notification to increment/decrement runtime pm usage count.
6262 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006263 pm_runtime_enable(&(pdev)->dev);
6264#else
6265 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006266 pm_runtime_enable(&(pdev)->dev);
6267 }
6268#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306269 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006270 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6271 (unsigned long)host);
6272
San Mehat9d2bd732009-09-22 16:44:22 -07006273 mmc_add_host(mmc);
6274
Sujit Reddy Thumma97a35d22012-10-31 22:45:45 +05306275 mmc->clk_scaling.up_threshold = 35;
6276 mmc->clk_scaling.down_threshold = 5;
6277 mmc->clk_scaling.polling_delay_ms = 100;
6278 mmc->caps2 |= MMC_CAP2_CLK_SCALE;
6279
Krishna Konda25786ec2011-07-25 16:21:36 -07006280 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
6281 " dmacrcri %d\n", mmc_hostname(mmc),
6282 (unsigned long long)core_memres->start,
6283 (unsigned int) core_irqres->start,
6284 (unsigned int) plat->status_irq, host->dma.channel,
6285 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006286
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306287 pr_info("%s: Controller capabilities: 0x%.8x\n",
6288 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006289 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6290 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6291 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6292 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6293 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6294 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6295 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6296 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6297 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6298 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6299 host->eject);
6300 pr_info("%s: Power save feature enable = %d\n",
6301 mmc_hostname(mmc), msmsdcc_pwrsave);
6302
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306303 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006304 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006305 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006306 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006307 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006308 mmc_hostname(mmc), host->dma.cmd_busaddr,
6309 host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306310 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006311 pr_info("%s: SPS-BAM data transfer mode available\n",
6312 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006313 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006314 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006316#if defined(CONFIG_DEBUG_FS)
6317 msmsdcc_dbg_createhost(host);
6318#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306319
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306320 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6321 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6322 sysfs_attr_init(&host->max_bus_bw.attr);
6323 host->max_bus_bw.attr.name = "max_bus_bw";
6324 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6325 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306326 if (ret)
6327 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306328
6329 if (!plat->status_irq) {
6330 host->polling.show = show_polling;
6331 host->polling.store = store_polling;
6332 sysfs_attr_init(&host->polling.attr);
6333 host->polling.attr.name = "polling";
6334 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6335 ret = device_create_file(&pdev->dev, &host->polling);
6336 if (ret)
6337 goto remove_max_bus_bw_file;
6338 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306339 host->idle_timeout.show = show_idle_timeout;
6340 host->idle_timeout.store = store_idle_timeout;
6341 sysfs_attr_init(&host->idle_timeout.attr);
6342 host->idle_timeout.attr.name = "idle_timeout";
6343 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6344 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6345 if (ret)
6346 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306347
6348 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306349 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306350
6351 /* Sysfs entry for AUTO CMD19 control */
6352 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6353 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6354 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6355 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6356 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6357 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6358 if (ret)
6359 goto remove_idle_timeout_file;
6360
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306361 add_auto_cmd21_atrr:
6362 if (!is_auto_cmd21(host))
6363 goto exit;
6364
6365 /* Sysfs entry for AUTO CMD21 control */
6366 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6367 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6368 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6369 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6370 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6371 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6372 if (ret)
6373 goto remove_auto_cmd19_attr_file;
6374
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306375 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006376 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006377
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306378 remove_auto_cmd19_attr_file:
6379 if (is_auto_cmd19(host))
6380 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306381 remove_idle_timeout_file:
6382 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306383 remove_polling_file:
6384 if (!plat->status_irq)
6385 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306386 remove_max_bus_bw_file:
6387 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006388 platform_irq_free:
6389 del_timer_sync(&host->req_tout_timer);
6390 pm_runtime_disable(&(pdev)->dev);
6391 pm_runtime_set_suspended(&(pdev)->dev);
6392
6393 if (plat->status_irq)
6394 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306395 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006396 sdiowakeup_irq_free:
Krishna Konda1963f432013-02-19 20:28:53 -08006397 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6398 wake_lock_destroy(&host->sdio_wlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006399 wake_lock_destroy(&host->sdio_suspend_wlock);
6400 if (plat->sdiowakeup_irq)
6401 free_irq(plat->sdiowakeup_irq, host);
6402 pio_irq_free:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006403 free_irq(core_irqres->start, host);
6404 irq_free:
6405 free_irq(core_irqres->start, host);
6406 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306407 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006408 msmsdcc_dml_exit(host);
6409 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306410 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006411 msmsdcc_sps_exit(host);
6412 vreg_deinit:
6413 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07006414 clk_disable:
Krishna Konda7dd56c22012-11-08 17:52:32 -08006415 clk_disable_unprepare(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306416 msmsdcc_msm_bus_unregister(host);
6417 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006418 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306419 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07006420 clk_put:
6421 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006422 pclk_disable:
6423 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306424 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006425 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006426 if (!IS_ERR(host->pclk))
6427 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306428 if (!IS_ERR_OR_NULL(host->bus_clk))
6429 clk_disable_unprepare(host->bus_clk);
6430 bus_clk_put:
6431 if (!IS_ERR_OR_NULL(host->bus_clk))
6432 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306433 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006434 if (host->dmares)
6435 dma_free_coherent(NULL,
6436 sizeof(struct msmsdcc_nc_dmadata),
6437 host->dma.nc, host->dma.nc_busaddr);
6438 }
6439 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306440 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006441 host_free:
6442 mmc_free_host(mmc);
6443 out:
6444 return ret;
6445}
6446
Pratibhasagar V713817b2012-09-07 11:28:30 +05306447#ifdef CONFIG_DEBUG_FS
6448static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6449{
6450 debugfs_remove_recursive(host->debugfs_host_dir);
6451 host->debugfs_host_dir = NULL;
6452}
6453#else
6454static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6455#endif
6456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006457static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006458{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006459 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6460 struct mmc_platform_data *plat;
6461 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006463 if (!mmc)
6464 return -ENXIO;
6465
6466 if (pm_runtime_suspended(&(pdev)->dev))
6467 pm_runtime_resume(&(pdev)->dev);
6468
6469 host = mmc_priv(mmc);
6470
6471 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6472 plat = host->plat;
6473
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306474 if (is_auto_cmd19(host))
6475 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306476 if (is_auto_cmd21(host))
6477 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306478 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006479 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306480 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306481 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006482
Pratibhasagar V713817b2012-09-07 11:28:30 +05306483 msmsdcc_remove_debugfs(host);
6484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006485 del_timer_sync(&host->req_tout_timer);
6486 tasklet_kill(&host->dma_tlet);
6487 tasklet_kill(&host->sps.tlet);
6488 mmc_remove_host(mmc);
6489
6490 if (plat->status_irq)
6491 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306492 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006493
6494 wake_lock_destroy(&host->sdio_suspend_wlock);
6495 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006496 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6497 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006498 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006499
Krishna Konda1963f432013-02-19 20:28:53 -08006500 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6501 wake_lock_destroy(&host->sdio_wlock);
6502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006503 free_irq(host->core_irqres->start, host);
6504 free_irq(host->core_irqres->start, host);
6505
6506 clk_put(host->clk);
6507 if (!IS_ERR(host->pclk))
6508 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306509 if (!IS_ERR_OR_NULL(host->bus_clk))
6510 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006511
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006512 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306513 pm_qos_remove_request(&host->pm_qos_req_dma);
6514
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306515 if (host->msm_bus_vote.client_handle) {
6516 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6517 msmsdcc_msm_bus_unregister(host);
6518 }
6519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006520 msmsdcc_vreg_init(host, false);
6521
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306522 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006523 if (host->dmares)
6524 dma_free_coherent(NULL,
6525 sizeof(struct msmsdcc_nc_dmadata),
6526 host->dma.nc, host->dma.nc_busaddr);
6527 }
6528
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306529 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006530 msmsdcc_dml_exit(host);
6531 msmsdcc_sps_exit(host);
6532 }
6533
6534 iounmap(host->base);
6535 mmc_free_host(mmc);
6536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006537 pm_runtime_disable(&(pdev)->dev);
6538 pm_runtime_set_suspended(&(pdev)->dev);
6539
6540 return 0;
6541}
6542
6543#ifdef CONFIG_MSM_SDIO_AL
6544int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6545{
6546 struct msmsdcc_host *host = mmc_priv(mmc);
6547 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306548 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006549
Asutosh Dasf5298c32012-04-03 14:51:47 +05306550 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006551 spin_lock_irqsave(&host->lock, flags);
6552 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6553 enable ? "En" : "Dis");
6554
6555 if (enable) {
6556 if (!host->sdcc_irq_disabled) {
6557 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306558 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006559 host->sdcc_irq_disabled = 1;
6560 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306561 rc = msmsdcc_setup_clocks(host, false);
6562 if (rc)
6563 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006564
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306565 if (host->plat->sdio_lpm_gpio_setup &&
6566 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006567 spin_unlock_irqrestore(&host->lock, flags);
6568 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6569 spin_lock_irqsave(&host->lock, flags);
6570 host->sdio_gpio_lpm = 1;
6571 }
6572
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306573 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006574 msmsdcc_enable_irq_wake(host);
6575 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306576 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006577 }
6578 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306579 rc = msmsdcc_setup_clocks(host, true);
6580 if (rc)
6581 goto out;
6582
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306583 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006584 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306585 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006586 msmsdcc_disable_irq_wake(host);
6587 }
6588
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306589 if (host->plat->sdio_lpm_gpio_setup &&
6590 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006591 spin_unlock_irqrestore(&host->lock, flags);
6592 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6593 spin_lock_irqsave(&host->lock, flags);
6594 host->sdio_gpio_lpm = 0;
6595 }
6596
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306597 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006598 writel_relaxed(host->mci_irqenable,
6599 host->base + MMCIMASK0);
6600 mb();
6601 enable_irq(host->core_irqres->start);
6602 host->sdcc_irq_disabled = 0;
6603 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006604 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306605out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006606 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306607 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306608 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006609}
6610#else
6611int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6612{
6613 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006614}
6615#endif
6616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006617#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306618#ifdef CONFIG_MMC_CLKGATE
6619static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6620{
6621 struct mmc_host *mmc = host->mmc;
6622 unsigned long flags;
6623
6624 mmc_host_clk_hold(mmc);
6625 spin_lock_irqsave(&mmc->clk_lock, flags);
6626 mmc->clk_old = mmc->ios.clock;
6627 mmc->ios.clock = 0;
6628 mmc->clk_gated = true;
6629 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6630 mmc_set_ios(mmc);
6631 mmc_host_clk_release(mmc);
6632}
6633
6634static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6635{
6636 struct mmc_host *mmc = host->mmc;
6637
6638 mmc_host_clk_hold(mmc);
6639 mmc->ios.clock = host->clk_rate;
6640 mmc_set_ios(mmc);
6641 mmc_host_clk_release(mmc);
6642}
6643#else
6644static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6645{
6646 struct mmc_host *mmc = host->mmc;
6647
6648 mmc->ios.clock = 0;
6649 mmc_set_ios(mmc);
6650}
6651
6652static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6653{
6654 struct mmc_host *mmc = host->mmc;
6655
6656 mmc->ios.clock = host->clk_rate;
6657 mmc_set_ios(mmc);
6658}
6659#endif
6660
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306661#if CONFIG_DEBUG_FS
6662static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306663 const char *func, int err)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306664{
6665 ktime_t diff;
6666
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306667 if (host->print_pm_stats && !err) {
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306668 diff = ktime_sub(ktime_get(), start);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306669 pr_info("%s: %s: Completed in %llu usec\n",
6670 mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306671 }
6672}
6673#else
6674static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306675 const char *func, int err) {}
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306676#endif
6677
San Mehat9d2bd732009-09-22 16:44:22 -07006678static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006679msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006680{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006681 struct mmc_host *mmc = dev_get_drvdata(dev);
6682 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006683 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306684 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306685 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006686
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306687 if (host->plat->is_sdio_al_client) {
6688 rc = 0;
6689 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006690 }
San Mehat9d2bd732009-09-22 16:44:22 -07006691
Sahitya Tummala7661a452011-07-18 13:28:35 +05306692 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006693 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006694 host->sdcc_suspending = 1;
6695 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006697 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006698 * MMC core thinks that host is disabled by now since
6699 * runtime suspend is scheduled after msmsdcc_disable()
6700 * is called. Thus, MMC core will try to enable the host
6701 * while suspending it. This results in a synchronous
6702 * runtime resume request while in runtime suspending
6703 * context and hence inorder to complete this resume
6704 * requet, it will wait for suspend to be complete,
6705 * but runtime suspend also can not proceed further
6706 * until the host is resumed. Thus, it leads to a hang.
6707 * Hence, increase the pm usage count before suspending
6708 * the host so that any resume requests after this will
6709 * simple become pm usage counter increment operations.
6710 */
6711 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306712 /* If there is pending detect work abort runtime suspend */
6713 if (unlikely(work_busy(&mmc->detect.work)))
6714 rc = -EAGAIN;
6715 else
6716 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006717 pm_runtime_put_noidle(dev);
6718
6719 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306720 spin_lock_irqsave(&host->lock, flags);
6721 host->sdcc_suspended = true;
6722 spin_unlock_irqrestore(&host->lock, flags);
6723 if (mmc->card && mmc_card_sdio(mmc->card) &&
6724 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006725 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306726 * If SDIO function driver doesn't want
6727 * to power off the card, atleast turn off
6728 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006729 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306730 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006731 }
6732 }
6733 host->sdcc_suspending = 0;
6734 mmc->suspend_task = NULL;
6735 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6736 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006737 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306738 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306739out:
6740 /* set bus bandwidth to 0 immediately */
6741 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306742 msmsdcc_print_pm_stats(host, start, __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07006743 return rc;
6744}
6745
6746static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006747msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006748{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006749 struct mmc_host *mmc = dev_get_drvdata(dev);
6750 struct msmsdcc_host *host = mmc_priv(mmc);
6751 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306752 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006754 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306755 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006756
Sahitya Tummala7661a452011-07-18 13:28:35 +05306757 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006758 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306759 if (mmc->card && mmc_card_sdio(mmc->card) &&
6760 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306761 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306762 }
San Mehat9d2bd732009-09-22 16:44:22 -07006763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006764 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006766 /*
6767 * FIXME: Clearing of flags must be handled in clients
6768 * resume handler.
6769 */
6770 spin_lock_irqsave(&host->lock, flags);
6771 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306772 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006773 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006775 /*
6776 * After resuming the host wait for sometime so that
6777 * the SDIO work will be processed.
6778 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306779 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306780 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006781 host->plat->sdiowakeup_irq) &&
6782 wake_lock_active(&host->sdio_wlock))
6783 wake_lock_timeout(&host->sdio_wlock, 1);
6784 }
6785
6786 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006787 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306788 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306789 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306790out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306791 msmsdcc_print_pm_stats(host, start, __func__, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07006792 return 0;
6793}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006794
6795static int msmsdcc_runtime_idle(struct device *dev)
6796{
6797 struct mmc_host *mmc = dev_get_drvdata(dev);
6798 struct msmsdcc_host *host = mmc_priv(mmc);
6799
6800 if (host->plat->is_sdio_al_client)
6801 return 0;
6802
6803 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306804 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006805
6806 return -EAGAIN;
6807}
6808
6809static int msmsdcc_pm_suspend(struct device *dev)
6810{
6811 struct mmc_host *mmc = dev_get_drvdata(dev);
6812 struct msmsdcc_host *host = mmc_priv(mmc);
6813 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306814 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006815
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306816 if (host->plat->is_sdio_al_client) {
6817 rc = 0;
6818 goto out;
6819 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306820 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006821 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306822 msmsdcc_disable_status_gpio(host);
6823 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006824
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306825 /*
6826 * If system comes out of suspend, msmsdcc_pm_resume() sets the
6827 * host->pending_resume flag if the SDCC wasn't runtime suspended.
6828 * Now if the system again goes to suspend without any SDCC activity
6829 * then host->pending_resume flag will remain set which may cause
6830 * the SDCC resume to happen first and then suspend.
6831 * To avoid this unnecessary resume/suspend, make sure that
6832 * pending_resume flag is cleared before calling the
6833 * msmsdcc_runtime_suspend().
6834 */
6835 if (!pm_runtime_suspended(dev) && !host->pending_resume)
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006836 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306837 out:
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306838 /* This flag must not be set if system is entering into suspend */
6839 host->pending_resume = false;
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306840 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006841 return rc;
6842}
6843
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306844static int msmsdcc_suspend_noirq(struct device *dev)
6845{
6846 struct mmc_host *mmc = dev_get_drvdata(dev);
6847 struct msmsdcc_host *host = mmc_priv(mmc);
6848 int rc = 0;
6849
6850 /*
6851 * After platform suspend there may be active request
6852 * which might have enabled clocks. For example, in SDIO
6853 * case, ksdioirq thread might have scheduled after sdcc
6854 * suspend but before system freeze. In that case abort
6855 * suspend and retry instead of keeping the clocks on
6856 * during suspend and not allowing TCXO.
6857 */
6858
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306859 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306860 pr_warn("%s: clocks are on after suspend, aborting system "
6861 "suspend\n", mmc_hostname(mmc));
6862 rc = -EAGAIN;
6863 }
6864
6865 return rc;
6866}
6867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006868static int msmsdcc_pm_resume(struct device *dev)
6869{
6870 struct mmc_host *mmc = dev_get_drvdata(dev);
6871 struct msmsdcc_host *host = mmc_priv(mmc);
6872 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306873 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006874
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306875 if (host->plat->is_sdio_al_client) {
6876 rc = 0;
6877 goto out;
6878 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006879 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306880 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306881 /*
6882 * As runtime PM is enabled before calling the device's platform resume
6883 * callback, we use the pm_runtime_suspended API to know if SDCC is
6884 * really runtime suspended or not and set the pending_resume flag only
6885 * if its not runtime suspended.
6886 */
6887 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006888 host->pending_resume = true;
6889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006890 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306891 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006892 msmsdcc_check_status((unsigned long)host);
6893 enable_irq(host->plat->status_irq);
6894 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306895out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306896 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006897 return rc;
6898}
6899
Daniel Walker08ecfde2010-06-23 12:32:20 -07006900#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006901static int msmsdcc_runtime_suspend(struct device *dev)
6902{
6903 return 0;
6904}
6905static int msmsdcc_runtime_idle(struct device *dev)
6906{
6907 return 0;
6908}
6909static int msmsdcc_pm_suspend(struct device *dev)
6910{
6911 return 0;
6912}
6913static int msmsdcc_pm_resume(struct device *dev)
6914{
6915 return 0;
6916}
6917static int msmsdcc_suspend_noirq(struct device *dev)
6918{
6919 return 0;
6920}
6921static int msmsdcc_runtime_resume(struct device *dev)
6922{
6923 return 0;
6924}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006925#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006927static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6928 .runtime_suspend = msmsdcc_runtime_suspend,
6929 .runtime_resume = msmsdcc_runtime_resume,
6930 .runtime_idle = msmsdcc_runtime_idle,
6931 .suspend = msmsdcc_pm_suspend,
6932 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306933 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006934};
6935
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306936static const struct of_device_id msmsdcc_dt_match[] = {
6937 {.compatible = "qcom,msm-sdcc"},
6938
6939};
6940MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6941
San Mehat9d2bd732009-09-22 16:44:22 -07006942static struct platform_driver msmsdcc_driver = {
6943 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006944 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006945 .driver = {
6946 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006947 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306948 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006949 },
6950};
6951
6952static int __init msmsdcc_init(void)
6953{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006954#if defined(CONFIG_DEBUG_FS)
6955 int ret = 0;
6956 ret = msmsdcc_dbg_init();
6957 if (ret) {
6958 pr_err("Failed to create debug fs dir \n");
6959 return ret;
6960 }
6961#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006962 return platform_driver_register(&msmsdcc_driver);
6963}
San Mehat9d2bd732009-09-22 16:44:22 -07006964
San Mehat9d2bd732009-09-22 16:44:22 -07006965static void __exit msmsdcc_exit(void)
6966{
6967 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006968
6969#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006970 debugfs_remove(debugfs_dir);
6971#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006972}
6973
6974module_init(msmsdcc_init);
6975module_exit(msmsdcc_exit);
6976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006977MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07006978MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006979
6980#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05306981static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006982{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306983 struct msmsdcc_host *host = data;
6984
6985 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006986 return 0;
6987}
6988
Pratibhasagar V713817b2012-09-07 11:28:30 +05306989static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006990{
Pratibhasagar V713817b2012-09-07 11:28:30 +05306991 struct msmsdcc_host *host = data;
6992 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006993
Pratibhasagar V713817b2012-09-07 11:28:30 +05306994 spin_lock_irqsave(&host->lock, flags);
6995 host->idle_tout = (u32)val * 1000;
6996 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006997
Pratibhasagar V713817b2012-09-07 11:28:30 +05306998 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006999}
7000
Pratibhasagar V713817b2012-09-07 11:28:30 +05307001DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
7002 msmsdcc_dbg_idle_tout_get,
7003 msmsdcc_dbg_idle_tout_set,
7004 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007005
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307006static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
7007{
7008 struct msmsdcc_host *host = data;
7009
7010 *val = (u64) host->enforce_pio_mode;
7011 return 0;
7012}
7013
7014static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
7015{
7016 struct msmsdcc_host *host = data;
7017 unsigned long flags;
7018
7019 spin_lock_irqsave(&host->lock, flags);
7020 host->enforce_pio_mode = !!val;
7021 spin_unlock_irqrestore(&host->lock, flags);
7022
7023 return 0;
7024}
7025
7026DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
7027 msmsdcc_dbg_pio_mode_get,
7028 msmsdcc_dbg_pio_mode_set,
7029 "%llu\n");
7030
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307031static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
7032{
7033 struct msmsdcc_host *host = data;
7034
7035 *val = !!host->print_pm_stats;
7036 return 0;
7037}
7038
7039static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
7040{
7041 struct msmsdcc_host *host = data;
7042 unsigned long flags;
7043
7044 spin_lock_irqsave(&host->lock, flags);
7045 host->print_pm_stats = !!val;
7046 spin_unlock_irqrestore(&host->lock, flags);
7047
7048 return 0;
7049}
7050
7051DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
7052 msmsdcc_dbg_pm_stats_get,
7053 msmsdcc_dbg_pm_stats_set,
7054 "%llu\n");
7055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007056static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
7057{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307058 int err = 0;
7059
7060 if (!debugfs_dir)
7061 return;
7062
7063 host->debugfs_host_dir = debugfs_create_dir(
7064 mmc_hostname(host->mmc), debugfs_dir);
7065 if (IS_ERR(host->debugfs_host_dir)) {
7066 err = PTR_ERR(host->debugfs_host_dir);
7067 host->debugfs_host_dir = NULL;
7068 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
7069 mmc_hostname(host->mmc), err);
7070 return;
7071 }
7072
7073 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
7074 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7075 &msmsdcc_dbg_idle_tout_ops);
7076
7077 if (IS_ERR(host->debugfs_idle_tout)) {
7078 err = PTR_ERR(host->debugfs_idle_tout);
7079 host->debugfs_idle_tout = NULL;
7080 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
7081 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007082 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307083
7084 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
7085 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7086 &msmsdcc_dbg_pio_mode_ops);
7087
7088 if (IS_ERR(host->debugfs_pio_mode)) {
7089 err = PTR_ERR(host->debugfs_pio_mode);
7090 host->debugfs_pio_mode = NULL;
7091 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
7092 mmc_hostname(host->mmc), err);
7093 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307094
7095 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
7096 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7097 &msmsdcc_dbg_pm_stats_ops);
7098 if (IS_ERR(host->debugfs_pm_stats)) {
7099 err = PTR_ERR(host->debugfs_pm_stats);
7100 host->debugfs_pm_stats = NULL;
7101 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
7102 mmc_hostname(host->mmc), err);
7103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007104}
7105
7106static int __init msmsdcc_dbg_init(void)
7107{
7108 int err;
7109
Pratibhasagar V713817b2012-09-07 11:28:30 +05307110 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007111 if (IS_ERR(debugfs_dir)) {
7112 err = PTR_ERR(debugfs_dir);
7113 debugfs_dir = NULL;
7114 return err;
7115 }
7116
7117 return 0;
7118}
7119#endif