blob: b3863188646d475d8f3034111f0a3231e6afcefe [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);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +053090static void msmsdcc_msm_bus_cancel_work_and_set_vote(struct msmsdcc_host *host,
91 struct mmc_ios *ios);
92static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host);
93
Asutosh Dasaccacd42012-03-08 14:33:17 +053094
Subhash Jadavani8766e352011-11-30 11:30:32 +053095static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070096static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098static struct mmc_command dummy52cmd;
99static struct mmc_request dummy52mrq = {
100 .cmd = &dummy52cmd,
101 .data = NULL,
102 .stop = NULL,
103};
104static struct mmc_command dummy52cmd = {
105 .opcode = SD_IO_RW_DIRECT,
106 .flags = MMC_RSP_PRESENT,
107 .data = NULL,
108 .mrq = &dummy52mrq,
109};
110/*
111 * An array holding the Tuning pattern to compare with when
112 * executing a tuning cycle.
113 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530114static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
116 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
117 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
118 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
119};
San Mehat9d2bd732009-09-22 16:44:22 -0700120
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530121static const u32 tuning_block_128[] = {
122 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
123 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
124 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
125 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
126 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
127 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
128 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
129 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
130};
San Mehat865c8062009-11-13 13:42:06 -0800131
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -0800132static int disable_slots;
133module_param(disable_slots, int, 0);
134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135#if IRQ_DEBUG == 1
136static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
137 "dattimeout", "txunderrun", "rxoverrun",
138 "cmdrespend", "cmdsent", "dataend", NULL,
139 "datablkend", "cmdactive", "txactive",
140 "rxactive", "txhalfempty", "rxhalffull",
141 "txfifofull", "rxfifofull", "txfifoempty",
142 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
143 "sdiointr", "progdone", "atacmdcompl",
144 "sdiointrope", "ccstimeout", NULL, NULL,
145 NULL, NULL, NULL };
146
147static void
148msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800149{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
153 for (i = 0; i < 32; i++) {
154 if (status & (1 << i))
155 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800158}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159#endif
San Mehat865c8062009-11-13 13:42:06 -0800160
San Mehat9d2bd732009-09-22 16:44:22 -0700161static void
162msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
163 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530164static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530165static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530166static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800167static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800168static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700169static int msmsdcc_runtime_resume(struct device *dev);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530170static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
171 u32 **out_array, int *len, int size);
Subhash Jadavani355df542012-10-09 19:06:49 +0530172static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode);
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530173static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
174 struct mmc_request *mrq);
175static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
176 struct mmc_request *mrq);
San Mehat9d2bd732009-09-22 16:44:22 -0700177
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530178static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530179{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530180 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530181
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530182 if (is_sps_mode(host)) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530183 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530184 } else { /* DMA or PIO mode */
185 if (NR_SG > MAX_NR_SG_DMA_PIO)
186 ret = MAX_NR_SG_DMA_PIO;
187 }
188
189 return ret;
190}
191
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530192/* Prevent idle power collapse(pc) while operating in peripheral mode */
193static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
194{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700195 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530196 return;
197
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530198 if (vote)
199 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700200 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530201 else
202 pm_qos_update_request(&host->pm_qos_req_dma,
203 PM_QOS_DEFAULT_VALUE);
204}
205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
207static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
208 struct msmsdcc_sps_ep_conn_data *ep);
209static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
210 struct msmsdcc_sps_ep_conn_data *ep);
211#else
212static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
213 struct msmsdcc_sps_ep_conn_data *ep,
214 bool is_producer) { return 0; }
215static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
216 struct msmsdcc_sps_ep_conn_data *ep) { }
217static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
218 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530219{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 return 0;
221}
222static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
223 struct msmsdcc_sps_ep_conn_data *ep)
224{
225 return 0;
226}
227static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
228static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
229#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231/**
Krishna Konda3ca90f02012-08-29 16:29:21 -0700232 * Apply reset
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530233 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700234 * This function resets SPS BAM and DML cores.
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530235 *
236 * This function should be called to recover from error
237 * conditions encountered during CMD/DATA tranfsers with card.
238 *
239 * @host - Pointer to driver's host structure
240 *
241 */
Krishna Konda3ca90f02012-08-29 16:29:21 -0700242static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530243{
244 int rc;
245
246 /* Reset all SDCC BAM pipes */
247 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700248 if (rc) {
249 pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530250 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700251 goto out;
252 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530253
Krishna Konda3ca90f02012-08-29 16:29:21 -0700254 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
255 if (rc) {
256 pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
Krishna Konda5af8f972012-05-14 16:15:24 -0700257 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700258 goto out;
259 }
260
261 /* Reset BAM */
262 rc = sps_device_reset(host->sps.bam_handle);
263 if (rc) {
264 pr_err("%s: sps_device_reset error=%d\n",
265 mmc_hostname(host->mmc), rc);
266 goto out;
Krishna Konda5af8f972012-05-14 16:15:24 -0700267 }
268
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530269 memset(host->sps.prod.config.desc.base, 0x00,
270 host->sps.prod.config.desc.size);
271 memset(host->sps.cons.config.desc.base, 0x00,
272 host->sps.cons.config.desc.size);
273
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530274 /* Restore all BAM pipes connections */
275 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700276 if (rc) {
277 pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530278 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700279 goto out;
280 }
281
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530282 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530283 if (rc) {
Krishna Konda3ca90f02012-08-29 16:29:21 -0700284 pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530285 mmc_hostname(host->mmc), rc);
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530286 goto out;
287 }
288
289 /* Reset and init DML */
290 rc = msmsdcc_dml_init(host);
291 if (rc)
292 pr_err("%s: msmsdcc_dml_init error=%d\n",
293 mmc_hostname(host->mmc), rc);
Krishna Konda3ca90f02012-08-29 16:29:21 -0700294
295out:
Sujit Reddy Thummab745eeb2012-12-27 17:24:45 +0530296 if (!rc)
297 host->sps.reset_bam = false;
Krishna Konda3ca90f02012-08-29 16:29:21 -0700298 return rc;
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530299}
300
301/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 * Apply soft reset
303 *
Krishna Konda3ca90f02012-08-29 16:29:21 -0700304 * This function applies soft reset to SDCC core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 *
306 * This function should be called to recover from error
307 * conditions encountered with CMD/DATA tranfsers with card.
308 *
309 * Soft reset should only be used with SDCC controller v4.
310 *
311 * @host - Pointer to driver's host structure
312 *
313 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530314static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 /*
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530317 * Reset controller state machines without resetting
318 * configuration registers (MCI_POWER, MCI_CLK, MCI_INT_MASKn).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530320 if (is_sw_reset_save_config(host)) {
321 ktime_t start;
Krishna Kondabb97f922012-10-23 20:41:04 -0700322 uint32_t dll_config = 0;
323
324
325 if (is_sw_reset_save_config_broken(host))
326 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530327
328 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
329 | MCI_SW_RST_CFG, host->base + MMCIPOWER);
330 msmsdcc_sync_reg_wr(host);
331
332 start = ktime_get();
333 while (readl_relaxed(host->base + MMCIPOWER) & MCI_SW_RST_CFG) {
334 /*
335 * SW reset can take upto 10HCLK + 15MCLK cycles.
336 * Calculating based on min clk rates (hclk = 27MHz,
337 * mclk = 400KHz) it comes to ~40us. Let's poll for
338 * max. 1ms for reset completion.
339 */
340 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
341 pr_err("%s: %s failed\n",
342 mmc_hostname(host->mmc), __func__);
343 BUG();
344 }
345 }
Krishna Kondabb97f922012-10-23 20:41:04 -0700346
347 if (is_sw_reset_save_config_broken(host)) {
348 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
349 mb();
350 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530351 } else {
352 writel_relaxed(0, host->base + MMCICOMMAND);
353 msmsdcc_sync_reg_wr(host);
354 writel_relaxed(0, host->base + MMCIDATACTRL);
355 msmsdcc_sync_reg_wr(host);
356 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530357}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530358
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530359static void msmsdcc_hard_reset(struct msmsdcc_host *host)
360{
361 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530362
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530363 /*
364 * Reset SDCC controller to power on default state.
365 * Don't issue a reset request to clock control block if
366 * SDCC controller itself can support hard reset.
367 */
368 if (is_sw_hard_reset(host)) {
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800369 u32 pwr;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530370
371 writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
372 | MCI_SW_RST, host->base + MMCIPOWER);
373 msmsdcc_sync_reg_wr(host);
374
Oluwafemi Adeyemi7eeea872012-11-21 17:00:40 -0800375 /*
376 * See comment in msmsdcc_soft_reset() on choosing 1ms
377 * poll timeout.
378 */
379 ret = readl_poll_timeout_noirq(host->base + MMCIPOWER,
380 pwr, !(pwr & MCI_SW_RST), 100, 10);
381
382 if (ret) {
383 pr_err("%s: %s failed (%d)\n",
384 mmc_hostname(host->mmc), __func__, ret);
385 BUG();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530386 }
387 } else {
388 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
389 if (ret)
390 pr_err("%s: Clock assert failed at %u Hz" \
391 " with err %d\n", mmc_hostname(host->mmc),
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530392 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530393
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530394 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
395 if (ret)
396 pr_err("%s: Clock deassert failed at %u Hz" \
397 " with err %d\n", mmc_hostname(host->mmc),
398 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530399
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530400 mb();
401 /* Give some delay for clock reset to propogate to controller */
402 msmsdcc_delay(host);
403 }
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530404}
405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
407{
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530408 if (is_soft_reset(host)) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530409 msmsdcc_soft_reset(host);
410
411 pr_debug("%s: Applied soft reset to Controller\n",
412 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 } else {
414 /* Give Clock reset (hard reset) to controller */
415 u32 mci_clk = 0;
416 u32 mci_mask0 = 0;
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530417 u32 dll_config = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418
419 /* Save the controller state */
420 mci_clk = readl_relaxed(host->base + MMCICLOCK);
421 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530422 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530423 if (host->tuning_needed)
424 dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530427 msmsdcc_hard_reset(host);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530428 pr_debug("%s: Applied hard reset to controller\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 mmc_hostname(host->mmc));
430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700431 /* Restore the contoller state */
432 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530433 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530435 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530437 if (host->tuning_needed)
438 writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530439 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530441
Sujit Reddy Thummaaa9a3642013-02-10 17:01:30 +0530442 if (is_sps_mode(host))
443 /*
444 * delay the SPS BAM reset in thread context as
445 * sps_connect/sps_disconnect APIs can be called
446 * only from non-atomic context.
447 */
448 host->sps.reset_bam = true;
449
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700450 if (host->dummy_52_needed)
451 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700452}
453
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530454static void msmsdcc_reset_dpsm(struct msmsdcc_host *host)
455{
456 struct mmc_request *mrq = host->curr.mrq;
457
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530458 if (!mrq || !mrq->cmd || !mrq->data)
459 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530460
461 /*
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530462 * If we have not waited for the prog done for write transfer then
463 * perform the DPSM reset without polling for TXACTIVE.
464 * Otherwise, we poll here unnecessarily as TXACTIVE will not be
465 * deasserted until DAT0 (Busy line) goes high.
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530466 */
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530467 if (mrq->data->flags & MMC_DATA_WRITE) {
468 if (!msmsdcc_is_wait_for_prog_done(host, mrq)) {
469 if (is_wait_for_tx_rx_active(host) &&
470 !is_auto_prog_done(host))
471 pr_warning("%s: %s: AUTO_PROG_DONE capability is must\n",
472 mmc_hostname(host->mmc), __func__);
473 goto no_polling;
474 }
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530475 }
476
477 /* Make sure h/w (TX/RX) is inactive before resetting DPSM */
478 if (is_wait_for_tx_rx_active(host)) {
479 ktime_t start = ktime_get();
480
481 while (readl_relaxed(host->base + MMCISTATUS) &
482 (MCI_TXACTIVE | MCI_RXACTIVE)) {
483 /*
484 * TX/RX active bits may be asserted for 4HCLK + 4MCLK
485 * cycles (~11us) after data transfer due to clock mux
486 * switching delays. Let's poll for 1ms and panic if
487 * still active.
488 */
489 if (ktime_to_us(ktime_sub(ktime_get(), start)) > 1000) {
490 pr_err("%s: %s still active\n",
491 mmc_hostname(host->mmc),
492 readl_relaxed(host->base + MMCISTATUS)
493 & MCI_TXACTIVE ? "TX" : "RX");
494 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530495 msmsdcc_reset_and_restore(host);
Sujit Reddy Thumma0a295882012-11-17 13:03:27 +0530496 goto out;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530497 }
498 }
499 }
500
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +0530501no_polling:
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530502 writel_relaxed(0, host->base + MMCIDATACTRL);
503 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530504out:
505 return;
506}
507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508static int
San Mehat9d2bd732009-09-22 16:44:22 -0700509msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
510{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 int retval = 0;
512
San Mehat9d2bd732009-09-22 16:44:22 -0700513 BUG_ON(host->curr.data);
514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700516
517 if (mrq->data)
518 mrq->data->bytes_xfered = host->curr.data_xfered;
519 if (mrq->cmd->error == -ETIMEDOUT)
520 mdelay(5);
521
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530522 msmsdcc_reset_dpsm(host);
523
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530524 /* Clear current request information as current request has ended */
525 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
526
San Mehat9d2bd732009-09-22 16:44:22 -0700527 /*
528 * Need to drop the host lock here; mmc_request_done may call
529 * back into the driver...
530 */
531 spin_unlock(&host->lock);
532 mmc_request_done(host->mmc, mrq);
533 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534
535 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700536}
537
538static void
539msmsdcc_stop_data(struct msmsdcc_host *host)
540{
San Mehat9d2bd732009-09-22 16:44:22 -0700541 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530542 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530543 host->curr.wait_for_auto_prog_done = false;
544 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -0700545}
546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700548{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 return host->core_memres->start + MMCIFIFO;
550}
551
552static inline unsigned int msmsdcc_get_min_sup_clk_rate(
553 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530554
Subhash Jadavanidd432952012-03-28 11:25:56 +0530555static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556{
557 mb();
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530558 if (!is_wait_for_reg_write(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +0530559 udelay(host->reg_write_delay);
560 else if (readl_relaxed(host->base + MCI_STATUS2) &
561 MCI_MCLK_REG_WR_ACTIVE) {
562 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530563
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530564 start = ktime_get();
565 while (readl_relaxed(host->base + MCI_STATUS2) &
566 MCI_MCLK_REG_WR_ACTIVE) {
567 diff = ktime_sub(ktime_get(), start);
568 /* poll for max. 1 ms */
569 if (ktime_to_us(diff) > 1000) {
570 pr_warning("%s: previous reg. write is"
571 " still active\n",
572 mmc_hostname(host->mmc));
573 break;
574 }
575 }
576 }
San Mehat9d2bd732009-09-22 16:44:22 -0700577}
578
Subhash Jadavanidd432952012-03-28 11:25:56 +0530579static inline void msmsdcc_delay(struct msmsdcc_host *host)
580{
581 udelay(host->reg_write_delay);
582
San Mehat9d2bd732009-09-22 16:44:22 -0700583}
584
San Mehat56a8b5b2009-11-21 12:29:46 -0800585static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
587{
588 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530590 /*
591 * As after sending the command, we don't write any of the
592 * controller registers and just wait for the
593 * CMD_RESPOND_END/CMD_SENT/Command failure notication
594 * from Controller.
595 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800597}
598
599static void
600msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
601{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
605 writel_relaxed((unsigned int)host->curr.xfer_size,
606 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530608 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800609
San Mehat6ac9ea62009-12-02 17:24:58 -0800610 if (host->cmd_cmd) {
611 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800613 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800614}
615
San Mehat9d2bd732009-09-22 16:44:22 -0700616static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530617msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700618{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530619 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700620 unsigned long flags;
621 struct mmc_request *mrq;
622
623 spin_lock_irqsave(&host->lock, flags);
624 mrq = host->curr.mrq;
625 BUG_ON(!mrq);
626
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530627 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700628 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700629 goto out;
630 }
631
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530632 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700633 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700635 } else {
636 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530637 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700638 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530639 mmc_hostname(host->mmc), host->dma.result);
640 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700641 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530642 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530643 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644 host->dma.err.flush[0], host->dma.err.flush[1],
645 host->dma.err.flush[2], host->dma.err.flush[3],
646 host->dma.err.flush[4],
647 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530648 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700649 if (!mrq->data->error)
650 mrq->data->error = -EIO;
651 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530652 if (!mrq->data->host_cookie)
653 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
654 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 if (host->curr.user_pages) {
657 struct scatterlist *sg = host->dma.sg;
658 int i;
659
660 for (i = 0; i < host->dma.num_ents; i++, sg++)
661 flush_dcache_page(sg_page(sg));
662 }
San Mehat9d2bd732009-09-22 16:44:22 -0700663
San Mehat9d2bd732009-09-22 16:44:22 -0700664 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800665 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700666
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530667 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
668 (host->curr.wait_for_auto_prog_done &&
669 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700670 /*
671 * If we've already gotten our DATAEND / DATABLKEND
672 * for this request, then complete it through here.
673 */
San Mehat9d2bd732009-09-22 16:44:22 -0700674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700676 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 host->curr.xfer_remain -= host->curr.xfer_size;
678 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700679 if (host->dummy_52_needed) {
San Mehat9d2bd732009-09-22 16:44:22 -0700680 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700681 host->dummy_52_sent = 1;
682 msmsdcc_start_command(host, &dummy52cmd,
683 MCI_CPSM_PROGENA);
684 goto out;
685 }
686 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530687 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530688 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700689 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530690 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530692 /*
693 * Clear current request information as current
694 * request has ended
695 */
696 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700697 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698
San Mehat9d2bd732009-09-22 16:44:22 -0700699 mmc_request_done(host->mmc, mrq);
700 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530701 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
702 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700703 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530704 }
San Mehat9d2bd732009-09-22 16:44:22 -0700705 }
706
707out:
708 spin_unlock_irqrestore(&host->lock, flags);
709 return;
710}
711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
713/**
714 * Callback notification from SPS driver
715 *
716 * This callback function gets triggered called from
717 * SPS driver when requested SPS data transfer is
718 * completed.
719 *
720 * SPS driver invokes this callback in BAM irq context so
721 * SDCC driver schedule a tasklet for further processing
722 * this callback notification at later point of time in
723 * tasklet context and immediately returns control back
724 * to SPS driver.
725 *
726 * @nofity - Pointer to sps event notify sturcture
727 *
728 */
729static void
730msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
731{
732 struct msmsdcc_host *host =
733 (struct msmsdcc_host *)
734 ((struct sps_event_notify *)notify)->user;
735
736 host->sps.notify = *notify;
737 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
738 mmc_hostname(host->mmc), __func__, notify->event_id,
739 notify->data.transfer.iovec.addr,
740 notify->data.transfer.iovec.size,
741 notify->data.transfer.iovec.flags);
742 /* Schedule a tasklet for completing data transfer */
743 tasklet_schedule(&host->sps.tlet);
744}
745
746/**
747 * Tasklet handler for processing SPS callback event
748 *
749 * This function processing SPS event notification and
750 * checks if the SPS transfer is completed or not and
751 * then accordingly notifies status to MMC core layer.
752 *
753 * This function is called in tasklet context.
754 *
755 * @data - Pointer to sdcc driver data
756 *
757 */
758static void msmsdcc_sps_complete_tlet(unsigned long data)
759{
760 unsigned long flags;
761 int i, rc;
762 u32 data_xfered = 0;
763 struct mmc_request *mrq;
764 struct sps_iovec iovec;
765 struct sps_pipe *sps_pipe_handle;
766 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
767 struct sps_event_notify *notify = &host->sps.notify;
768
769 spin_lock_irqsave(&host->lock, flags);
770 if (host->sps.dir == DMA_FROM_DEVICE)
771 sps_pipe_handle = host->sps.prod.pipe_handle;
772 else
773 sps_pipe_handle = host->sps.cons.pipe_handle;
774 mrq = host->curr.mrq;
775
776 if (!mrq) {
777 spin_unlock_irqrestore(&host->lock, flags);
778 return;
779 }
780
781 pr_debug("%s: %s: sps event_id=%d\n",
782 mmc_hostname(host->mmc), __func__,
783 notify->event_id);
784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 /*
786 * Got End of transfer event!!! Check if all of the data
787 * has been transferred?
788 */
789 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
790 rc = sps_get_iovec(sps_pipe_handle, &iovec);
791 if (rc) {
792 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
793 mmc_hostname(host->mmc), __func__, rc, i);
794 break;
795 }
796 data_xfered += iovec.size;
797 }
798
799 if (data_xfered == host->curr.xfer_size) {
800 host->curr.data_xfered = host->curr.xfer_size;
801 host->curr.xfer_remain -= host->curr.xfer_size;
802 pr_debug("%s: Data xfer success. data_xfered=0x%x",
803 mmc_hostname(host->mmc),
804 host->curr.xfer_size);
805 } else {
806 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
807 " xfer_size=%d", mmc_hostname(host->mmc),
808 data_xfered, host->curr.xfer_size);
809 msmsdcc_reset_and_restore(host);
810 if (!mrq->data->error)
811 mrq->data->error = -EIO;
812 }
813
814 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530815 if (!mrq->data->host_cookie)
816 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
817 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 host->sps.sg = NULL;
819 host->sps.busy = 0;
820
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530821 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
822 (host->curr.wait_for_auto_prog_done &&
823 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 /*
825 * If we've already gotten our DATAEND / DATABLKEND
826 * for this request, then complete it through here.
827 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828
829 if (!mrq->data->error) {
830 host->curr.data_xfered = host->curr.xfer_size;
831 host->curr.xfer_remain -= host->curr.xfer_size;
832 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700833 if (host->dummy_52_needed) {
834 mrq->data->bytes_xfered = host->curr.data_xfered;
835 host->dummy_52_sent = 1;
836 msmsdcc_start_command(host, &dummy52cmd,
837 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700838 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700839 return;
840 }
841 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530842 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530843 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844 mrq->data->bytes_xfered = host->curr.data_xfered;
Sujit Reddy Thumma02868752012-06-25 17:22:56 +0530845 msmsdcc_reset_dpsm(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530847 /*
848 * Clear current request information as current
849 * request has ended
850 */
851 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852 spin_unlock_irqrestore(&host->lock, flags);
853
854 mmc_request_done(host->mmc, mrq);
855 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530856 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
857 || !mrq->sbc)) {
858 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859 }
860 }
861 spin_unlock_irqrestore(&host->lock, flags);
862}
863
864/**
865 * Exit from current SPS data transfer
866 *
867 * This function exits from current SPS data transfer.
868 *
869 * This function should be called when error condition
870 * is encountered during data transfer.
871 *
872 * @host - Pointer to sdcc host structure
873 *
874 */
875static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
876{
877 struct mmc_request *mrq;
878
879 mrq = host->curr.mrq;
880 BUG_ON(!mrq);
881
882 msmsdcc_reset_and_restore(host);
883 if (!mrq->data->error)
884 mrq->data->error = -EIO;
885
886 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530887 if (!mrq->data->host_cookie)
888 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
889 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890
891 host->sps.sg = NULL;
892 host->sps.busy = 0;
893 if (host->curr.data)
894 msmsdcc_stop_data(host);
895
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530896 if (!mrq->data->stop || mrq->cmd->error ||
897 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530899 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
900 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 msmsdcc_start_command(host, mrq->data->stop, 0);
902
903}
904#else
905static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
906static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
907static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
908#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
909
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530910static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530912static void
913msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
914 unsigned int result,
915 struct msm_dmov_errdata *err)
916{
917 struct msmsdcc_dma_data *dma_data =
918 container_of(cmd, struct msmsdcc_dma_data, hdr);
919 struct msmsdcc_host *host = dma_data->host;
920
921 dma_data->result = result;
922 if (err)
923 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
924
925 tasklet_schedule(&host->dma_tlet);
926}
927
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530928static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
929 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700930{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530931 bool ret = true;
932 u32 xfer_size = data->blksz * data->blocks;
San Mehat9d2bd732009-09-22 16:44:22 -0700933
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530934 if (host->enforce_pio_mode) {
935 ret = false;
936 goto out;
937 }
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530938 if (is_sps_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530939 /*
940 * BAM Mode: Fall back on PIO if size is less
941 * than or equal to SPS_MIN_XFER_SIZE bytes.
942 */
943 if (xfer_size <= SPS_MIN_XFER_SIZE)
944 ret = false;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +0530945 } else if (is_dma_mode(host)) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530946 /*
947 * ADM Mode: Fall back on PIO if size is less than FIFO size
948 * or not integer multiple of FIFO size
949 */
950 if (xfer_size % MCI_FIFOSIZE)
951 ret = false;
952 } else {
953 /* PIO Mode */
954 ret = false;
955 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +0530956 out:
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530957 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700958}
959
960static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
961{
962 struct msmsdcc_nc_dmadata *nc;
963 dmov_box *box;
964 uint32_t rows;
Subhash Jadavani34a47f02013-05-02 15:36:48 +0530965 int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530966 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700967 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530968 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700969
Krishna Konda25786ec2011-07-25 16:21:36 -0700970 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700972
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +0530973 BUG_ON((host->pdev->id < 1) || (host->pdev->id > 5));
San Mehat9d2bd732009-09-22 16:44:22 -0700974
975 host->dma.sg = data->sg;
976 host->dma.num_ents = data->sg_len;
977
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530978 /* Prevent memory corruption */
979 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800980
San Mehat9d2bd732009-09-22 16:44:22 -0700981 nc = host->dma.nc;
982
San Mehat9d2bd732009-09-22 16:44:22 -0700983 if (data->flags & MMC_DATA_READ)
984 host->dma.dir = DMA_FROM_DEVICE;
985 else
986 host->dma.dir = DMA_TO_DEVICE;
987
Asutosh Dasaccacd42012-03-08 14:33:17 +0530988 if (!data->host_cookie) {
989 n = msmsdcc_prep_xfer(host, data);
990 if (unlikely(n < 0)) {
991 host->dma.sg = NULL;
992 host->dma.num_ents = 0;
993 return -ENOMEM;
994 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800995 }
San Mehat9d2bd732009-09-22 16:44:22 -0700996
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530997 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
998 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700999 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301000 for (i = 0; i < host->dma.num_ents; i++) {
1001 len = sg_dma_len(sg);
1002 offset = 0;
1003
1004 do {
1005 /* Check if we can do DMA */
1006 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
1007 err = -ENOTSUPP;
1008 goto unmap;
1009 }
1010
1011 box->cmd = CMD_MODE_BOX;
1012
1013 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
1014 len = MMC_MAX_DMA_BOX_LENGTH;
1015 len -= len % data->blksz;
1016 }
1017 rows = (len % MCI_FIFOSIZE) ?
1018 (len / MCI_FIFOSIZE) + 1 :
1019 (len / MCI_FIFOSIZE);
1020
1021 if (data->flags & MMC_DATA_READ) {
1022 box->src_row_addr = msmsdcc_fifo_addr(host);
1023 box->dst_row_addr = sg_dma_address(sg) + offset;
1024 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1025 (MCI_FIFOSIZE);
1026 box->row_offset = MCI_FIFOSIZE;
1027 box->num_rows = rows * ((1 << 16) + 1);
1028 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
1029 } else {
1030 box->src_row_addr = sg_dma_address(sg) + offset;
1031 box->dst_row_addr = msmsdcc_fifo_addr(host);
1032 box->src_dst_len = (MCI_FIFOSIZE << 16) |
1033 (MCI_FIFOSIZE);
1034 box->row_offset = (MCI_FIFOSIZE << 16);
1035 box->num_rows = rows * ((1 << 16) + 1);
1036 box->cmd |= CMD_DST_CRCI(host->dma.crci);
1037 }
1038
1039 offset += len;
1040 len = sg_dma_len(sg) - offset;
1041 box++;
1042 box_cmd_cnt++;
1043 } while (len);
1044 sg++;
1045 }
1046 /* Mark last command */
1047 box--;
1048 box->cmd |= CMD_LC;
San Mehat9d2bd732009-09-22 16:44:22 -07001049
1050 /* location of command block must be 64 bit aligned */
1051 BUG_ON(host->dma.cmd_busaddr & 0x07);
1052
1053 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
1054 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
1055 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
1056 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
1057
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301058 /* Flush all data to memory before starting dma */
1059 mb();
1060
1061unmap:
1062 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +05301063 if (!data->host_cookie)
1064 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
1065 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301066 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
1067 mmc_hostname(host->mmc), err);
San Mehat9d2bd732009-09-22 16:44:22 -07001068 }
1069
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05301070 return err;
San Mehat9d2bd732009-09-22 16:44:22 -07001071}
1072
Asutosh Dasaccacd42012-03-08 14:33:17 +05301073static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
1074 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -08001075{
Asutosh Dasaccacd42012-03-08 14:33:17 +05301076 int rc = 0;
1077 unsigned int dir;
1078
1079 /* Prevent memory corruption */
1080 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
1081
1082 if (data->flags & MMC_DATA_READ)
1083 dir = DMA_FROM_DEVICE;
1084 else
1085 dir = DMA_TO_DEVICE;
1086
1087 /* Make sg buffers DMA ready */
1088 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1089 dir);
1090
1091 if (unlikely(rc != data->sg_len)) {
1092 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
1093 mmc_hostname(host->mmc), rc);
1094 rc = -ENOMEM;
1095 goto dma_map_err;
1096 }
1097
1098 pr_debug("%s: %s: %s: sg_len=%d\n",
1099 mmc_hostname(host->mmc), __func__,
1100 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
1101 data->sg_len);
1102
1103 goto out;
1104
1105dma_map_err:
1106 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1107 data->flags);
1108out:
1109 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001110}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
1112/**
1113 * Submits data transfer request to SPS driver
1114 *
1115 * This function make sg (scatter gather) data buffers
1116 * DMA ready and then submits them to SPS driver for
1117 * transfer.
1118 *
1119 * @host - Pointer to sdcc host structure
1120 * @data - Pointer to mmc_data structure
1121 *
1122 * @return 0 if success else negative value
1123 */
1124static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +05301125 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -07001126{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 int rc = 0;
1128 u32 flags;
1129 int i;
1130 u32 addr, len, data_cnt;
1131 struct scatterlist *sg = data->sg;
1132 struct sps_pipe *sps_pipe_handle;
1133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 host->sps.sg = data->sg;
1135 host->sps.num_ents = data->sg_len;
1136 host->sps.xfer_req_cnt = 0;
1137 if (data->flags & MMC_DATA_READ) {
1138 host->sps.dir = DMA_FROM_DEVICE;
1139 sps_pipe_handle = host->sps.prod.pipe_handle;
1140 } else {
1141 host->sps.dir = DMA_TO_DEVICE;
1142 sps_pipe_handle = host->sps.cons.pipe_handle;
1143 }
1144
Asutosh Dasaccacd42012-03-08 14:33:17 +05301145 if (!data->host_cookie) {
1146 rc = msmsdcc_prep_xfer(host, data);
1147 if (unlikely(rc < 0)) {
1148 host->dma.sg = NULL;
1149 host->dma.num_ents = 0;
1150 goto out;
1151 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 }
1153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 for (i = 0; i < data->sg_len; i++) {
1155 /*
1156 * Check if this is the last buffer to transfer?
1157 * If yes then set the INT and EOT flags.
1158 */
1159 len = sg_dma_len(sg);
1160 addr = sg_dma_address(sg);
1161 flags = 0;
1162 while (len > 0) {
1163 if (len > SPS_MAX_DESC_SIZE) {
1164 data_cnt = SPS_MAX_DESC_SIZE;
1165 } else {
1166 data_cnt = len;
Sujit Reddy Thumma001a02f2013-01-23 10:31:38 +05301167 if ((i == data->sg_len - 1) &&
1168 (sps_pipe_handle ==
1169 host->sps.cons.pipe_handle)) {
1170 /*
1171 * set EOT only for consumer pipe, for
1172 * producer pipe h/w will set it.
1173 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 flags = SPS_IOVEC_FLAG_INT |
1175 SPS_IOVEC_FLAG_EOT;
Sujit Reddy Thumma001a02f2013-01-23 10:31:38 +05301176 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 }
1178 rc = sps_transfer_one(sps_pipe_handle, addr,
1179 data_cnt, host, flags);
1180 if (rc) {
1181 pr_err("%s: sps_transfer_one() error! rc=%d,"
1182 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1183 mmc_hostname(host->mmc), rc,
1184 (u32)sps_pipe_handle, (u32)sg, i);
1185 goto dma_map_err;
1186 }
1187 addr += data_cnt;
1188 len -= data_cnt;
1189 host->sps.xfer_req_cnt++;
1190 }
1191 sg++;
1192 }
1193 goto out;
1194
1195dma_map_err:
1196 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301197 if (!data->host_cookie)
1198 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1199 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200out:
1201 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001202}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203#else
1204static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1205 struct mmc_data *data) { return 0; }
1206#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001207
1208static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001209msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1210 struct mmc_command *cmd, u32 *c)
1211{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301212 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 cmd->opcode, cmd->arg, cmd->flags);
1214
San Mehat56a8b5b2009-11-21 12:29:46 -08001215 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1216
1217 if (cmd->flags & MMC_RSP_PRESENT) {
1218 if (cmd->flags & MMC_RSP_136)
1219 *c |= MCI_CPSM_LONGRSP;
1220 *c |= MCI_CPSM_RESPONSE;
1221 }
1222
1223 if (/*interrupt*/0)
1224 *c |= MCI_CPSM_INTERRUPT;
1225
Asutosh Das05049132012-05-09 12:38:15 +05301226 /* DAT_CMD bit should be set for all ADTC */
1227 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001228 *c |= MCI_CSPM_DATCMD;
1229
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301230 /* Check if AUTO CMD19/CMD21 is required or not? */
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301231 if (host->tuning_needed && (cmd->mrq->data &&
1232 (cmd->mrq->data->flags & MMC_DATA_READ)) &&
1233 (host->en_auto_cmd19 || host->en_auto_cmd21)) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301234 /*
1235 * For open ended block read operation (without CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301236 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1237 * the READ command.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301238 * For close ended block read operation (with CMD23),
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301239 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
1240 * CMD23.
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301241 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301242 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1243 host->curr.mrq->cmd->opcode ==
1244 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301245 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301246 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
Subhash Jadavani67be0a92012-11-26 23:07:44 +05301247 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1248 cmd->opcode == SD_IO_RW_EXTENDED))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301249 msmsdcc_enable_cdr_cm_sdc4_dll(host);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05301250 if (host->en_auto_cmd19 &&
1251 host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
1252 *c |= MCI_CSPM_AUTO_CMD19;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05301253 else if (host->en_auto_cmd21 &&
1254 host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
1255 *c |= MCI_CSPM_AUTO_CMD21;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301256 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 }
1258
Subhash Jadavanif97d2992012-07-13 14:47:47 +05301259 if (cmd->mrq->data && (cmd->mrq->data->flags & MMC_DATA_READ))
1260 writel_relaxed((readl_relaxed(host->base +
1261 MCI_DLL_CONFIG) | MCI_CDR_EN),
1262 host->base + MCI_DLL_CONFIG);
1263 else
1264 /* Clear CDR_EN bit for non read operations */
1265 writel_relaxed((readl_relaxed(host->base +
1266 MCI_DLL_CONFIG) & ~MCI_CDR_EN),
1267 host->base + MCI_DLL_CONFIG);
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301268
Subhash Jadavani56fd4512012-12-19 19:05:02 +05301269 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301270 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301272 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001273 if (cmd == cmd->mrq->stop)
1274 *c |= MCI_CSPM_MCIABORT;
1275
San Mehat56a8b5b2009-11-21 12:29:46 -08001276 if (host->curr.cmd != NULL) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301277 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001279 }
1280 host->curr.cmd = cmd;
1281}
1282
1283static void
1284msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1285 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001286{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301287 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001288 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001290 unsigned int pio_irqmask = 0;
1291
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301292 BUG_ON(!data->sg);
1293 BUG_ON(!data->sg_len);
1294
San Mehat9d2bd732009-09-22 16:44:22 -07001295 host->curr.data = data;
1296 host->curr.xfer_size = data->blksz * data->blocks;
1297 host->curr.xfer_remain = host->curr.xfer_size;
1298 host->curr.data_xfered = 0;
1299 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301300 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001301
San Mehat9d2bd732009-09-22 16:44:22 -07001302 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1303
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301304 if (host->curr.wait_for_auto_prog_done)
1305 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001306
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301307 if (msmsdcc_is_dma_possible(host, data)) {
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301308 if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 datactrl |= MCI_DPSM_DMAENABLE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301310 } else if (is_sps_mode(host)) {
Krishna Konda7a05d532012-08-19 11:16:39 -07001311 if (!msmsdcc_sps_start_xfer(host, data)) {
1312 /* Now kick start DML transfer */
1313 mb();
1314 msmsdcc_dml_start_xfer(host, data);
1315 datactrl |= MCI_DPSM_DMAENABLE;
1316 host->sps.busy = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 }
1318 }
1319 }
1320
1321 /* Is data transfer in PIO mode required? */
1322 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001323 if (data->flags & MMC_DATA_READ) {
1324 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1325 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1326 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1327 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1329 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001330
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001331 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001332 }
1333
1334 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301335 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301336 else if (host->curr.use_wr_data_pend)
1337 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001338
Subhash Jadavanicfa14072013-01-30 16:47:07 +05301339 if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
1340 clks = (unsigned long long)data->timeout_ns *
1341 (host->clk_rate / 2);
1342 else
1343 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
1344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001346 timeout = data->timeout_clks + (unsigned int)clks*2 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301347 WARN(!timeout,
1348 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1349 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001350
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301351 if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 /* Use ADM (Application Data Mover) HW for Data transfer */
1353 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001354 host->cmd_timeout = timeout;
1355 host->cmd_pio_irqmask = pio_irqmask;
1356 host->cmd_datactrl = datactrl;
1357 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1360 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001361 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001362
1363 if (cmd) {
1364 msmsdcc_start_command_deferred(host, cmd, &c);
1365 host->cmd_c = c;
1366 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1368 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1369 host->base + MMCIMASK0);
1370 mb();
1371 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001372 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001373 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1379 (~(MCI_IRQ_PIO))) | pio_irqmask,
1380 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001382
1383 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301384 /* Delay between data/command */
1385 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001386 /* Daisy-chain the command if requested */
1387 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301388 } else {
1389 /*
1390 * We don't need delay after writing to DATA_CTRL
1391 * register if we are not writing to CMD register
1392 * immediately after this. As we already have delay
1393 * before sending the command, we just need mb() here.
1394 */
1395 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001396 }
San Mehat9d2bd732009-09-22 16:44:22 -07001397 }
1398}
1399
1400static void
1401msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1402{
San Mehat56a8b5b2009-11-21 12:29:46 -08001403 msmsdcc_start_command_deferred(host, cmd, &c);
1404 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001405}
1406
1407static void
1408msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1409 unsigned int status)
1410{
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301411 if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
1412 u32 opcode = data->mrq->cmd->opcode;
1413
1414 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1415 || (opcode == MMC_BUS_TEST_R) ||
1416 (host->tuning_in_progress &&
1417 (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
1418 opcode == MMC_SEND_TUNING_BLOCK)))) {
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301419 /* Execute full tuning in case of CRC/timeout errors */
1420 host->saved_tuning_phase = INVALID_TUNING_PHASE;
1421
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301422 if (status & MCI_DATACRCFAIL) {
1423 pr_err("%s: Data CRC error\n",
1424 mmc_hostname(host->mmc));
1425 pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
1426 pr_err("%s: blksz %d, blocks %d\n", __func__,
1427 data->blksz, data->blocks);
1428 } else {
1429 pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
1430 mmc_hostname(host->mmc), opcode,
1431 (readl_relaxed(host->base
1432 + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
1433 msmsdcc_dump_sdcc_state(host);
1434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435 }
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301436
1437 /*
1438 * CRC is optional for the bus test commands, not all
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 * cards respond back with CRC. However controller
1440 * waits for the CRC and times out. Hence ignore the
1441 * data timeouts during the Bustest.
1442 */
Subhash Jadavanifd75b6372012-09-20 18:32:19 +05301443 if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
1444 || (opcode == MMC_BUS_TEST_R))) {
1445 if (status & MCI_DATACRCFAIL)
1446 data->error = -EILSEQ;
1447 else
1448 data->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 }
Subhash Jadavani355df542012-10-09 19:06:49 +05301450 /* In case of DATA CRC/timeout error, execute tuning again */
1451 if (host->tuning_needed && !host->tuning_in_progress)
1452 host->tuning_done = false;
1453
San Mehat9d2bd732009-09-22 16:44:22 -07001454 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001455 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001456 data->error = -EIO;
1457 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001458 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001459 data->error = -EIO;
1460 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001461 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001463 data->error = -EIO;
1464 }
San Mehat9d2bd732009-09-22 16:44:22 -07001465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001467 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 host->dummy_52_needed = 0;
1469}
San Mehat9d2bd732009-09-22 16:44:22 -07001470
1471static int
1472msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1473{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001475 uint32_t *ptr = (uint32_t *) buffer;
1476 int count = 0;
1477
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301478 if (remain % 4)
1479 remain = ((remain >> 2) + 1) << 2;
1480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1482
1483 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001484 ptr++;
1485 count += sizeof(uint32_t);
1486
1487 remain -= sizeof(uint32_t);
1488 if (remain == 0)
1489 break;
1490 }
1491 return count;
1492}
1493
1494static int
1495msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001497{
1498 void __iomem *base = host->base;
1499 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 while (readl_relaxed(base + MMCISTATUS) &
1503 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1504 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001505
San Mehat9d2bd732009-09-22 16:44:22 -07001506 count = min(remain, maxcnt);
1507
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301508 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1509 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001510 ptr += count;
1511 remain -= count;
1512
1513 if (remain == 0)
1514 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 }
1516 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001517
1518 return ptr - buffer;
1519}
1520
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001521/*
1522 * Copy up to a word (4 bytes) between a scatterlist
1523 * and a temporary bounce buffer when the word lies across
1524 * two pages. The temporary buffer can then be read to/
1525 * written from the FIFO once.
1526 */
1527static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001528{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001529 struct msmsdcc_pio_data *pio = &host->pio;
1530 unsigned int bytes_avail;
1531
1532 if (host->curr.data->flags & MMC_DATA_READ)
1533 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1534 pio->bounce_buf_len);
1535 else
1536 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1537 pio->bounce_buf_len);
1538
1539 while (pio->bounce_buf_len != 4) {
1540 if (!sg_miter_next(&pio->sg_miter))
1541 break;
1542 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1543 4 - pio->bounce_buf_len);
1544 if (host->curr.data->flags & MMC_DATA_READ)
1545 memcpy(pio->sg_miter.addr,
1546 &pio->bounce_buf[pio->bounce_buf_len],
1547 bytes_avail);
1548 else
1549 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1550 pio->sg_miter.addr, bytes_avail);
1551
1552 pio->sg_miter.consumed = bytes_avail;
1553 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001554 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001555}
1556
1557/*
1558 * Use sg_miter_next to return as many 4-byte aligned
1559 * chunks as possible, using a temporary 4 byte buffer
1560 * for alignment if necessary
1561 */
1562static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1563{
1564 struct msmsdcc_pio_data *pio = &host->pio;
1565 unsigned int length, rlength;
1566 char *buffer;
1567
1568 if (!sg_miter_next(&pio->sg_miter))
1569 return 0;
1570
1571 buffer = pio->sg_miter.addr;
1572 length = pio->sg_miter.length;
1573
1574 if (length < host->curr.xfer_remain) {
1575 rlength = round_down(length, 4);
1576 if (rlength) {
1577 /*
1578 * We have a 4-byte aligned chunk.
1579 * The rounding will be reflected by
1580 * a call to msmsdcc_sg_consumed
1581 */
1582 length = rlength;
1583 goto sg_next_end;
1584 }
1585 /*
1586 * We have a length less than 4 bytes. Check to
1587 * see if more buffer is available, and combine
1588 * to make 4 bytes if possible.
1589 */
1590 pio->bounce_buf_len = length;
1591 memset(pio->bounce_buf, 0, 4);
1592
1593 /*
1594 * On a read, get 4 bytes from FIFO, and distribute
1595 * (4-bouce_buf_len) bytes into consecutive
1596 * sgl buffers when msmsdcc_sg_consumed is called
1597 */
1598 if (host->curr.data->flags & MMC_DATA_READ) {
1599 buffer = pio->bounce_buf;
1600 length = 4;
1601 goto sg_next_end;
1602 } else {
1603 _msmsdcc_sg_consume_word(host);
1604 buffer = pio->bounce_buf;
1605 length = pio->bounce_buf_len;
1606 }
1607 }
1608
1609sg_next_end:
1610 *buf = buffer;
1611 *len = length;
1612 return 1;
1613}
1614
1615/*
1616 * Update sg_miter.consumed based on how many bytes were
1617 * consumed. If the bounce buffer was used to read from FIFO,
1618 * redistribute into sgls.
1619 */
1620static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1621 unsigned int length)
1622{
1623 struct msmsdcc_pio_data *pio = &host->pio;
1624
1625 if (host->curr.data->flags & MMC_DATA_READ) {
1626 if (length > pio->sg_miter.consumed)
1627 /*
1628 * consumed 4 bytes, but sgl
1629 * describes < 4 bytes
1630 */
1631 _msmsdcc_sg_consume_word(host);
1632 else
1633 pio->sg_miter.consumed = length;
1634 } else
1635 if (length < pio->sg_miter.consumed)
1636 pio->sg_miter.consumed = length;
1637}
1638
1639static void msmsdcc_sg_start(struct msmsdcc_host *host)
1640{
1641 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1642
1643 host->pio.bounce_buf_len = 0;
1644
1645 if (host->curr.data->flags & MMC_DATA_READ)
1646 sg_miter_flags |= SG_MITER_TO_SG;
1647 else
1648 sg_miter_flags |= SG_MITER_FROM_SG;
1649
1650 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1651 host->curr.data->sg_len, sg_miter_flags);
1652}
1653
1654static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1655{
1656 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001657}
1658
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05301659static inline void msmsdcc_clear_pio_irq_mask(struct msmsdcc_host *host)
1660{
1661 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) & ~MCI_IRQ_PIO,
1662 host->base + MMCIMASK0);
1663 mb();
1664}
1665
San Mehat1cd22962010-02-03 12:59:29 -08001666static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001667msmsdcc_pio_irq(int irq, void *dev_id)
1668{
1669 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001671 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001672 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001673 unsigned int remain;
1674 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001675
Murali Palnati36448a42011-09-02 15:06:18 +05301676 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301677
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05301678 if (!atomic_read(&host->clks_on) || !host->curr.data) {
Oluwafemi Adeyemi0bcb1332012-12-07 16:21:22 -08001679 spin_unlock(&host->lock);
1680 return IRQ_NONE;
1681 }
1682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001685 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301686 (MCI_IRQ_PIO)) == 0) {
1687 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301688 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301689 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690#if IRQ_DEBUG
1691 msmsdcc_print_status(host, "irq1-r", status);
1692#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001693 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001694
1695 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001696 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1699 | MCI_RXDATAAVLBL)))
1700 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001701
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001702 if (!msmsdcc_sg_next(host, &buffer, &remain))
1703 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001704
San Mehat9d2bd732009-09-22 16:44:22 -07001705 len = 0;
1706 if (status & MCI_RXACTIVE)
1707 len = msmsdcc_pio_read(host, buffer, remain);
1708 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001710
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301711 /* len might have aligned to 32bits above */
1712 if (len > remain)
1713 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001714
San Mehat9d2bd732009-09-22 16:44:22 -07001715 host->curr.xfer_remain -= len;
1716 host->curr.data_xfered += len;
1717 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001718 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 if (remain) /* Done with this page? */
1721 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001724 } while (1);
1725
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001726 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001727 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001728
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05301729 if (!host->curr.xfer_remain) {
1730 msmsdcc_clear_pio_irq_mask(host);
1731 goto out_unlock;
1732 }
1733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1735 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05301736 ~MCI_IRQ_PIO) | MCI_RXDATAAVLBLMASK,
1737 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 mb();
1739 }
San Mehat9d2bd732009-09-22 16:44:22 -07001740
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05301741out_unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001743
1744 return IRQ_HANDLED;
1745}
1746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747static void
1748msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1749
1750static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1751 struct mmc_data *data)
1752{
1753 u32 loop_cnt = 0;
1754
1755 /*
1756 * For read commands with data less than fifo size, it is possible to
1757 * get DATAEND first and RXDATA_AVAIL might be set later because of
1758 * synchronization delay through the asynchronous RX FIFO. Thus, for
1759 * such cases, even after DATAEND interrupt is received software
1760 * should poll for RXDATA_AVAIL until the requested data is read out
1761 * of FIFO. This change is needed to get around this abnormal but
1762 * sometimes expected behavior of SDCC3 controller.
1763 *
1764 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1765 * after the data is loaded into RX FIFO. This would amount to less
1766 * than a microsecond and thus looping for 1000 times is good enough
1767 * for that delay.
1768 */
1769 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1770 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1771 spin_unlock(&host->lock);
1772 msmsdcc_pio_irq(1, host);
1773 spin_lock(&host->lock);
1774 }
1775 }
1776 if (loop_cnt == 1000) {
1777 pr_info("%s: Timed out while polling for Rx Data\n",
1778 mmc_hostname(host->mmc));
1779 data->error = -ETIMEDOUT;
1780 msmsdcc_reset_and_restore(host);
1781 }
1782}
1783
San Mehat9d2bd732009-09-22 16:44:22 -07001784static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1785{
1786 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001787
1788 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301789 if (mmc_resp_type(cmd))
1790 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1791 /*
1792 * Read rest of the response registers only if
1793 * long response is expected for this command
1794 */
1795 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1796 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1797 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1798 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1799 }
San Mehat9d2bd732009-09-22 16:44:22 -07001800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301802 pr_debug("%s: CMD%d: Command timeout\n",
1803 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001804 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301806 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301807 pr_err("%s: CMD%d: Command CRC error\n",
1808 mmc_hostname(host->mmc), cmd->opcode);
1809 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301810 /* Execute full tuning in case of CRC errors */
1811 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Subhash Jadavani355df542012-10-09 19:06:49 +05301812 if (host->tuning_needed)
1813 host->tuning_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001814 cmd->error = -EILSEQ;
1815 }
1816
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301817 if (!cmd->error) {
1818 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1819 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1820 mod_timer(&host->req_tout_timer, (jiffies +
1821 msecs_to_jiffies(host->curr.req_tout_ms)));
1822 }
1823 }
1824
San Mehat9d2bd732009-09-22 16:44:22 -07001825 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301827 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001828 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301830 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 /* Stop current SPS transfer */
1832 msmsdcc_sps_exit_curr_xfer(host);
1833 }
San Mehat9d2bd732009-09-22 16:44:22 -07001834 else if (host->curr.data) { /* Non DMA */
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05301835 msmsdcc_clear_pio_irq_mask(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301836 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001837 msmsdcc_stop_data(host);
1838 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301839 } else { /* host->data == NULL */
1840 if (!cmd->error && host->prog_enable) {
1841 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301843 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301845 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301846 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301847 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301848 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001849 if (host->dummy_52_needed)
1850 host->dummy_52_needed = 0;
1851 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001852 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301853 msmsdcc_request_end(host, cmd->mrq);
1854 }
1855 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301856 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301857 if (cmd == host->curr.mrq->sbc)
1858 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1859 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1860 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301861 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001862 }
1863}
1864
San Mehat9d2bd732009-09-22 16:44:22 -07001865static irqreturn_t
1866msmsdcc_irq(int irq, void *dev_id)
1867{
1868 struct msmsdcc_host *host = dev_id;
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301869 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001870 u32 status;
1871 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001873
1874 spin_lock(&host->lock);
1875
1876 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877 struct mmc_command *cmd;
1878 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001879
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 if (timer) {
1881 timer = 0;
1882 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001883 }
San Mehat9d2bd732009-09-22 16:44:22 -07001884
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301885 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 pr_debug("%s: %s: SDIO async irq received\n",
1887 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301888
1889 /*
1890 * Only async interrupt can come when clocks are off,
1891 * disable further interrupts and enable them when
1892 * clocks are on.
1893 */
1894 if (!host->sdcc_irq_disabled) {
1895 disable_irq_nosync(irq);
1896 host->sdcc_irq_disabled = 1;
1897 }
1898
1899 /*
1900 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1901 * will take care of signaling sdio irq during
1902 * mmc_sdio_resume().
1903 */
Krishna Konda1963f432013-02-19 20:28:53 -08001904 if (host->sdcc_suspended &&
1905 (host->plat->mpm_sdiowakeup_int ||
1906 host->plat->sdiowakeup_irq)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301907 /*
1908 * This is a wakeup interrupt so hold wakelock
1909 * until SDCC resume is handled.
1910 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301912 } else {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301913 if (!mmc->card || (mmc->card &&
1914 !mmc_card_sdio(mmc->card))) {
1915 pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1916 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301917 ret = 1;
1918 break;
1919 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301920 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301921 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301922 spin_lock(&host->lock);
1923 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301924 ret = 1;
1925 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 }
1927
1928 status = readl_relaxed(host->base + MMCISTATUS);
1929
1930 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1931 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001932 break;
1933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934#if IRQ_DEBUG
1935 msmsdcc_print_status(host, "irq0-r", status);
1936#endif
1937 status &= readl_relaxed(host->base + MMCIMASK0);
1938 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301939 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301940 if (host->clk_rate <=
1941 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301942 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943#if IRQ_DEBUG
1944 msmsdcc_print_status(host, "irq0-p", status);
1945#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001946
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001947 if (status & MCI_SDIOINTROPE) {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301948 if (!mmc->card || (mmc->card &&
1949 !mmc_card_sdio(mmc->card))) {
1950 pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
1951 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301952 ret = 1;
1953 break;
1954 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955 if (host->sdcc_suspending)
1956 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301957 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301959 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001960 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001961 data = host->curr.data;
1962
1963 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001964 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1965 MCI_CMDTIMEOUT)) {
1966 if (status & MCI_CMDTIMEOUT)
1967 pr_debug("%s: dummy CMD52 timeout\n",
1968 mmc_hostname(host->mmc));
1969 if (status & MCI_CMDCRCFAIL)
1970 pr_debug("%s: dummy CMD52 CRC failed\n",
1971 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001972 host->dummy_52_sent = 0;
1973 host->dummy_52_needed = 0;
1974 if (data) {
1975 msmsdcc_stop_data(host);
1976 msmsdcc_request_end(host, data->mrq);
1977 }
1978 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 spin_unlock(&host->lock);
1980 return IRQ_HANDLED;
1981 }
1982 break;
1983 }
1984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 /*
1986 * Check for proper command response
1987 */
1988 cmd = host->curr.cmd;
1989 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1990 MCI_CMDTIMEOUT | MCI_PROGDONE |
1991 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1992 msmsdcc_do_cmdirq(host, status);
1993 }
1994
Subhash Jadavani2d7980f2013-01-09 16:18:08 +05301995 if (data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996 /* Check for data errors */
1997 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1998 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1999 msmsdcc_data_err(host, data, status);
2000 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302001 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07002002 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302003 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 /* Stop current SPS transfer */
2005 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302006 } else {
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05302007 msmsdcc_clear_pio_irq_mask(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 msmsdcc_reset_and_restore(host);
2009 if (host->curr.data)
2010 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302011 if (!data->stop || (host->curr.mrq->sbc
2012 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 timer |=
2014 msmsdcc_request_end(host,
2015 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302016 else if ((host->curr.mrq->sbc
2017 && data->error) ||
2018 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 msmsdcc_start_command(host,
2020 data->stop,
2021 0);
2022 timer = 1;
2023 }
2024 }
2025 }
2026
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302027 /* Check for prog done */
2028 if (host->curr.wait_for_auto_prog_done &&
2029 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302030 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 /* Check for data done */
2033 if (!host->curr.got_dataend && (status & MCI_DATAEND))
2034 host->curr.got_dataend = 1;
2035
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302036 if (host->curr.got_dataend &&
2037 (!host->curr.wait_for_auto_prog_done ||
2038 (host->curr.wait_for_auto_prog_done &&
2039 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040 /*
2041 * If DMA is still in progress, we complete
2042 * via the completion handler
2043 */
2044 if (!host->dma.busy && !host->sps.busy) {
2045 /*
2046 * There appears to be an issue in the
2047 * controller where if you request a
2048 * small block transfer (< fifo size),
2049 * you may get your DATAEND/DATABLKEND
2050 * irq without the PIO data irq.
2051 *
2052 * Check to see if theres still data
2053 * to be read, and simulate a PIO irq.
2054 */
2055 if (data->flags & MMC_DATA_READ)
2056 msmsdcc_wait_for_rxdata(host,
2057 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 if (!data->error) {
2059 host->curr.data_xfered =
2060 host->curr.xfer_size;
2061 host->curr.xfer_remain -=
2062 host->curr.xfer_size;
2063 }
2064
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002065 if (!host->dummy_52_needed) {
2066 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302067 if (!data->stop ||
2068 (host->curr.mrq->sbc
2069 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002070 msmsdcc_request_end(
2071 host,
2072 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302073 else if ((host->curr.mrq->sbc
2074 && data->error) ||
2075 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002076 msmsdcc_start_command(
2077 host,
2078 data->stop, 0);
2079 timer = 1;
2080 }
2081 } else {
2082 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002083 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002084 &dummy52cmd,
2085 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002086 }
2087 }
2088 }
2089 }
2090
San Mehat9d2bd732009-09-22 16:44:22 -07002091 ret = 1;
2092 } while (status);
2093
2094 spin_unlock(&host->lock);
2095
San Mehat9d2bd732009-09-22 16:44:22 -07002096 return IRQ_RETVAL(ret);
2097}
2098
2099static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302100msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2101 bool is_first_request)
2102{
2103 struct msmsdcc_host *host = mmc_priv(mmc);
2104 struct mmc_data *data = mrq->data;
2105 int rc = 0;
2106
2107 if (unlikely(!data)) {
2108 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2109 __func__);
2110 return;
2111 }
2112 if (unlikely(data->host_cookie)) {
2113 /* Very wrong */
2114 data->host_cookie = 0;
2115 pr_err("%s: %s Request reposted for prepare\n",
2116 mmc_hostname(mmc), __func__);
2117 return;
2118 }
2119
2120 if (!msmsdcc_is_dma_possible(host, data))
2121 return;
2122
2123 rc = msmsdcc_prep_xfer(host, data);
2124 if (unlikely(rc < 0)) {
2125 data->host_cookie = 0;
2126 return;
2127 }
2128
2129 data->host_cookie = 1;
2130}
2131
2132static void
2133msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2134{
2135 struct msmsdcc_host *host = mmc_priv(mmc);
2136 unsigned int dir;
2137 struct mmc_data *data = mrq->data;
2138
2139 if (unlikely(!data)) {
2140 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2141 __func__);
2142 return;
2143 }
2144 if (data->flags & MMC_DATA_READ)
2145 dir = DMA_FROM_DEVICE;
2146 else
2147 dir = DMA_TO_DEVICE;
2148
2149 if (data->host_cookie)
2150 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2151 data->sg_len, dir);
2152
2153 data->host_cookie = 0;
2154}
2155
2156static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2158{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302159 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302161 if ((mrq->data->flags & MMC_DATA_READ) ||
2162 host->curr.use_wr_data_pend)
2163 msmsdcc_start_data(host, mrq->data,
2164 mrq->sbc ? mrq->sbc : mrq->cmd,
2165 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302166 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302167 msmsdcc_start_command(host,
2168 mrq->sbc ? mrq->sbc : mrq->cmd,
2169 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170 } else {
2171 msmsdcc_start_command(host, mrq->cmd, 0);
2172 }
2173}
2174
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302175/*
2176 * This function returns true if AUTO_PROG_DONE feature of host is
2177 * applicable for current request, returns "false" otherwise.
2178 *
2179 * NOTE: Caller should call this function only for data write operations.
2180 */
2181static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2182 struct mmc_request *mrq)
2183{
2184 /*
2185 * Auto-prog done will be enabled for following cases:
2186 * mrq->sbc | mrq->stop
2187 * _____________|________________
2188 * True | Don't care
2189 * False | False (CMD24, ACMD25 use case)
2190 */
2191 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2192 return true;
2193
2194 return false;
2195}
2196
2197/*
2198 * This function returns true if controller can wait for prog done
2199 * for current request, returns "false" otherwise.
2200 *
2201 * NOTE: Caller should call this function only for data write operations.
2202 */
2203static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2204 struct mmc_request *mrq)
2205{
2206 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2207 return true;
2208
2209 return false;
2210}
2211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002212static void
San Mehat9d2bd732009-09-22 16:44:22 -07002213msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2214{
2215 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302216 unsigned long flags;
Krishna Konda3d47c822013-02-21 18:28:11 -08002217 unsigned int error = 0;
Krishna Konda3ca90f02012-08-29 16:29:21 -07002218 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220 /*
2221 * Get the SDIO AL client out of LPM.
2222 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002223 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 if (host->plat->is_sdio_al_client)
2225 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002226
Krishna Konda3d47c822013-02-21 18:28:11 -08002227 /*
2228 * Don't start the request if SDCC is not in proper state to handle it
2229 * BAM state is checked below if applicable
2230 */
2231 if (!host->pwr || !atomic_read(&host->clks_on) ||
2232 host->sdcc_irq_disabled) {
2233 WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
2234 mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
2235 error = EIO;
2236 goto bad_state;
2237 }
2238
Krishna Konda3ca90f02012-08-29 16:29:21 -07002239 /* check if sps bam needs to be reset */
2240 if (is_sps_mode(host) && host->sps.reset_bam) {
2241 while (retries) {
2242 if (!msmsdcc_bam_dml_reset_and_restore(host))
2243 break;
2244 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2245 mmc_hostname(host->mmc), --retries);
2246 }
Krishna Konda3d47c822013-02-21 18:28:11 -08002247
2248 /* check if BAM reset succeeded or not */
2249 if (host->sps.reset_bam) {
2250 pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
2251 mmc_hostname(host->mmc), mrq->cmd->opcode);
2252 error = EAGAIN;
2253 goto bad_state;
2254 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302255 }
San Mehat9d2bd732009-09-22 16:44:22 -07002256
Subhash Jadavani355df542012-10-09 19:06:49 +05302257 /*
2258 * Check if DLL retuning is required? If yes, perform it here before
2259 * starting new request.
2260 */
2261 if (host->tuning_needed && !host->tuning_in_progress &&
2262 !host->tuning_done) {
2263 pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
2264 mmc_hostname(mmc), __func__, host->mmc->ios.timing);
2265 if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
2266 msmsdcc_execute_tuning(mmc,
2267 MMC_SEND_TUNING_BLOCK);
2268 else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
2269 msmsdcc_execute_tuning(mmc,
2270 MMC_SEND_TUNING_BLOCK_HS200);
2271 }
2272
San Mehat9d2bd732009-09-22 16:44:22 -07002273 if (host->eject) {
Krishna Konda3d47c822013-02-21 18:28:11 -08002274 error = ENOMEDIUM;
2275 goto card_ejected;
subhashjf181c292012-05-02 13:07:40 +05302276 }
2277
2278 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2279 " other request (CMD%d) is in progress\n",
2280 mmc_hostname(host->mmc), __func__,
2281 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2282
Krishna Konda3d47c822013-02-21 18:28:11 -08002283 spin_lock_irqsave(&host->lock, flags);
2284
subhashjf181c292012-05-02 13:07:40 +05302285 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302286 * Set timeout value to 10 secs (or more in case of buggy cards)
2287 */
2288 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302289 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302290 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302291 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302292 /*
2293 * Kick the software request timeout timer here with the timeout
2294 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302295 */
2296 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302297 (jiffies +
2298 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002299
San Mehat9d2bd732009-09-22 16:44:22 -07002300 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302301 if (mrq->sbc) {
2302 mrq->sbc->mrq = mrq;
2303 mrq->sbc->data = mrq->data;
2304 }
2305
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302306 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302307 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2308 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302309 } else {
2310 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2311 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312 host->dummy_52_needed = 1;
2313 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302314
Subhash Jadavanif5277752011-10-12 16:47:52 +05302315 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
Subhash Jadavanicf58e6f2012-10-05 20:45:54 +05302316 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
2317 ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
2318 is_data_pend_for_cmd53(host)))
Subhash Jadavanif5277752011-10-12 16:47:52 +05302319 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002320 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302321
Subhash Jadavanif5277752011-10-12 16:47:52 +05302322 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002323 spin_unlock_irqrestore(&host->lock, flags);
Krishna Konda3d47c822013-02-21 18:28:11 -08002324 return;
2325
2326bad_state:
2327 msmsdcc_dump_sdcc_state(host);
2328card_ejected:
2329 mrq->cmd->error = -error;
2330 if (mrq->data) {
2331 mrq->data->error = -error;
2332 mrq->data->bytes_xfered = 0;
2333 }
2334 mmc_request_done(mmc, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002335}
2336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2338 int min_uV, int max_uV)
2339{
2340 int rc = 0;
2341
2342 if (vreg->set_voltage_sup) {
2343 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2344 if (rc) {
2345 pr_err("%s: regulator_set_voltage(%s) failed."
2346 " min_uV=%d, max_uV=%d, rc=%d\n",
2347 __func__, vreg->name, min_uV, max_uV, rc);
2348 }
2349 }
2350
2351 return rc;
2352}
2353
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302354static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2355{
2356 int rc = 0;
2357
2358 rc = regulator_get_voltage(vreg->reg);
2359 if (rc < 0)
2360 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2361 __func__, vreg->name, rc);
2362
2363 return rc;
2364}
2365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2367 int uA_load)
2368{
2369 int rc = 0;
2370
Krishna Kondafea60182011-11-01 16:01:34 -07002371 /* regulators that do not support regulator_set_voltage also
2372 do not support regulator_set_optimum_mode */
2373 if (vreg->set_voltage_sup) {
2374 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2375 if (rc < 0)
2376 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2377 "uA_load=%d) failed. rc=%d\n", __func__,
2378 vreg->name, uA_load, rc);
2379 else
2380 /* regulator_set_optimum_mode() can return non zero
2381 * value even for success case.
2382 */
2383 rc = 0;
2384 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385
2386 return rc;
2387}
2388
2389static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2390 struct device *dev)
2391{
2392 int rc = 0;
2393
2394 /* check if regulator is already initialized? */
2395 if (vreg->reg)
2396 goto out;
2397
2398 /* Get the regulator handle */
2399 vreg->reg = regulator_get(dev, vreg->name);
2400 if (IS_ERR(vreg->reg)) {
2401 rc = PTR_ERR(vreg->reg);
2402 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2403 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002404 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002406
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302407 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002408 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302409 /* sanity check */
2410 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2411 pr_err("%s: %s invalid constraints specified\n",
2412 __func__, vreg->name);
2413 rc = -EINVAL;
2414 }
2415 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417out:
2418 return rc;
2419}
2420
2421static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2422{
2423 if (vreg->reg)
2424 regulator_put(vreg->reg);
2425}
2426
2427/* This init function should be called only once for each SDCC slot */
2428static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2429{
2430 int rc = 0;
2431 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302432 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002433 struct device *dev = mmc_dev(host->mmc);
2434
2435 curr_slot = host->plat->vreg_data;
2436 if (!curr_slot)
2437 goto out;
2438
2439 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302440 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002441
2442 if (is_init) {
2443 /*
2444 * Get the regulator handle from voltage regulator framework
2445 * and then try to set the voltage level for the regulator
2446 */
2447 if (curr_vdd_reg) {
2448 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2449 if (rc)
2450 goto out;
2451 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302452 if (curr_vdd_io_reg) {
2453 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 if (rc)
2455 goto vdd_reg_deinit;
2456 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002457 rc = msmsdcc_vreg_reset(host);
2458 if (rc)
2459 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302460 host->pdev->id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 goto out;
2462 } else {
2463 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302464 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302466vdd_io_reg_deinit:
2467 if (curr_vdd_io_reg)
2468 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002469vdd_reg_deinit:
2470 if (curr_vdd_reg)
2471 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2472out:
2473 return rc;
2474}
2475
2476static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2477{
2478 int rc = 0;
2479
Subhash Jadavanicc922692011-08-01 23:05:01 +05302480 /* Put regulator in HPM (high power mode) */
2481 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2482 if (rc < 0)
2483 goto out;
2484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 if (!vreg->is_enabled) {
2486 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302487 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2488 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489 if (rc)
2490 goto out;
2491
2492 rc = regulator_enable(vreg->reg);
2493 if (rc) {
2494 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2495 __func__, vreg->name, rc);
2496 goto out;
2497 }
2498 vreg->is_enabled = true;
2499 }
2500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501out:
2502 return rc;
2503}
2504
Krishna Konda3c4142d2012-06-27 11:01:56 -07002505static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506{
2507 int rc = 0;
2508
2509 /* Never disable regulator marked as always_on */
2510 if (vreg->is_enabled && !vreg->always_on) {
2511 rc = regulator_disable(vreg->reg);
2512 if (rc) {
2513 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2514 __func__, vreg->name, rc);
2515 goto out;
2516 }
2517 vreg->is_enabled = false;
2518
2519 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2520 if (rc < 0)
2521 goto out;
2522
2523 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302524 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 if (rc)
2526 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002527 } else if (vreg->is_enabled && vreg->always_on) {
2528 if (!is_init && vreg->lpm_sup) {
2529 /* Put always_on regulator in LPM (low power mode) */
2530 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2531 if (rc < 0)
2532 goto out;
2533 } else if (is_init && vreg->reset_at_init) {
2534 /**
2535 * The regulator might not actually be disabled if it
2536 * is shared and in use by other drivers.
2537 */
2538 rc = regulator_disable(vreg->reg);
2539 if (rc) {
2540 pr_err("%s: regulator_disable(%s) failed at " \
2541 "bootup. rc=%d\n", __func__,
2542 vreg->name, rc);
2543 goto out;
2544 }
2545 vreg->is_enabled = false;
2546 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 }
2548out:
2549 return rc;
2550}
2551
Krishna Konda3c4142d2012-06-27 11:01:56 -07002552static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2553 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554{
2555 int rc = 0, i;
2556 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302557 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558
2559 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302560 if (!curr_slot) {
Asutosh Dasd5902bf2012-10-03 18:28:20 +05302561 pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
2562 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302564 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565
Subhash Jadavani937c7502012-06-01 15:34:46 +05302566 vreg_table[0] = curr_slot->vdd_data;
2567 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568
2569 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2570 if (vreg_table[i]) {
2571 if (enable)
2572 rc = msmsdcc_vreg_enable(vreg_table[i]);
2573 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002574 rc = msmsdcc_vreg_disable(vreg_table[i],
2575 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002576 if (rc)
2577 goto out;
2578 }
2579 }
2580out:
2581 return rc;
2582}
2583
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002584/*
2585 * Reset vreg by ensuring it is off during probe. A call
2586 * to enable vreg is needed to balance disable vreg
2587 */
2588static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2589{
2590 int rc;
2591
Krishna Konda3c4142d2012-06-27 11:01:56 -07002592 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002593 if (rc)
2594 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002595 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002596 return rc;
2597}
2598
Subhash Jadavani937c7502012-06-01 15:34:46 +05302599enum vdd_io_level {
2600 /* set vdd_io_data->low_vol_level */
2601 VDD_IO_LOW,
2602 /* set vdd_io_data->high_vol_level */
2603 VDD_IO_HIGH,
2604 /*
2605 * set whatever there in voltage_level (third argument) of
2606 * msmsdcc_set_vdd_io_vol() function.
2607 */
2608 VDD_IO_SET_LEVEL,
2609};
2610
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302611/*
2612 * This function returns the current VDD IO voltage level.
2613 * Returns negative value if it fails to read the voltage level
2614 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2615 * regulator were not defined for host.
2616 */
2617static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2618{
2619 int rc = 0;
2620
2621 if (host->plat->vreg_data) {
2622 struct msm_mmc_reg_data *io_reg =
2623 host->plat->vreg_data->vdd_io_data;
2624
2625 /*
2626 * If vdd_io is not defined, then we can consider that
2627 * IO voltage is same as VDD.
2628 */
2629 if (!io_reg)
2630 io_reg = host->plat->vreg_data->vdd_data;
2631
2632 if (io_reg && io_reg->is_enabled)
2633 rc = msmsdcc_vreg_get_voltage(io_reg);
2634 }
2635
2636 return rc;
2637}
2638
2639/*
2640 * This function updates the IO pad power switch bit in MCI_CLK register
2641 * based on currrent IO pad voltage level.
2642 * NOTE: This function assumes that host lock was not taken by caller.
2643 */
2644static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2645{
2646 int rc = 0;
2647 unsigned long flags;
2648
2649 if (!is_io_pad_pwr_switch(host))
2650 return;
2651
2652 rc = msmsdcc_get_vdd_io_vol(host);
2653
2654 spin_lock_irqsave(&host->lock, flags);
2655 /*
2656 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2657 * the SDCC instances support the dual voltage pads.
2658 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2659 * bit before using the pads in 1.8V mode.
2660 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2661 * IO_PAD_PWR_SWITCH bit is a don't care.
2662 * But we don't have an option to know (by reading some SDCC register)
2663 * that a particular SDCC instance supports dual voltage pads or not,
2664 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2665 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2666 * is anyway ignored.
2667 */
2668 if (rc > 0 && rc < 2700000)
2669 host->io_pad_pwr_switch = 1;
2670 else
2671 host->io_pad_pwr_switch = 0;
2672
2673 if (atomic_read(&host->clks_on)) {
2674 if (host->io_pad_pwr_switch)
2675 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2676 IO_PAD_PWR_SWITCH),
2677 host->base + MMCICLOCK);
2678 else
2679 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2680 ~IO_PAD_PWR_SWITCH),
2681 host->base + MMCICLOCK);
2682 msmsdcc_sync_reg_wr(host);
2683 }
2684 spin_unlock_irqrestore(&host->lock, flags);
2685}
2686
Subhash Jadavani937c7502012-06-01 15:34:46 +05302687static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2688 enum vdd_io_level level,
2689 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690{
2691 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302692 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693
2694 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302695 struct msm_mmc_reg_data *vdd_io_reg =
2696 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697
Subhash Jadavani937c7502012-06-01 15:34:46 +05302698 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2699 switch (level) {
2700 case VDD_IO_LOW:
2701 set_level = vdd_io_reg->low_vol_level;
2702 break;
2703 case VDD_IO_HIGH:
2704 set_level = vdd_io_reg->high_vol_level;
2705 break;
2706 case VDD_IO_SET_LEVEL:
2707 set_level = voltage_level;
2708 break;
2709 default:
2710 pr_err("%s: %s: invalid argument level = %d",
2711 mmc_hostname(host->mmc), __func__,
2712 level);
2713 rc = -EINVAL;
2714 goto out;
2715 }
2716 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2717 set_level, set_level);
2718 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 }
2720
Subhash Jadavani937c7502012-06-01 15:34:46 +05302721out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302722 return rc;
2723}
2724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002725static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2726{
2727 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2728 return 1;
2729 return 0;
2730}
2731
Asutosh Dasf5298c32012-04-03 14:51:47 +05302732/*
2733 * Any function calling msmsdcc_setup_clocks must
2734 * acquire clk_mutex. May sleep.
2735 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302736static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302738 int rc = 0;
2739
2740 if (enable && !atomic_read(&host->clks_on)) {
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302741 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &host->mmc->ios);
2742
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302743 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2744 rc = clk_prepare_enable(host->bus_clk);
2745 if (rc) {
2746 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2747 mmc_hostname(host->mmc), __func__, rc);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302748 goto remove_vote;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302749 }
2750 }
2751 if (!IS_ERR(host->pclk)) {
2752 rc = clk_prepare_enable(host->pclk);
2753 if (rc) {
2754 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2755 mmc_hostname(host->mmc), __func__, rc);
2756 goto disable_bus;
2757 }
2758 }
2759 rc = clk_prepare_enable(host->clk);
2760 if (rc) {
2761 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2762 mmc_hostname(host->mmc), __func__, rc);
2763 goto disable_pclk;
2764 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302765 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302766 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302767 atomic_set(&host->clks_on, 1);
2768 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302769 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302770 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302771 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302773 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302774 if (!IS_ERR_OR_NULL(host->bus_clk))
2775 clk_disable_unprepare(host->bus_clk);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302776
2777 /*
2778 * If clock gating is enabled, then remove the vote
2779 * immediately because clocks will be disabled only
2780 * after MSM_MMC_CLK_GATE_DELAY and thus no additional
2781 * delay is required to remove the bus vote.
2782 */
2783 if (host->mmc->clkgate_delay)
2784 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
2785 else
2786 msmsdcc_msm_bus_queue_work(host);
2787
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302788 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002789 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302790 goto out;
2791
2792disable_pclk:
2793 if (!IS_ERR_OR_NULL(host->pclk))
2794 clk_disable_unprepare(host->pclk);
2795disable_bus:
2796 if (!IS_ERR_OR_NULL(host->bus_clk))
2797 clk_disable_unprepare(host->bus_clk);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302798remove_vote:
2799 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302800out:
2801 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002802}
2803
2804static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2805 unsigned int req_clk)
2806{
2807 unsigned int sel_clk = -1;
2808
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302809 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2810 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2811 goto out;
2812 }
2813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002814 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2815 unsigned char cnt;
2816
2817 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2818 if (host->plat->sup_clk_table[cnt] > req_clk)
2819 break;
2820 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2821 sel_clk = host->plat->sup_clk_table[cnt];
2822 break;
2823 } else
2824 sel_clk = host->plat->sup_clk_table[cnt];
2825 }
2826 } else {
2827 if ((req_clk < host->plat->msmsdcc_fmax) &&
2828 (req_clk > host->plat->msmsdcc_fmid))
2829 sel_clk = host->plat->msmsdcc_fmid;
2830 else
2831 sel_clk = req_clk;
2832 }
2833
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302834out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002835 return sel_clk;
2836}
2837
2838static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2839 struct msmsdcc_host *host)
2840{
2841 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2842 return host->plat->sup_clk_table[0];
2843 else
2844 return host->plat->msmsdcc_fmin;
2845}
2846
2847static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2848 struct msmsdcc_host *host)
2849{
2850 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2851 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2852 else
2853 return host->plat->msmsdcc_fmax;
2854}
2855
2856static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302857{
2858 struct msm_mmc_gpio_data *curr;
2859 int i, rc = 0;
2860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302862 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302863 if (!gpio_is_valid(curr->gpio[i].no)) {
2864 rc = -EINVAL;
2865 pr_err("%s: Invalid gpio = %d\n",
2866 mmc_hostname(host->mmc), curr->gpio[i].no);
2867 goto free_gpios;
2868 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302869 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002870 if (curr->gpio[i].is_always_on &&
2871 curr->gpio[i].is_enabled)
2872 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302873 rc = gpio_request(curr->gpio[i].no,
2874 curr->gpio[i].name);
2875 if (rc) {
2876 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2877 mmc_hostname(host->mmc),
2878 curr->gpio[i].no,
2879 curr->gpio[i].name, rc);
2880 goto free_gpios;
2881 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302883 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 if (curr->gpio[i].is_always_on)
2885 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302886 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002887 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302888 }
2889 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002890 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302891
2892free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302893 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302894 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895 curr->gpio[i].is_enabled = false;
2896 }
2897out:
2898 return rc;
2899}
2900
2901static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2902{
2903 struct msm_mmc_pad_data *curr;
2904 int i;
2905
2906 curr = host->plat->pin_data->pad_data;
2907 for (i = 0; i < curr->drv->size; i++) {
2908 if (enable)
2909 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2910 curr->drv->on[i].val);
2911 else
2912 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2913 curr->drv->off[i].val);
2914 }
2915
2916 for (i = 0; i < curr->pull->size; i++) {
2917 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002918 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002919 curr->pull->on[i].val);
2920 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002921 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002922 curr->pull->off[i].val);
2923 }
2924
2925 return 0;
2926}
2927
2928static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2929{
2930 int rc = 0;
2931
2932 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2933 return 0;
2934
2935 if (host->plat->pin_data->is_gpio)
2936 rc = msmsdcc_setup_gpio(host, enable);
2937 else
2938 rc = msmsdcc_setup_pad(host, enable);
2939
2940 if (!rc)
2941 host->plat->pin_data->cfg_sts = enable;
2942
2943 return rc;
2944}
2945
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302946static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2947 unsigned mode)
2948{
2949 int ret = 0;
2950 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2951
2952 if (!pin)
2953 return 0;
2954
2955 switch (mode) {
2956 case SDC_DAT1_DISABLE:
2957 ret = msm_mpm_enable_pin(pin, 0);
2958 break;
2959 case SDC_DAT1_ENABLE:
2960 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2961 ret = msm_mpm_enable_pin(pin, 1);
2962 break;
2963 case SDC_DAT1_ENWAKE:
2964 ret = msm_mpm_set_pin_wake(pin, 1);
2965 break;
2966 case SDC_DAT1_DISWAKE:
2967 ret = msm_mpm_set_pin_wake(pin, 0);
2968 break;
2969 default:
2970 ret = -EINVAL;
2971 break;
2972 }
2973
2974 return ret;
2975}
2976
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302977static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2978{
2979 u32 pwr = 0;
2980 int ret = 0;
2981 struct mmc_host *mmc = host->mmc;
2982
2983 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2984 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2985 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002986 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302987
2988 if (ret) {
2989 pr_err("%s: Failed to setup voltage regulators\n",
2990 mmc_hostname(host->mmc));
2991 goto out;
2992 }
2993
2994 switch (ios->power_mode) {
2995 case MMC_POWER_OFF:
2996 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302997 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302998 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302999 * If VDD IO rail is always on, set low voltage for VDD
3000 * IO rail when slot is not in use (like when card is not
3001 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303002 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303003 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303004 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303005 msmsdcc_setup_pins(host, false);
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05303006 /*
3007 * Reset the mask to prevent hitting any pending interrupts
3008 * after powering up the card again.
3009 */
3010 if (atomic_read(&host->clks_on)) {
3011 writel_relaxed(0, host->base + MMCIMASK0);
3012 mb();
3013 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303014 break;
3015 case MMC_POWER_UP:
3016 /* writing PWR_UP bit is redundant */
3017 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303018 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303019
Subhash Jadavani937c7502012-06-01 15:34:46 +05303020 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303021 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303022 msmsdcc_setup_pins(host, true);
3023 break;
3024 case MMC_POWER_ON:
3025 pwr = MCI_PWR_ON;
3026 break;
3027 }
3028
3029out:
3030 return pwr;
3031}
3032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003033static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
3034{
3035 unsigned int wakeup_irq;
3036
3037 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3038 host->plat->sdiowakeup_irq :
3039 host->core_irqres->start;
3040
3041 if (!host->irq_wake_enabled) {
3042 enable_irq_wake(wakeup_irq);
3043 host->irq_wake_enabled = true;
3044 }
3045}
3046
3047static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
3048{
3049 unsigned int wakeup_irq;
3050
3051 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3052 host->plat->sdiowakeup_irq :
3053 host->core_irqres->start;
3054
3055 if (host->irq_wake_enabled) {
3056 disable_irq_wake(wakeup_irq);
3057 host->irq_wake_enabled = false;
3058 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05303059}
3060
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303061/* Returns required bandwidth in Bytes per Sec */
3062static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
3063 struct mmc_ios *ios)
3064{
3065 unsigned int bw;
3066
3067 bw = host->clk_rate;
3068 /*
3069 * For DDR mode, SDCC controller clock will be at
3070 * the double rate than the actual clock that goes to card.
3071 */
3072 if (ios->bus_width == MMC_BUS_WIDTH_4)
3073 bw /= 2;
3074 else if (ios->bus_width == MMC_BUS_WIDTH_1)
3075 bw /= 8;
3076
3077 return bw;
3078}
3079
3080static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
3081 unsigned int bw)
3082{
3083 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
3084 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
3085 int i;
3086
3087 if (host->msm_bus_vote.is_max_bw_needed && bw)
3088 return host->msm_bus_vote.max_bw_vote;
3089
3090 for (i = 0; i < size; i++) {
3091 if (bw <= table[i])
3092 break;
3093 }
3094
3095 if (i && (i == size))
3096 i--;
3097
3098 return i;
3099}
3100
3101static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
3102{
3103 int rc = 0;
3104 struct msm_bus_scale_pdata *use_cases;
3105
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303106 if (host->pdev->dev.of_node) {
3107 struct msm_mmc_bus_voting_data *data;
3108 struct device *dev = &host->pdev->dev;
3109
3110 data = devm_kzalloc(dev,
3111 sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
3112 if (!data) {
3113 dev_err(&host->pdev->dev,
3114 "%s: failed to allocate memory\n", __func__);
3115 rc = -ENOMEM;
3116 goto out;
3117 }
3118
3119 rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
3120 &data->bw_vecs, &data->bw_vecs_size, 0);
3121 if (!rc) {
3122 data->use_cases = msm_bus_cl_get_pdata(host->pdev);
3123 host->plat->msm_bus_voting_data = data;
3124 }
3125 }
3126
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303127 if (host->plat->msm_bus_voting_data &&
3128 host->plat->msm_bus_voting_data->use_cases &&
3129 host->plat->msm_bus_voting_data->bw_vecs &&
3130 host->plat->msm_bus_voting_data->bw_vecs_size) {
3131 use_cases = host->plat->msm_bus_voting_data->use_cases;
3132 host->msm_bus_vote.client_handle =
3133 msm_bus_scale_register_client(use_cases);
3134 } else {
3135 return 0;
3136 }
3137
3138 if (!host->msm_bus_vote.client_handle) {
3139 pr_err("%s: msm_bus_scale_register_client() failed\n",
3140 mmc_hostname(host->mmc));
3141 rc = -EFAULT;
3142 } else {
3143 /* cache the vote index for minimum and maximum bandwidth */
3144 host->msm_bus_vote.min_bw_vote =
3145 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3146 host->msm_bus_vote.max_bw_vote =
3147 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3148 }
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303149out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303150 return rc;
3151}
3152
3153static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3154{
3155 if (host->msm_bus_vote.client_handle)
3156 msm_bus_scale_unregister_client(
3157 host->msm_bus_vote.client_handle);
3158}
3159
3160/*
3161 * This function must be called with host lock acquired.
3162 * Caller of this function should also ensure that msm bus client
3163 * handle is not null.
3164 */
3165static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3166 int vote,
3167 unsigned long flags)
3168{
3169 int rc = 0;
3170
3171 if (vote != host->msm_bus_vote.curr_vote) {
3172 spin_unlock_irqrestore(&host->lock, flags);
3173 rc = msm_bus_scale_client_update_request(
3174 host->msm_bus_vote.client_handle, vote);
3175 if (rc)
3176 pr_err("%s: msm_bus_scale_client_update_request() failed."
3177 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3178 mmc_hostname(host->mmc),
3179 host->msm_bus_vote.client_handle, vote, rc);
3180 spin_lock_irqsave(&host->lock, flags);
3181 if (!rc)
3182 host->msm_bus_vote.curr_vote = vote;
3183 }
3184
3185 return rc;
3186}
3187
3188/*
3189 * Internal work. Work to set 0 bandwidth for msm bus.
3190 */
3191static void msmsdcc_msm_bus_work(struct work_struct *work)
3192{
3193 struct msmsdcc_host *host = container_of(work,
3194 struct msmsdcc_host,
3195 msm_bus_vote.vote_work.work);
3196 unsigned long flags;
3197
3198 if (!host->msm_bus_vote.client_handle)
3199 return;
3200
3201 spin_lock_irqsave(&host->lock, flags);
3202 /* don't vote for 0 bandwidth if any request is in progress */
3203 if (!host->curr.mrq)
3204 msmsdcc_msm_bus_set_vote(host,
3205 host->msm_bus_vote.min_bw_vote, flags);
3206 else
3207 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3208 " bus voting to 0 bandwidth\n",
3209 mmc_hostname(host->mmc), __func__);
3210 spin_unlock_irqrestore(&host->lock, flags);
3211}
3212
3213/*
3214 * This function cancels any scheduled delayed work
3215 * and sets the bus vote based on ios argument.
3216 * If "ios" argument is NULL, bandwidth required is 0 else
3217 * calculate the bandwidth based on ios parameters.
3218 */
3219static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3220 struct msmsdcc_host *host,
3221 struct mmc_ios *ios)
3222{
3223 unsigned long flags;
3224 unsigned int bw;
3225 int vote;
3226
3227 if (!host->msm_bus_vote.client_handle)
3228 return;
3229
3230 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3231
3232 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3233 spin_lock_irqsave(&host->lock, flags);
3234 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3235 msmsdcc_msm_bus_set_vote(host, vote, flags);
3236 spin_unlock_irqrestore(&host->lock, flags);
3237}
3238
3239/* This function queues a work which will set the bandwidth requiement to 0 */
3240static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3241{
3242 unsigned long flags;
3243
3244 if (!host->msm_bus_vote.client_handle)
3245 return;
3246
3247 spin_lock_irqsave(&host->lock, flags);
3248 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3249 queue_delayed_work(system_nrt_wq,
3250 &host->msm_bus_vote.vote_work,
3251 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3252 spin_unlock_irqrestore(&host->lock, flags);
3253}
3254
San Mehat9d2bd732009-09-22 16:44:22 -07003255static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303256msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3257{
3258 struct mmc_host *mmc = host->mmc;
3259
3260 /*
3261 * SDIO_AL clients has different mechanism of handling LPM through
3262 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3263 * part of that. Here, we are interested only in clients like WLAN.
3264 */
3265 if (!(mmc->card && mmc_card_sdio(mmc->card))
3266 || host->plat->is_sdio_al_client)
3267 goto out;
3268
3269 if (!host->sdcc_suspended) {
3270 /*
3271 * When MSM is not in power collapse and we
3272 * are disabling clocks, enable bit 22 in MASK0
3273 * to handle asynchronous SDIO interrupts.
3274 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303275 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303276 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303277 mb();
3278 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303279 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303280 msmsdcc_sync_reg_wr(host);
3281 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303282 goto out;
3283 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3284 /*
3285 * Wakeup MSM only if SDIO function drivers set
3286 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3287 */
3288 goto out;
3289 }
3290
3291 if (enable_wakeup_irq) {
3292 if (!host->plat->sdiowakeup_irq) {
3293 /*
3294 * When there is no gpio line that can be configured
3295 * as wakeup interrupt handle it by configuring
3296 * asynchronous sdio interrupts and DAT1 line.
3297 */
3298 writel_relaxed(MCI_SDIOINTMASK,
3299 host->base + MMCIMASK0);
3300 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303301 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303302 /* configure sdcc core interrupt as wakeup interrupt */
3303 msmsdcc_enable_irq_wake(host);
3304 } else {
3305 /* Let gpio line handle wakeup interrupt */
3306 writel_relaxed(0, host->base + MMCIMASK0);
3307 mb();
3308 if (host->sdio_wakeupirq_disabled) {
3309 host->sdio_wakeupirq_disabled = 0;
3310 /* configure gpio line as wakeup interrupt */
3311 msmsdcc_enable_irq_wake(host);
3312 enable_irq(host->plat->sdiowakeup_irq);
3313 }
3314 }
3315 } else {
3316 if (!host->plat->sdiowakeup_irq) {
3317 /*
3318 * We may not have cleared bit 22 in the interrupt
3319 * handler as the clocks might be off at that time.
3320 */
3321 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303322 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303323 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303324 msmsdcc_disable_irq_wake(host);
3325 } else if (!host->sdio_wakeupirq_disabled) {
3326 disable_irq_nosync(host->plat->sdiowakeup_irq);
3327 msmsdcc_disable_irq_wake(host);
3328 host->sdio_wakeupirq_disabled = 1;
3329 }
3330 }
3331out:
3332 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003333}
3334
3335static void
3336msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3337{
3338 struct msmsdcc_host *host = mmc_priv(mmc);
3339 u32 clk = 0, pwr = 0;
3340 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003341 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003342 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003343
Sahitya Tummala7a892482011-01-18 11:22:49 +05303344
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303345 /*
3346 * Disable SDCC core interrupt until set_ios is completed.
3347 * This avoids any race conditions with interrupt raised
3348 * when turning on/off the clocks. One possible
3349 * scenario is SDIO operational interrupt while the clock
3350 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303351 * host->lock is being released intermittently below.
3352 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303353 */
3354
Asutosh Dasf5298c32012-04-03 14:51:47 +05303355 mutex_lock(&host->clk_mutex);
3356 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003357 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303358 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303359 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303360 host->sdcc_irq_disabled = 1;
3361 }
San Mehatd0719e52009-12-03 10:58:54 -08003362 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003363
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303364 /* Make sure sdcc core irq is synchronized */
3365 synchronize_irq(host->core_irqres->start);
3366
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303367 pwr = msmsdcc_setup_pwr(host, ios);
3368
3369 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003370 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303371 spin_unlock_irqrestore(&host->lock, flags);
3372 rc = msmsdcc_setup_clocks(host, true);
3373 if (rc)
3374 goto out;
3375 spin_lock_irqsave(&host->lock, flags);
3376 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3377 mb();
3378 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003379 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003381 /*
3382 * For DDR50 mode, controller needs clock rate to be
3383 * double than what is required on the SD card CLK pin.
Subhash Jadavani2877d912012-10-09 20:01:56 +05303384 *
3385 * Setting DDR timing mode in controller before setting the
3386 * clock rate will make sure that card don't see the double
3387 * clock rate even for very small duration. Some eMMC
3388 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003389 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303390 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2877d912012-10-09 20:01:56 +05303391 u32 clk;
3392
3393 clk = readl_relaxed(host->base + MMCICLOCK);
3394 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3395 clk |= (3 << 14); /* set DDR timing mode */
3396 writel_relaxed(clk, host->base + MMCICLOCK);
3397 msmsdcc_sync_reg_wr(host);
3398
Subhash Jadavani879856d2013-03-04 16:28:04 +05303399 clock = msmsdcc_get_sup_clk_rate(host, ios->clock * 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 }
3401
3402 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303403 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003404 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303405 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303407 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408 mmc_hostname(mmc), clock);
3409 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303410 host->reg_write_delay =
3411 (1 + ((3 * USEC_PER_SEC) /
3412 (host->clk_rate ? host->clk_rate :
3413 msmsdcc_get_min_sup_clk_rate(host))));
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05303414 spin_unlock_irqrestore(&host->lock, flags);
3415 /*
3416 * Update bus vote incase of frequency change due to
3417 * clock scaling.
3418 */
3419 msmsdcc_msm_bus_cancel_work_and_set_vote(host,
3420 &mmc->ios);
3421 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422 }
3423 /*
3424 * give atleast 2 MCLK cycles delay for clocks
3425 * and SDCC core to stabilize
3426 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303427 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003429 clk |= MCI_CLK_ENABLE;
3430 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003431 if (ios->bus_width == MMC_BUS_WIDTH_8)
3432 clk |= MCI_CLK_WIDEBUS_8;
3433 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3434 clk |= MCI_CLK_WIDEBUS_4;
3435 else
3436 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003437
Subhash Jadavani568907c2013-05-27 16:37:52 +05303438 if (msmsdcc_is_pwrsave(host) && mmc_host_may_gate_card(host->mmc->card))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 host->tuning_needed = 0;
3444 /*
3445 * Select the controller timing mode according
3446 * to current bus speed mode
3447 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303448 if (host->clk_rate > (100 * 1000 * 1000) &&
3449 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3450 ios->timing == MMC_TIMING_MMC_HS200)) {
3451 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452 clk |= (4 << 14);
3453 host->tuning_needed = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003454 } else {
Subhash Jadavani355df542012-10-09 19:06:49 +05303455 if (ios->timing == MMC_TIMING_UHS_DDR50)
3456 clk |= (3 << 14);
3457 else
3458 clk |= (2 << 14); /* feedback clock */
3459
3460 host->tuning_done = false;
3461 if (atomic_read(&host->clks_on)) {
3462 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3463 writel_relaxed((readl_relaxed(host->base +
3464 MCI_DLL_CONFIG) | MCI_DLL_RST),
3465 host->base + MCI_DLL_CONFIG);
3466
3467 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3468 writel_relaxed((readl_relaxed(host->base +
3469 MCI_DLL_CONFIG) | MCI_DLL_PDN),
3470 host->base + MCI_DLL_CONFIG);
3471 }
San Mehat9d2bd732009-09-22 16:44:22 -07003472 }
3473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3475 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 if (host->io_pad_pwr_switch)
3478 clk |= IO_PAD_PWR_SWITCH;
3479
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303480 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303481 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303482 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3483 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303484 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303486 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3487 host->pwr = pwr;
3488 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303489 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003490 }
San Mehat9d2bd732009-09-22 16:44:22 -07003491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303493 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303494 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303495 spin_unlock_irqrestore(&host->lock, flags);
3496 /*
3497 * May get a wake-up interrupt the instant we disable the
3498 * clocks. This would disable the wake-up interrupt.
3499 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303501 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303503
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303504 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303505 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303506 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303507
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303508 /* Let interrupts be disabled if the host is powered off */
3509 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3510 enable_irq(host->core_irqres->start);
3511 host->sdcc_irq_disabled = 0;
3512 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003513 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303514out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303515 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003516}
3517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3519{
3520 struct msmsdcc_host *host = mmc_priv(mmc);
3521 u32 clk;
3522
3523 clk = readl_relaxed(host->base + MMCICLOCK);
3524 pr_debug("Changing to pwr_save=%d", pwrsave);
3525 if (pwrsave && msmsdcc_is_pwrsave(host))
3526 clk |= MCI_CLK_PWRSAVE;
3527 else
3528 clk &= ~MCI_CLK_PWRSAVE;
3529 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303530 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531
3532 return 0;
3533}
3534
3535static int msmsdcc_get_ro(struct mmc_host *mmc)
3536{
3537 int status = -ENOSYS;
3538 struct msmsdcc_host *host = mmc_priv(mmc);
3539
3540 if (host->plat->wpswitch) {
3541 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303542 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003543 status = gpio_request(host->plat->wpswitch_gpio,
3544 "SD_WP_Switch");
3545 if (status) {
3546 pr_err("%s: %s: Failed to request GPIO %d\n",
3547 mmc_hostname(mmc), __func__,
3548 host->plat->wpswitch_gpio);
3549 } else {
3550 status = gpio_direction_input(
3551 host->plat->wpswitch_gpio);
3552 if (!status) {
3553 /*
3554 * Wait for atleast 300ms as debounce
3555 * time for GPIO input to stabilize.
3556 */
3557 msleep(300);
3558 status = gpio_get_value_cansleep(
3559 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303560 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561 }
3562 gpio_free(host->plat->wpswitch_gpio);
3563 }
3564 }
3565
3566 if (status < 0)
3567 status = -ENOSYS;
3568 pr_debug("%s: Card read-only status %d\n", __func__, status);
3569
3570 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003571}
3572
3573static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3574{
3575 struct msmsdcc_host *host = mmc_priv(mmc);
3576 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003577
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303578 /*
3579 * We may come here with clocks turned off in that case don't
3580 * attempt to write into MASK0 register. While turning on the
3581 * clocks mci_irqenable will be written to MASK0 register.
3582 */
San Mehat9d2bd732009-09-22 16:44:22 -07003583
3584 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003585 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303587 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303588 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003589 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303590 mb();
3591 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003592 } else {
3593 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303594 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303595 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003596 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303597 mb();
3598 }
San Mehat9d2bd732009-09-22 16:44:22 -07003599 }
3600 spin_unlock_irqrestore(&host->lock, flags);
3601}
3602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303604static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003605{
subhashj245831e2012-04-30 18:46:17 +05303606 struct device *dev = mmc_dev(host->mmc);
3607
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303608 pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
Subhash Jadavani386ad802012-08-16 18:46:57 +05303609 mmc_hostname(host->mmc), host->sdcc_suspended,
3610 host->pending_resume, host->sdcc_suspending);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303611 pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
subhashj245831e2012-04-30 18:46:17 +05303612 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3613 " request_pending=%d, request=%d\n",
3614 mmc_hostname(host->mmc), dev->power.runtime_status,
3615 atomic_read(&dev->power.usage_count),
3616 dev->power.is_suspended, dev->power.disable_depth,
3617 dev->power.runtime_error, dev->power.request_pending,
3618 dev->power.request);
3619}
3620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003621static int msmsdcc_enable(struct mmc_host *mmc)
3622{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003623 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003625 struct msmsdcc_host *host = mmc_priv(mmc);
3626
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303627 msmsdcc_pm_qos_update_latency(host, 1);
3628
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003629 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303630 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003631
Subhash Jadavani386ad802012-08-16 18:46:57 +05303632 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003633 host->pending_resume = false;
3634 pm_runtime_get_noresume(dev);
3635 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303636 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003637 }
3638
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303639 if (dev->power.runtime_status == RPM_SUSPENDING) {
3640 if (mmc->suspend_task == current) {
3641 pm_runtime_get_noresume(dev);
3642 goto out;
3643 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303644 } else if (dev->power.runtime_status == RPM_RESUMING) {
3645 pm_runtime_get_noresume(dev);
3646 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303647 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003648
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303649 rc = pm_runtime_get_sync(dev);
3650
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303651skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303652 if (rc < 0) {
Subhash Jadavani386ad802012-08-16 18:46:57 +05303653 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3654 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303655 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303656 return rc;
3657 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303658out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303659 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660}
3661
Steve Mucklef132c6c2012-06-06 18:30:57 -07003662static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663{
3664 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303665 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003666
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303667 msmsdcc_pm_qos_update_latency(host, 0);
3668
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303669 if (mmc->card && mmc_card_sdio(mmc->card)) {
3670 rc = 0;
3671 goto out;
3672 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303673
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303674 if (host->plat->disable_runtime_pm)
3675 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676
3677 rc = pm_runtime_put_sync(mmc->parent);
3678
Subhash Jadavani386ad802012-08-16 18:46:57 +05303679 if (rc < 0) {
3680 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3681 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303682 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003683 return rc;
3684 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303685
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303686out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303687 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688}
3689#else
subhashj245831e2012-04-30 18:46:17 +05303690static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3691
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303692static int msmsdcc_enable(struct mmc_host *mmc)
3693{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003694 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303695 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303696 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303697
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303698 msmsdcc_pm_qos_update_latency(host, 1);
3699
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303700 if (mmc->card && mmc_card_sdio(mmc->card)) {
3701 rc = 0;
3702 goto out;
3703 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003704
3705 if (host->sdcc_suspended && host->pending_resume) {
3706 host->pending_resume = false;
3707 rc = msmsdcc_runtime_resume(dev);
3708 goto out;
3709 }
3710
Asutosh Dasf5298c32012-04-03 14:51:47 +05303711 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303712 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303713 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303714
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003715out:
3716 if (rc < 0) {
3717 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3718 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303719 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003720 return rc;
3721 }
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303722 return 0;
3723}
3724
Steve Mucklef132c6c2012-06-06 18:30:57 -07003725static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303726{
3727 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303728 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303729
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303730 msmsdcc_pm_qos_update_latency(host, 0);
3731
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303732 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303733 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303734
Asutosh Dasf5298c32012-04-03 14:51:47 +05303735 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303736 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303737 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303738
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303739 if (rc) {
3740 msmsdcc_pm_qos_update_latency(host, 1);
3741 return rc;
3742 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303743out:
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303744 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303745}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003746#endif
3747
Subhash Jadavani937c7502012-06-01 15:34:46 +05303748static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3749 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750{
3751 struct msmsdcc_host *host = mmc_priv(mmc);
3752 unsigned long flags;
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303753 bool prev_pwrsave, curr_pwrsave;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303754 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003755
Subhash Jadavani937c7502012-06-01 15:34:46 +05303756 switch (ios->signal_voltage) {
3757 case MMC_SIGNAL_VOLTAGE_330:
3758 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3759 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303760 if (!rc)
3761 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303762 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303763 case MMC_SIGNAL_VOLTAGE_180:
3764 break;
3765 case MMC_SIGNAL_VOLTAGE_120:
3766 /*
3767 * For eMMC cards, VDD_IO voltage range must be changed
3768 * only if it operates in HS200 SDR 1.2V mode or in
3769 * DDR 1.2V mode.
3770 */
3771 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303772 if (!rc)
3773 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003774 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303775 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303777 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 goto out;
3779 }
San Mehat9d2bd732009-09-22 16:44:22 -07003780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781 /*
3782 * If we are here means voltage switch from high voltage to
3783 * low voltage is required
3784 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303785 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303786 prev_pwrsave = !!(readl_relaxed(host->base + MMCICLOCK) &
3787 MCI_CLK_PWRSAVE);
3788 curr_pwrsave = prev_pwrsave;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789 /*
3790 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3791 * register until they become all zeros.
3792 */
3793 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303794 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3796 mmc_hostname(mmc), __func__);
3797 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003798 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799
3800 /* Stop SD CLK output. */
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303801 if (!prev_pwrsave) {
3802 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3803 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
3804 msmsdcc_sync_reg_wr(host);
3805 curr_pwrsave = true;
3806 }
San Mehat9d2bd732009-09-22 16:44:22 -07003807 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003808
3809 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303810 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3811 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303813 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303814 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003815 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303817 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818
3819 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3820 usleep_range(5000, 5500);
3821
3822 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303823 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3825 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303826 msmsdcc_sync_reg_wr(host);
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303827 curr_pwrsave = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003828 spin_unlock_irqrestore(&host->lock, flags);
3829
3830 /*
3831 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3832 * don't become all ones within 1 ms then a Voltage Switch
3833 * sequence has failed and a power cycle to the card is required.
3834 * Otherwise Voltage Switch sequence is completed successfully.
3835 */
3836 usleep_range(1000, 1500);
3837
3838 spin_lock_irqsave(&host->lock, flags);
3839 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3840 != (0xF << 1)) {
3841 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3842 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303843 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003844 goto out_unlock;
3845 }
3846
3847out_unlock:
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303848 /* Restore the correct PWRSAVE state */
3849 if (prev_pwrsave ^ curr_pwrsave)
3850 msmsdcc_set_pwrsave(mmc, prev_pwrsave);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003851 spin_unlock_irqrestore(&host->lock, flags);
3852out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303853 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854}
3855
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303856static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003857{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859
3860 /* Program the MCLK value to MCLK_FREQ bit field */
3861 if (host->clk_rate <= 112000000)
3862 mclk_freq = 0;
3863 else if (host->clk_rate <= 125000000)
3864 mclk_freq = 1;
3865 else if (host->clk_rate <= 137000000)
3866 mclk_freq = 2;
3867 else if (host->clk_rate <= 150000000)
3868 mclk_freq = 3;
3869 else if (host->clk_rate <= 162000000)
3870 mclk_freq = 4;
3871 else if (host->clk_rate <= 175000000)
3872 mclk_freq = 5;
3873 else if (host->clk_rate <= 187000000)
3874 mclk_freq = 6;
3875 else if (host->clk_rate <= 200000000)
3876 mclk_freq = 7;
3877
3878 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3879 & ~(7 << 24)) | (mclk_freq << 24)),
3880 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881}
3882
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303883/* Initialize the DLL (Programmable Delay Line ) */
3884static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003886 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303887 unsigned long flags;
3888 u32 wait_cnt;
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303889 bool prev_pwrsave, curr_pwrsave;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303891 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303892 prev_pwrsave = !!(readl_relaxed(host->base + MMCICLOCK) &
3893 MCI_CLK_PWRSAVE);
3894 curr_pwrsave = prev_pwrsave;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 /*
3896 * Make sure that clock is always enabled when DLL
3897 * tuning is in progress. Keeping PWRSAVE ON may
3898 * turn off the clock. So let's disable the PWRSAVE
3899 * here and re-enable it once tuning is completed.
3900 */
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303901 if (prev_pwrsave) {
3902 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3903 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
3904 msmsdcc_sync_reg_wr(host);
3905 curr_pwrsave = false;
3906 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303907
3908 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3909 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3910 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3911
3912 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3913 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3914 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3915
3916 msmsdcc_cm_sdc4_dll_set_freq(host);
3917
3918 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3919 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3920 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3921
3922 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3923 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3924 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3925
3926 /* Set DLL_EN bit to 1. */
3927 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3928 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3929
3930 /* Set CK_OUT_EN bit to 1. */
3931 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3932 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3933
3934 wait_cnt = 50;
3935 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3936 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3937 /* max. wait for 50us sec for LOCK bit to be set */
3938 if (--wait_cnt == 0) {
3939 pr_err("%s: %s: DLL failed to LOCK\n",
3940 mmc_hostname(host->mmc), __func__);
3941 rc = -ETIMEDOUT;
3942 goto out;
3943 }
3944 /* wait for 1us before polling again */
3945 udelay(1);
3946 }
3947
3948out:
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303949 /* Restore the correct PWRSAVE state */
3950 if (prev_pwrsave ^ curr_pwrsave)
3951 msmsdcc_set_pwrsave(host->mmc, prev_pwrsave);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303952 spin_unlock_irqrestore(&host->lock, flags);
3953
3954 return rc;
3955}
3956
3957static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3958 u8 poll)
3959{
3960 int rc = 0;
3961 u32 wait_cnt = 50;
3962 u8 ck_out_en = 0;
3963
3964 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3965 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3966 MCI_CK_OUT_EN);
3967
3968 while (ck_out_en != poll) {
3969 if (--wait_cnt == 0) {
3970 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3971 mmc_hostname(host->mmc), __func__, poll);
3972 rc = -ETIMEDOUT;
3973 goto out;
3974 }
3975 udelay(1);
3976
3977 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3978 MCI_CK_OUT_EN);
3979 }
3980out:
3981 return rc;
3982}
3983
3984/*
3985 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3986 * calibration sequence. This function should be called before
3987 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3988 * commands (CMD17/CMD18).
3989 *
3990 * This function gets called when host spinlock acquired.
3991 */
3992static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3993{
3994 int rc = 0;
3995 u32 config;
3996
3997 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3998 config |= MCI_CDR_EN;
3999 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
4000 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4001
4002 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
4003 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
4004 if (rc)
4005 goto err_out;
4006
4007 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4008 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4009 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4010
4011 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4012 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4013 if (rc)
4014 goto err_out;
4015
4016 goto out;
4017
4018err_out:
4019 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
4020out:
4021 return rc;
4022}
4023
4024static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
4025 u8 phase)
4026{
4027 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05304028 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
4029 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
4030 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304031 unsigned long flags;
4032 u32 config;
4033
4034 spin_lock_irqsave(&host->lock, flags);
4035
4036 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4037 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
4038 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
4039 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4040
4041 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
4042 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
4043 if (rc)
4044 goto err_out;
4045
4046 /*
4047 * Write the selected DLL clock output phase (0 ... 15)
4048 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
4049 */
4050 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
4051 & ~(0xF << 20))
4052 | (grey_coded_phase_table[phase] << 20)),
4053 host->base + MCI_DLL_CONFIG);
4054
4055 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4056 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4057 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4058
4059 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4060 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4061 if (rc)
4062 goto err_out;
4063
4064 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4065 config |= MCI_CDR_EN;
4066 config &= ~MCI_CDR_EXT_EN;
4067 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4068 goto out;
4069
4070err_out:
4071 pr_err("%s: %s: Failed to set DLL phase: %d\n",
4072 mmc_hostname(host->mmc), __func__, phase);
4073out:
4074 spin_unlock_irqrestore(&host->lock, flags);
4075 return rc;
4076}
4077
4078/*
4079 * Find out the greatest range of consecuitive selected
4080 * DLL clock output phases that can be used as sampling
4081 * setting for SD3.0 UHS-I card read operation (in SDR104
4082 * timing mode) or for eMMC4.5 card read operation (in HS200
4083 * timing mode).
4084 * Select the 3/4 of the range and configure the DLL with the
4085 * selected DLL clock output phase.
4086*/
Subhash Jadavani34187042012-03-02 10:59:49 +05304087static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304088 u8 *phase_table, u8 total_phases)
4089{
Subhash Jadavani6159c622012-03-15 19:05:55 +05304090 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05304091 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05304092 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
4093 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304094 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304095 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
4096 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304097
Subhash Jadavani6159c622012-03-15 19:05:55 +05304098 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304099 pr_err("%s: %s: invalid argument: total_phases=%d\n",
4100 mmc_hostname(host->mmc), __func__, total_phases);
4101 return -EINVAL;
4102 }
4103
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304104 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304105 ranges[row_index][col_index] = phase_table[cnt];
4106 phases_per_row[row_index] += 1;
4107 col_index++;
4108
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304109 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304110 continue;
4111 /* check if next phase in phase_table is consecutive or not */
4112 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
4113 row_index++;
4114 col_index = 0;
4115 }
4116 }
4117
Subhash Jadavani6159c622012-03-15 19:05:55 +05304118 if (row_index >= MAX_PHASES)
4119 return -EINVAL;
4120
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304121 /* Check if phase-0 is present in first valid window? */
4122 if (!ranges[0][0]) {
4123 phase_0_found = true;
4124 phase_0_raw_index = 0;
4125 /* Check if cycle exist between 2 valid windows */
4126 for (cnt = 1; cnt <= row_index; cnt++) {
4127 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05304128 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304129 if (ranges[cnt][i] == 15) {
4130 phase_15_found = true;
4131 phase_15_raw_index = cnt;
4132 break;
4133 }
4134 }
4135 }
4136 }
4137 }
4138
4139 /* If 2 valid windows form cycle then merge them as single window */
4140 if (phase_0_found && phase_15_found) {
4141 /* number of phases in raw where phase 0 is present */
4142 u8 phases_0 = phases_per_row[phase_0_raw_index];
4143 /* number of phases in raw where phase 15 is present */
4144 u8 phases_15 = phases_per_row[phase_15_raw_index];
4145
Subhash Jadavani6159c622012-03-15 19:05:55 +05304146 if (phases_0 + phases_15 >= MAX_PHASES)
4147 /*
4148 * If there are more than 1 phase windows then total
4149 * number of phases in both the windows should not be
4150 * more than or equal to MAX_PHASES.
4151 */
4152 return -EINVAL;
4153
4154 /* Merge 2 cyclic windows */
4155 i = phases_15;
4156 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304157 ranges[phase_15_raw_index][i] =
4158 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304159 if (++i >= MAX_PHASES)
4160 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304161 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304162
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304163 phases_per_row[phase_0_raw_index] = 0;
4164 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4165 }
4166
4167 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304168 if (phases_per_row[cnt] > curr_max) {
4169 curr_max = phases_per_row[cnt];
4170 selected_row_index = cnt;
4171 }
4172 }
4173
Subhash Jadavani6159c622012-03-15 19:05:55 +05304174 i = ((curr_max * 3) / 4);
4175 if (i)
4176 i--;
4177
Subhash Jadavani34187042012-03-02 10:59:49 +05304178 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304179
Subhash Jadavani6159c622012-03-15 19:05:55 +05304180 if (ret >= MAX_PHASES) {
4181 ret = -EINVAL;
4182 pr_err("%s: %s: invalid phase selected=%d\n",
4183 mmc_hostname(host->mmc), __func__, ret);
4184 }
4185
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304186 return ret;
4187}
4188
Girish K Sa3f41692012-02-29 12:00:09 +05304189static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304190{
4191 int rc = 0;
4192 struct msmsdcc_host *host = mmc_priv(mmc);
4193 unsigned long flags;
4194 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304195 const u32 *tuning_block_pattern = tuning_block_64;
4196 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304197 bool is_tuning_all_phases;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304198
4199 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4200
4201 /* Tuning is only required for SDR104 modes */
4202 if (!host->tuning_needed) {
4203 rc = 0;
4204 goto exit;
4205 }
4206
4207 spin_lock_irqsave(&host->lock, flags);
4208 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304209 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304210 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4211
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304212 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304213 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4214 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4215 tuning_block_pattern = tuning_block_128;
4216 size = sizeof(tuning_block_128);
4217 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304218 spin_unlock_irqrestore(&host->lock, flags);
4219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220 /* first of all reset the tuning block */
4221 rc = msmsdcc_init_cm_sdc4_dll(host);
4222 if (rc)
4223 goto out;
4224
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304225 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 if (!data_buf) {
4227 rc = -ENOMEM;
4228 goto out;
4229 }
4230
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304231 is_tuning_all_phases = !(host->mmc->card &&
4232 (host->saved_tuning_phase != INVALID_TUNING_PHASE));
4233retry:
4234 if (is_tuning_all_phases)
4235 phase = 0; /* start from phase 0 during init */
4236 else
4237 phase = (u8)host->saved_tuning_phase;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 do {
4239 struct mmc_command cmd = {0};
4240 struct mmc_data data = {0};
4241 struct mmc_request mrq = {
4242 .cmd = &cmd,
4243 .data = &data
4244 };
4245 struct scatterlist sg;
4246
4247 /* set the phase in delay line hw block */
4248 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4249 if (rc)
4250 goto kfree;
4251
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304252 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4254
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304255 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004256 data.blocks = 1;
4257 data.flags = MMC_DATA_READ;
4258 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4259
4260 data.sg = &sg;
4261 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304262 sg_init_one(&sg, data_buf, size);
4263 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004264 mmc_wait_for_req(mmc, &mrq);
4265
4266 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304267 !memcmp(data_buf, tuning_block_pattern, size)) {
4268 /* tuning is successful at this tuning point */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304269 if (!is_tuning_all_phases)
4270 goto kfree;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004271 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304272 pr_debug("%s: %s: found good phase = %d\n",
4273 mmc_hostname(mmc), __func__, phase);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304274 } else if (!is_tuning_all_phases) {
4275 pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
4276 mmc_hostname(mmc), (u32)phase);
4277 is_tuning_all_phases = true;
4278 goto retry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004279 }
4280 } while (++phase < 16);
4281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004282 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304283 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304284 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304285 if (rc < 0)
4286 goto kfree;
4287 else
4288 phase = (u8)rc;
4289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004290 /*
4291 * Finally set the selected phase in delay
4292 * line hw block.
4293 */
4294 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4295 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304296 goto kfree;
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304297 else
4298 host->saved_tuning_phase = phase;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304299 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4300 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004301 } else {
4302 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304303 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304305 msmsdcc_dump_sdcc_state(host);
4306 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308
4309kfree:
4310 kfree(data_buf);
4311out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304312 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304313 host->tuning_in_progress = 0;
Subhash Jadavani355df542012-10-09 19:06:49 +05304314 if (!rc)
4315 host->tuning_done = true;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304316 spin_unlock_irqrestore(&host->lock, flags);
4317exit:
4318 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004319 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004320}
4321
Subhash Jadavanid076af72013-02-17 23:36:03 +02004322/**
4323 * msmsdcc_stop_request - stops ongoing request
4324 * @mmc: MMC host, running the request
4325 *
4326 * Stops currently running request synchronously. All relevant request
4327 * information is cleared.
4328 */
4329int msmsdcc_stop_request(struct mmc_host *mmc)
4330{
4331 struct msmsdcc_host *host = mmc_priv(mmc);
4332 struct mmc_request *mrq;
4333 unsigned long flags;
4334 int rc = 0;
4335
4336 spin_lock_irqsave(&host->lock, flags);
4337 mrq = host->curr.mrq;
4338 if (mrq) {
4339 msmsdcc_reset_and_restore(host);
4340 /*
4341 * Note: We are just taking care of SPS. We may also
4342 * need to think about ADM (and PIO?) later if required.
4343 */
4344 if (host->sps.sg && is_sps_mode(host)) {
4345 if (!mrq->data->host_cookie)
4346 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
4347 host->sps.num_ents, host->sps.dir);
4348 host->sps.sg = NULL;
4349 host->sps.busy = 0;
4350 }
4351
4352 /*
4353 * Clear current request information as current
4354 * request has ended
4355 */
4356 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
4357 del_timer(&host->req_tout_timer);
4358 } else {
4359 rc = -EINVAL;
4360 }
4361 spin_unlock_irqrestore(&host->lock, flags);
4362
4363 return rc;
4364}
4365
4366/**
4367 * msmsdcc_get_xfer_remain - returns number of bytes passed on bus
4368 * @mmc: MMC host, running the request
4369 *
4370 * Returns the number of bytes passed for SPS transfer. 0 - for non-SPS
4371 * transfer.
4372 */
4373unsigned int msmsdcc_get_xfer_remain(struct mmc_host *mmc)
4374{
4375 struct msmsdcc_host *host = mmc_priv(mmc);
4376 u32 data_cnt = 0;
4377
4378 /* Currently, we don't support to stop the non-SPS transfer */
4379 if (host->sps.busy && atomic_read(&host->clks_on))
4380 data_cnt = readl_relaxed(host->base + MMCIDATACNT);
4381
4382 return data_cnt;
4383}
4384
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05304385static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
4386{
4387 int err = 0;
4388 unsigned long rate;
4389 struct msmsdcc_host *host = mmc_priv(mmc);
4390
4391 if (IS_ERR_OR_NULL(host->bus_clk))
4392 goto out;
4393
4394 switch (state) {
4395 case MMC_LOAD_HIGH:
4396 rate = MSMSDCC_BUS_VOTE_MAX_RATE;
4397 break;
4398 case MMC_LOAD_LOW:
4399 rate = MSMSDCC_BUS_VOTE_MIN_RATE;
4400 break;
4401 default:
4402 err = -EINVAL;
4403 goto out;
4404 }
4405
4406 if (rate != host->bus_clk_rate) {
4407 err = clk_set_rate(host->bus_clk, rate);
4408 if (err)
4409 pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
4410 mmc_hostname(mmc), __func__, rate, err);
4411 else
4412 host->bus_clk_rate = rate;
4413 }
4414out:
4415 return err;
4416}
4417
San Mehat9d2bd732009-09-22 16:44:22 -07004418static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004419 .enable = msmsdcc_enable,
4420 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304421 .pre_req = msmsdcc_pre_req,
4422 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004423 .request = msmsdcc_request,
4424 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004425 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004426 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304427 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304428 .execute_tuning = msmsdcc_execute_tuning,
Subhash Jadavanid076af72013-02-17 23:36:03 +02004429 .stop_request = msmsdcc_stop_request,
4430 .get_xfer_remain = msmsdcc_get_xfer_remain,
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05304431 .notify_load = msmsdcc_notify_load,
San Mehat9d2bd732009-09-22 16:44:22 -07004432};
4433
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304434static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4435{
4436 unsigned int gpio_no = host->plat->status_gpio;
4437 int status;
4438
4439 if (!gpio_is_valid(gpio_no))
4440 return;
4441
4442 status = gpio_request(gpio_no, "SD_HW_Detect");
4443 if (status)
4444 pr_err("%s: %s: gpio_request(%d) failed\n",
4445 mmc_hostname(host->mmc), __func__, gpio_no);
4446}
4447
4448static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4449{
4450 if (gpio_is_valid(host->plat->status_gpio))
4451 gpio_free(host->plat->status_gpio);
4452}
4453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004454static unsigned int
4455msmsdcc_slot_status(struct msmsdcc_host *host)
4456{
4457 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004458
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304459 status = gpio_get_value_cansleep(host->plat->status_gpio);
4460 if (host->plat->is_status_gpio_active_low)
4461 status = !status;
4462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004463 return status;
4464}
4465
San Mehat9d2bd732009-09-22 16:44:22 -07004466static void
4467msmsdcc_check_status(unsigned long data)
4468{
4469 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4470 unsigned int status;
4471
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304472 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004473 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004474 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004475 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004476 status = msmsdcc_slot_status(host);
4477
Krishna Konda941604a2012-01-10 17:46:34 -08004478 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004480 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004481 if (host->plat->status)
4482 pr_info("%s: Slot status change detected "
4483 "(%d -> %d)\n",
4484 mmc_hostname(host->mmc),
4485 host->oldstat, status);
4486 else if (host->plat->is_status_gpio_active_low)
4487 pr_info("%s: Slot status change detected "
4488 "(%d -> %d) and the card detect GPIO"
4489 " is ACTIVE_LOW\n",
4490 mmc_hostname(host->mmc),
4491 host->oldstat, status);
4492 else
4493 pr_info("%s: Slot status change detected "
4494 "(%d -> %d) and the card detect GPIO"
4495 " is ACTIVE_HIGH\n",
4496 mmc_hostname(host->mmc),
4497 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004498 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004499 }
4500 host->oldstat = status;
4501 } else {
4502 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004503 }
San Mehat9d2bd732009-09-22 16:44:22 -07004504}
4505
4506static irqreturn_t
4507msmsdcc_platform_status_irq(int irq, void *dev_id)
4508{
4509 struct msmsdcc_host *host = dev_id;
4510
Girish K Sa3c76eb2011-10-11 11:44:09 +05304511 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004512 msmsdcc_check_status((unsigned long) host);
4513 return IRQ_HANDLED;
4514}
4515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004516static irqreturn_t
4517msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4518{
4519 struct msmsdcc_host *host = dev_id;
4520
4521 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4522 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304523 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304525 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004526 wake_lock(&host->sdio_wlock);
4527 msmsdcc_disable_irq_wake(host);
4528 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304529 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004530 }
4531 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004532 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304533 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304534 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304535 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004536 }
4537 spin_unlock(&host->lock);
4538
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304539out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 return IRQ_HANDLED;
4541}
4542
San Mehat9d2bd732009-09-22 16:44:22 -07004543static void
4544msmsdcc_status_notify_cb(int card_present, void *dev_id)
4545{
4546 struct msmsdcc_host *host = dev_id;
4547
Girish K Sa3c76eb2011-10-11 11:44:09 +05304548 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004549 card_present);
4550 msmsdcc_check_status((unsigned long) host);
4551}
4552
San Mehat9d2bd732009-09-22 16:44:22 -07004553static int
4554msmsdcc_init_dma(struct msmsdcc_host *host)
4555{
4556 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4557 host->dma.host = host;
4558 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004559 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004560
4561 if (!host->dmares)
4562 return -ENODEV;
4563
4564 host->dma.nc = dma_alloc_coherent(NULL,
4565 sizeof(struct msmsdcc_nc_dmadata),
4566 &host->dma.nc_busaddr,
4567 GFP_KERNEL);
4568 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004569 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004570 return -ENOMEM;
4571 }
4572 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4573 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4574 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4575 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4576 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004577 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004578
4579 return 0;
4580}
4581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004582#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4583/**
4584 * Allocate and Connect a SDCC peripheral's SPS endpoint
4585 *
4586 * This function allocates endpoint context and
4587 * connect it with memory endpoint by calling
4588 * appropriate SPS driver APIs.
4589 *
4590 * Also registers a SPS callback function with
4591 * SPS driver
4592 *
4593 * This function should only be called once typically
4594 * during driver probe.
4595 *
4596 * @host - Pointer to sdcc host structure
4597 * @ep - Pointer to sps endpoint data structure
4598 * @is_produce - 1 means Producer endpoint
4599 * 0 means Consumer endpoint
4600 *
4601 * @return - 0 if successful else negative value.
4602 *
4603 */
4604static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4605 struct msmsdcc_sps_ep_conn_data *ep,
4606 bool is_producer)
4607{
4608 int rc = 0;
4609 struct sps_pipe *sps_pipe_handle;
4610 struct sps_connect *sps_config = &ep->config;
4611 struct sps_register_event *sps_event = &ep->event;
4612
4613 /* Allocate endpoint context */
4614 sps_pipe_handle = sps_alloc_endpoint();
4615 if (!sps_pipe_handle) {
4616 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4617 mmc_hostname(host->mmc), is_producer);
4618 rc = -ENOMEM;
4619 goto out;
4620 }
4621
4622 /* Get default connection configuration for an endpoint */
4623 rc = sps_get_config(sps_pipe_handle, sps_config);
4624 if (rc) {
4625 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4626 " rc=%d", mmc_hostname(host->mmc),
4627 (u32)sps_pipe_handle, rc);
4628 goto get_config_err;
4629 }
4630
4631 /* Modify the default connection configuration */
4632 if (is_producer) {
4633 /*
4634 * For SDCC producer transfer, source should be
4635 * SDCC peripheral where as destination should
4636 * be system memory.
4637 */
4638 sps_config->source = host->sps.bam_handle;
4639 sps_config->destination = SPS_DEV_HANDLE_MEM;
4640 /* Producer pipe will handle this connection */
4641 sps_config->mode = SPS_MODE_SRC;
4642 sps_config->options =
4643 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4644 } else {
4645 /*
4646 * For SDCC consumer transfer, source should be
4647 * system memory where as destination should
4648 * SDCC peripheral
4649 */
4650 sps_config->source = SPS_DEV_HANDLE_MEM;
4651 sps_config->destination = host->sps.bam_handle;
4652 sps_config->mode = SPS_MODE_DEST;
4653 sps_config->options =
4654 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4655 }
4656
4657 /* Producer pipe index */
4658 sps_config->src_pipe_index = host->sps.src_pipe_index;
4659 /* Consumer pipe index */
4660 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4661 /*
4662 * This event thresold value is only significant for BAM-to-BAM
4663 * transfer. It's ignored for BAM-to-System mode transfer.
4664 */
4665 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304666
4667 /* Allocate maximum descriptor fifo size */
4668 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4669 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004670 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4671 sps_config->desc.size,
4672 &sps_config->desc.phys_base,
4673 GFP_KERNEL);
4674
Pratibhasagar V00b94332011-10-18 14:57:27 +05304675 if (!sps_config->desc.base) {
4676 rc = -ENOMEM;
4677 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4678 , mmc_hostname(host->mmc));
4679 goto get_config_err;
4680 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004681 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4682
4683 /* Establish connection between peripheral and memory endpoint */
4684 rc = sps_connect(sps_pipe_handle, sps_config);
4685 if (rc) {
4686 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4687 " rc=%d", mmc_hostname(host->mmc),
4688 (u32)sps_pipe_handle, rc);
4689 goto sps_connect_err;
4690 }
4691
4692 sps_event->mode = SPS_TRIGGER_CALLBACK;
4693 sps_event->options = SPS_O_EOT;
4694 sps_event->callback = msmsdcc_sps_complete_cb;
4695 sps_event->xfer_done = NULL;
4696 sps_event->user = (void *)host;
4697
4698 /* Register callback event for EOT (End of transfer) event. */
4699 rc = sps_register_event(sps_pipe_handle, sps_event);
4700 if (rc) {
4701 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4702 " rc=%d", mmc_hostname(host->mmc),
4703 (u32)sps_pipe_handle, rc);
4704 goto reg_event_err;
4705 }
4706 /* Now save the sps pipe handle */
4707 ep->pipe_handle = sps_pipe_handle;
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004708 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"\
4709 " desc_fifo.phys_base=%pa\n", mmc_hostname(host->mmc),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710 __func__, is_producer ? "READ" : "WRITE",
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004711 (u32)sps_pipe_handle, &sps_config->desc.phys_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004712 goto out;
4713
4714reg_event_err:
4715 sps_disconnect(sps_pipe_handle);
4716sps_connect_err:
4717 dma_free_coherent(mmc_dev(host->mmc),
4718 sps_config->desc.size,
4719 sps_config->desc.base,
4720 sps_config->desc.phys_base);
4721get_config_err:
4722 sps_free_endpoint(sps_pipe_handle);
4723out:
4724 return rc;
4725}
4726
4727/**
4728 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4729 *
4730 * This function disconnect endpoint and deallocates
4731 * endpoint context.
4732 *
4733 * This function should only be called once typically
4734 * during driver remove.
4735 *
4736 * @host - Pointer to sdcc host structure
4737 * @ep - Pointer to sps endpoint data structure
4738 *
4739 */
4740static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4741 struct msmsdcc_sps_ep_conn_data *ep)
4742{
4743 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4744 struct sps_connect *sps_config = &ep->config;
4745 struct sps_register_event *sps_event = &ep->event;
4746
4747 sps_event->xfer_done = NULL;
4748 sps_event->callback = NULL;
4749 sps_register_event(sps_pipe_handle, sps_event);
4750 sps_disconnect(sps_pipe_handle);
4751 dma_free_coherent(mmc_dev(host->mmc),
4752 sps_config->desc.size,
4753 sps_config->desc.base,
4754 sps_config->desc.phys_base);
4755 sps_free_endpoint(sps_pipe_handle);
4756}
4757
4758/**
4759 * Reset SDCC peripheral's SPS endpoint
4760 *
4761 * This function disconnects an endpoint.
4762 *
4763 * This function should be called for reseting
4764 * SPS endpoint when data transfer error is
4765 * encountered during data transfer. This
4766 * can be considered as soft reset to endpoint.
4767 *
4768 * This function should only be called if
4769 * msmsdcc_sps_init() is already called.
4770 *
4771 * @host - Pointer to sdcc host structure
4772 * @ep - Pointer to sps endpoint data structure
4773 *
4774 * @return - 0 if successful else negative value.
4775 */
4776static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4777 struct msmsdcc_sps_ep_conn_data *ep)
4778{
4779 int rc = 0;
4780 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4781
4782 rc = sps_disconnect(sps_pipe_handle);
4783 if (rc) {
4784 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4785 " rc=%d", mmc_hostname(host->mmc), __func__,
4786 (u32)sps_pipe_handle, rc);
4787 goto out;
4788 }
4789 out:
4790 return rc;
4791}
4792
4793/**
4794 * Restore SDCC peripheral's SPS endpoint
4795 *
4796 * This function connects an endpoint.
4797 *
4798 * This function should be called for restoring
4799 * SPS endpoint after data transfer error is
4800 * encountered during data transfer. This
4801 * can be considered as soft reset to endpoint.
4802 *
4803 * This function should only be called if
4804 * msmsdcc_sps_reset_ep() is called before.
4805 *
4806 * @host - Pointer to sdcc host structure
4807 * @ep - Pointer to sps endpoint data structure
4808 *
4809 * @return - 0 if successful else negative value.
4810 */
4811static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4812 struct msmsdcc_sps_ep_conn_data *ep)
4813{
4814 int rc = 0;
4815 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4816 struct sps_connect *sps_config = &ep->config;
4817 struct sps_register_event *sps_event = &ep->event;
4818
4819 /* Establish connection between peripheral and memory endpoint */
4820 rc = sps_connect(sps_pipe_handle, sps_config);
4821 if (rc) {
4822 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4823 " rc=%d", mmc_hostname(host->mmc), __func__,
4824 (u32)sps_pipe_handle, rc);
4825 goto out;
4826 }
4827
4828 /* Register callback event for EOT (End of transfer) event. */
4829 rc = sps_register_event(sps_pipe_handle, sps_event);
4830 if (rc) {
4831 pr_err("%s: %s: sps_register_event() failed!!!"
4832 " pipe_handle=0x%x, rc=%d",
4833 mmc_hostname(host->mmc), __func__,
4834 (u32)sps_pipe_handle, rc);
4835 goto reg_event_err;
4836 }
4837 goto out;
4838
4839reg_event_err:
4840 sps_disconnect(sps_pipe_handle);
4841out:
4842 return rc;
4843}
4844
4845/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004846 * Handle BAM device's global error condition
4847 *
4848 * This is an error handler for the SDCC bam device
4849 *
4850 * This function is registered as a callback with SPS-BAM
4851 * driver and will called in case there are an errors for
4852 * the SDCC BAM deivce. Any error conditions in the BAM
4853 * device are global and will be result in this function
4854 * being called once per device.
4855 *
4856 * This function will be called from the sps driver's
4857 * interrupt context.
4858 *
4859 * @sps_cb_case - indicates what error it is
4860 * @user - Pointer to sdcc host structure
4861 */
4862static void
4863msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4864{
4865 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4866 struct mmc_request *mrq;
4867 unsigned long flags;
4868 int32_t error = 0;
4869
4870 BUG_ON(!host);
4871 BUG_ON(!is_sps_mode(host));
4872
4873 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004874 /* Reset all endpoints along with resetting bam. */
4875 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004876
4877 pr_err("%s: BAM Global ERROR IRQ happened\n",
4878 mmc_hostname(host->mmc));
4879 error = EAGAIN;
4880 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4881 /**
4882 * This means that there was an AHB access error and
4883 * the address we are trying to read/write is something
4884 * we dont have priviliges to do so.
4885 */
4886 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4887 mmc_hostname(host->mmc));
4888 error = EACCES;
4889 } else {
4890 /**
4891 * This should not have happened ideally. If this happens
4892 * there is some seriously wrong.
4893 */
4894 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4895 mmc_hostname(host->mmc), (u32) sps_cb_case);
4896 error = EIO;
4897 }
4898
4899 spin_lock_irqsave(&host->lock, flags);
4900
4901 mrq = host->curr.mrq;
4902
4903 if (mrq && mrq->cmd) {
4904 msmsdcc_dump_sdcc_state(host);
4905
4906 if (!mrq->cmd->error)
4907 mrq->cmd->error = -error;
4908 if (host->curr.data) {
4909 if (mrq->data && !mrq->data->error)
4910 mrq->data->error = -error;
4911 host->curr.data_xfered = 0;
4912 if (host->sps.sg && is_sps_mode(host)) {
4913 /* Stop current SPS transfer */
4914 msmsdcc_sps_exit_curr_xfer(host);
4915 } else {
4916 /* this condition should not have happened */
4917 pr_err("%s: something is seriously wrong. "\
4918 "Funtion: %s, line: %d\n",
4919 mmc_hostname(host->mmc),
4920 __func__, __LINE__);
4921 }
4922 } else {
4923 /* this condition should not have happened */
4924 pr_err("%s: something is seriously wrong. Funtion: "\
4925 "%s, line: %d\n", mmc_hostname(host->mmc),
4926 __func__, __LINE__);
4927 }
4928 }
4929 spin_unlock_irqrestore(&host->lock, flags);
4930}
4931
4932/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004933 * Initialize SPS HW connected with SDCC core
4934 *
4935 * This function register BAM HW resources with
4936 * SPS driver and then initialize 2 SPS endpoints
4937 *
4938 * This function should only be called once typically
4939 * during driver probe.
4940 *
4941 * @host - Pointer to sdcc host structure
4942 *
4943 * @return - 0 if successful else negative value.
4944 *
4945 */
4946static int msmsdcc_sps_init(struct msmsdcc_host *host)
4947{
4948 int rc = 0;
4949 struct sps_bam_props bam = {0};
4950
4951 host->bam_base = ioremap(host->bam_memres->start,
4952 resource_size(host->bam_memres));
4953 if (!host->bam_base) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004954 pr_err("%s: BAM ioremap() failed!!! resource: %pr\n",
4955 mmc_hostname(host->mmc), host->bam_memres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004956 rc = -ENOMEM;
4957 goto out;
4958 }
4959
4960 bam.phys_addr = host->bam_memres->start;
4961 bam.virt_addr = host->bam_base;
4962 /*
4963 * This event thresold value is only significant for BAM-to-BAM
4964 * transfer. It's ignored for BAM-to-System mode transfer.
4965 */
4966 bam.event_threshold = 0x10; /* Pipe event threshold */
4967 /*
4968 * This threshold controls when the BAM publish
4969 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304970 * SPS HW will be used for data transfer size even
4971 * less than SDCC FIFO size. So let's set BAM summing
4972 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004973 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304974 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004975 /* SPS driver wll handle the SDCC BAM IRQ */
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004976 bam.irq = host->bam_irqres->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07004978 bam.callback = msmsdcc_sps_bam_global_irq_cb;
4979 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004980
Krishna Kondacdff0902013-04-09 17:57:22 -07004981 /* bam reset messages will be limited to 5 times */
4982 bam.constrained_logging = true;
4983 bam.logging_number = 5;
4984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004985 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4986 (u32)bam.phys_addr);
4987 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4988 (u32)bam.virt_addr);
4989
4990 /* Register SDCC Peripheral BAM device to SPS driver */
4991 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4992 if (rc) {
4993 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4994 mmc_hostname(host->mmc), rc);
4995 goto reg_bam_err;
4996 }
4997 pr_info("%s: BAM device registered. bam_handle=0x%x",
4998 mmc_hostname(host->mmc), host->sps.bam_handle);
4999
5000 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
5001 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
5002
5003 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
5004 SPS_PROD_PERIPHERAL);
5005 if (rc)
5006 goto sps_reset_err;
5007 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
5008 SPS_CONS_PERIPHERAL);
5009 if (rc)
5010 goto cons_conn_err;
5011
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005012 pr_info("%s: Qualcomm MSM SDCC-BAM at %pr %pr\n",
5013 mmc_hostname(host->mmc), host->bam_memres, host->bam_irqres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005014 goto out;
5015
5016cons_conn_err:
5017 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5018sps_reset_err:
5019 sps_deregister_bam_device(host->sps.bam_handle);
5020reg_bam_err:
5021 iounmap(host->bam_base);
5022out:
5023 return rc;
5024}
5025
5026/**
5027 * De-initialize SPS HW connected with SDCC core
5028 *
5029 * This function deinitialize SPS endpoints and then
5030 * deregisters BAM resources from SPS driver.
5031 *
5032 * This function should only be called once typically
5033 * during driver remove.
5034 *
5035 * @host - Pointer to sdcc host structure
5036 *
5037 */
5038static void msmsdcc_sps_exit(struct msmsdcc_host *host)
5039{
5040 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
5041 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5042 sps_deregister_bam_device(host->sps.bam_handle);
5043 iounmap(host->bam_base);
5044}
5045#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
5046
5047static ssize_t
5048show_polling(struct device *dev, struct device_attribute *attr, char *buf)
5049{
5050 struct mmc_host *mmc = dev_get_drvdata(dev);
5051 struct msmsdcc_host *host = mmc_priv(mmc);
5052 int poll;
5053 unsigned long flags;
5054
5055 spin_lock_irqsave(&host->lock, flags);
5056 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
5057 spin_unlock_irqrestore(&host->lock, flags);
5058
5059 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
5060}
5061
5062static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305063store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005064 const char *buf, size_t count)
5065{
5066 struct mmc_host *mmc = dev_get_drvdata(dev);
5067 struct msmsdcc_host *host = mmc_priv(mmc);
5068 int value;
5069 unsigned long flags;
5070
5071 sscanf(buf, "%d", &value);
5072
5073 spin_lock_irqsave(&host->lock, flags);
5074 if (value) {
5075 mmc->caps |= MMC_CAP_NEEDS_POLL;
5076 mmc_detect_change(host->mmc, 0);
5077 } else {
5078 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5079 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005080 spin_unlock_irqrestore(&host->lock, flags);
5081 return count;
5082}
5083
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305084static ssize_t
5085show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
5086 char *buf)
5087{
5088 struct mmc_host *mmc = dev_get_drvdata(dev);
5089 struct msmsdcc_host *host = mmc_priv(mmc);
5090
5091 return snprintf(buf, PAGE_SIZE, "%u\n",
5092 host->msm_bus_vote.is_max_bw_needed);
5093}
5094
5095static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305096store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305097 const char *buf, size_t count)
5098{
5099 struct mmc_host *mmc = dev_get_drvdata(dev);
5100 struct msmsdcc_host *host = mmc_priv(mmc);
5101 uint32_t value;
5102 unsigned long flags;
5103
5104 if (!kstrtou32(buf, 0, &value)) {
5105 spin_lock_irqsave(&host->lock, flags);
5106 host->msm_bus_vote.is_max_bw_needed = !!value;
5107 spin_unlock_irqrestore(&host->lock, flags);
5108 }
5109
5110 return count;
5111}
5112
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305113static ssize_t
5114show_idle_timeout(struct device *dev, struct device_attribute *attr,
5115 char *buf)
5116{
5117 struct mmc_host *mmc = dev_get_drvdata(dev);
5118 struct msmsdcc_host *host = mmc_priv(mmc);
5119
5120 return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05305121 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305122}
5123
5124static ssize_t
5125store_idle_timeout(struct device *dev, struct device_attribute *attr,
5126 const char *buf, size_t count)
5127{
5128 struct mmc_host *mmc = dev_get_drvdata(dev);
5129 struct msmsdcc_host *host = mmc_priv(mmc);
5130 unsigned int long flags;
5131 int timeout; /* in secs */
5132
5133 if (!kstrtou32(buf, 0, &timeout)
5134 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
5135 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05305136 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305137 spin_unlock_irqrestore(&host->lock, flags);
5138 }
5139 return count;
5140}
5141
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305142static inline void set_auto_cmd_setting(struct device *dev,
5143 const char *buf,
5144 bool is_cmd19)
5145{
5146 struct mmc_host *mmc = dev_get_drvdata(dev);
5147 struct msmsdcc_host *host = mmc_priv(mmc);
5148 unsigned int long flags;
5149 int temp;
5150
5151 if (!kstrtou32(buf, 0, &temp)) {
5152 spin_lock_irqsave(&host->lock, flags);
5153 if (is_cmd19)
5154 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305155 else
5156 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305157 spin_unlock_irqrestore(&host->lock, flags);
5158 }
5159}
5160
5161static ssize_t
5162show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5163 char *buf)
5164{
5165 struct mmc_host *mmc = dev_get_drvdata(dev);
5166 struct msmsdcc_host *host = mmc_priv(mmc);
5167
5168 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
5169}
5170
5171static ssize_t
5172store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5173 const char *buf, size_t count)
5174{
5175 set_auto_cmd_setting(dev, buf, true);
5176
5177 return count;
5178}
5179
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305180static ssize_t
5181show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5182 char *buf)
5183{
5184 struct mmc_host *mmc = dev_get_drvdata(dev);
5185 struct msmsdcc_host *host = mmc_priv(mmc);
5186
5187 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5188}
5189
5190static ssize_t
5191store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5192 const char *buf, size_t count)
5193{
5194 set_auto_cmd_setting(dev, buf, false);
5195
5196 return count;
5197}
5198
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305199static void msmsdcc_print_regs(const char *name, void __iomem *base,
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005200 resource_size_t phys_base,
5201 unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305202{
5203 unsigned int i;
5204
5205 if (!base)
5206 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305207
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005208 pr_err("===== %s: Register Dumps @phys_base=%pa, @virt_base=0x%x"\
5209 " =====\n", name, &phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305210 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305211 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305212 (u32)readl_relaxed(base + i*4),
5213 (u32)readl_relaxed(base + ((i+1)*4)),
5214 (u32)readl_relaxed(base + ((i+2)*4)),
5215 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305216 }
5217}
5218
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305219/*
5220 * This function prints the testbus debug output for all the
5221 * available SDCC controller test bus.
5222 *
5223 * Note: This function should only be called if the SDCC is clocked.
5224 */
5225static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
5226{
5227 int testbus_num;
5228
5229 if (!is_testbus_debug(host))
5230 return;
5231
5232 pr_err("== SDCC Test Bus Debug ==");
5233 for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
5234 writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
5235 | MCI_TESTBUS_ENA),
5236 host->base + MCI_TESTBUS_CONFIG);
5237 pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
5238 (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
5239 }
5240 /* Disable the test bus output */
5241 writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
5242}
5243
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305244static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5245{
5246 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305247 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305248 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305249 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305250 mmc_hostname(host->mmc),
5251 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305252 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305253 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305254 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5255
5256 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305257 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305258 msmsdcc_print_regs("SDCC-CORE", host->base,
5259 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305260 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5261 mmc_hostname(host->mmc),
5262 readl_relaxed(host->base + MCI_TEST_INPUT));
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305263 msmsdcc_print_testbus_info(host);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305264 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305265
5266 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305267 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305268 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305269 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305270 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305271 mmc_hostname(host->mmc), host->dma.busy,
5272 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305273 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305274 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305275 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5276 host->dml_memres->start,
5277 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305278 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305279 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305280 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305281
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305282 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305283 mmc_hostname(host->mmc), host->curr.xfer_size,
5284 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305285 }
5286
Krishna Konda3ca90f02012-08-29 16:29:21 -07005287 if (host->sps.reset_bam)
5288 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5289 mmc_hostname(host->mmc), host->sps.reset_bam);
5290
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305291 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305292 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5293 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5294 host->curr.got_dataend, host->prog_enable,
5295 host->curr.wait_for_auto_prog_done,
5296 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305297 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305298}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005300static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5301{
5302 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5303 struct mmc_request *mrq;
5304 unsigned long flags;
5305
5306 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005307 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005308 pr_info("%s: %s: dummy CMD52 timeout\n",
5309 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005310 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005311 }
5312
5313 mrq = host->curr.mrq;
5314
5315 if (mrq && mrq->cmd) {
Subhash Jadavani6ec6b7c2013-06-27 18:06:50 +05305316 if (!mrq->cmd->ignore_timeout) {
Subhash Jadavani926a9cb2012-12-15 22:05:54 +05305317 pr_info("%s: CMD%d: Request timeout\n",
5318 mmc_hostname(host->mmc), mrq->cmd->opcode);
5319 msmsdcc_dump_sdcc_state(host);
5320 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005322 if (!mrq->cmd->error)
5323 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305324 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005325 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005326 if (mrq->data && !mrq->data->error)
5327 mrq->data->error = -ETIMEDOUT;
5328 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305329 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005330 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305331 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005332 /* Stop current SPS transfer */
5333 msmsdcc_sps_exit_curr_xfer(host);
5334 } else {
Sujit Reddy Thumma0facf172013-06-20 14:11:38 +05305335 msmsdcc_clear_pio_irq_mask(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005336 msmsdcc_reset_and_restore(host);
5337 msmsdcc_stop_data(host);
5338 if (mrq->data && mrq->data->stop)
5339 msmsdcc_start_command(host,
5340 mrq->data->stop, 0);
5341 else
5342 msmsdcc_request_end(host, mrq);
5343 }
5344 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305345 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305346 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005347 msmsdcc_reset_and_restore(host);
5348 msmsdcc_request_end(host, mrq);
5349 }
5350 }
5351 spin_unlock_irqrestore(&host->lock, flags);
5352}
5353
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305354/*
5355 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5356 *
5357 * @dev: device node from which the property value is to be read.
5358 * @prop_name: name of the property to be searched.
5359 * @out_array: filled array returned to caller
5360 * @len: filled array size returned to caller
5361 * @size: expected size of the array
5362 *
5363 * If expected "size" doesn't match with "len" an error is returned. If
5364 * expected size is zero, the length of actual array is returned provided
5365 * return value is zero.
5366 *
5367 * RETURNS:
5368 * zero on success, negative error if failed.
5369 */
5370static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5371 u32 **out_array, int *len, int size)
5372{
5373 int ret = 0;
5374 u32 *array = NULL;
5375 struct device_node *np = dev->of_node;
5376
5377 if (of_get_property(np, prop_name, len)) {
5378 size_t sz;
5379 sz = *len = *len / sizeof(*array);
5380
5381 if (sz > 0 && !(size > 0 && (sz != size))) {
5382 array = devm_kzalloc(dev, sz * sizeof(*array),
5383 GFP_KERNEL);
5384 if (!array) {
5385 dev_err(dev, "%s: no memory\n", prop_name);
5386 ret = -ENOMEM;
5387 goto out;
5388 }
5389
5390 ret = of_property_read_u32_array(np, prop_name,
5391 array, sz);
5392 if (ret < 0) {
5393 dev_err(dev, "%s: error reading array %d\n",
5394 prop_name, ret);
5395 goto out;
5396 }
5397 } else {
5398 dev_err(dev, "%s invalid size\n", prop_name);
5399 ret = -EINVAL;
5400 goto out;
5401 }
5402 } else {
5403 dev_err(dev, "%s not specified\n", prop_name);
5404 ret = -EINVAL;
5405 goto out;
5406 }
5407 *out_array = array;
5408out:
5409 if (ret)
5410 *len = 0;
5411 return ret;
5412}
5413
5414static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5415 struct msm_mmc_pad_pull_data **pad_pull_data)
5416{
5417 int ret = 0, base = 0, len, i;
5418 u32 *tmp;
5419 struct msm_mmc_pad_pull_data *pull_data;
5420 struct msm_mmc_pad_pull *pull;
5421
5422 switch (id) {
5423 case 1:
5424 base = TLMM_PULL_SDC1_CLK;
5425 break;
5426 case 2:
5427 base = TLMM_PULL_SDC2_CLK;
5428 break;
5429 case 3:
5430 base = TLMM_PULL_SDC3_CLK;
5431 break;
5432 case 4:
5433 base = TLMM_PULL_SDC4_CLK;
5434 break;
5435 default:
5436 dev_err(dev, "%s: Invalid slot id\n", __func__);
5437 ret = -EINVAL;
5438 goto err;
5439 }
5440
5441 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5442 GFP_KERNEL);
5443 if (!pull_data) {
5444 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5445 ret = -ENOMEM;
5446 goto err;
5447 }
5448 pull_data->size = 3; /* array size for clk, cmd, data */
5449
5450 /* Allocate on, off configs for clk, cmd, data */
5451 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5452 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5453 if (!pull) {
5454 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5455 ret = -ENOMEM;
5456 goto err;
5457 }
5458 pull_data->on = pull;
5459 pull_data->off = pull + pull_data->size;
5460
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005461 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305462 &tmp, &len, pull_data->size);
5463 if (!ret) {
5464 for (i = 0; i < len; i++) {
5465 pull_data->on[i].no = base + i;
5466 pull_data->on[i].val = tmp[i];
5467 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5468 i, pull_data->on[i].val);
5469 }
5470 } else {
5471 goto err;
5472 }
5473
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005474 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305475 &tmp, &len, pull_data->size);
5476 if (!ret) {
5477 for (i = 0; i < len; i++) {
5478 pull_data->off[i].no = base + i;
5479 pull_data->off[i].val = tmp[i];
5480 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5481 i, pull_data->off[i].val);
5482 }
5483 } else {
5484 goto err;
5485 }
5486
5487 *pad_pull_data = pull_data;
5488err:
5489 return ret;
5490}
5491
5492static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5493 struct msm_mmc_pad_drv_data **pad_drv_data)
5494{
5495 int ret = 0, base = 0, len, i;
5496 u32 *tmp;
5497 struct msm_mmc_pad_drv_data *drv_data;
5498 struct msm_mmc_pad_drv *drv;
5499
5500 switch (id) {
5501 case 1:
5502 base = TLMM_HDRV_SDC1_CLK;
5503 break;
5504 case 2:
5505 base = TLMM_HDRV_SDC2_CLK;
5506 break;
5507 case 3:
5508 base = TLMM_HDRV_SDC3_CLK;
5509 break;
5510 case 4:
5511 base = TLMM_HDRV_SDC4_CLK;
5512 break;
5513 default:
5514 dev_err(dev, "%s: Invalid slot id\n", __func__);
5515 ret = -EINVAL;
5516 goto err;
5517 }
5518
5519 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5520 GFP_KERNEL);
5521 if (!drv_data) {
5522 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5523 ret = -ENOMEM;
5524 goto err;
5525 }
5526 drv_data->size = 3; /* array size for clk, cmd, data */
5527
5528 /* Allocate on, off configs for clk, cmd, data */
5529 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5530 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5531 if (!drv) {
5532 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5533 ret = -ENOMEM;
5534 goto err;
5535 }
5536 drv_data->on = drv;
5537 drv_data->off = drv + drv_data->size;
5538
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005539 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305540 &tmp, &len, drv_data->size);
5541 if (!ret) {
5542 for (i = 0; i < len; i++) {
5543 drv_data->on[i].no = base + i;
5544 drv_data->on[i].val = tmp[i];
5545 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5546 i, drv_data->on[i].val);
5547 }
5548 } else {
5549 goto err;
5550 }
5551
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005552 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305553 &tmp, &len, drv_data->size);
5554 if (!ret) {
5555 for (i = 0; i < len; i++) {
5556 drv_data->off[i].no = base + i;
5557 drv_data->off[i].val = tmp[i];
5558 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5559 i, drv_data->off[i].val);
5560 }
5561 } else {
5562 goto err;
5563 }
5564
5565 *pad_drv_data = drv_data;
5566err:
5567 return ret;
5568}
5569
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305570static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5571 struct mmc_platform_data *pdata)
5572{
5573 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5574 struct device_node *np = dev->of_node;
5575
5576 pdata->status_gpio = of_get_named_gpio_flags(np,
5577 "cd-gpios", 0, &flags);
5578 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005579 struct platform_device *pdev = container_of(dev,
5580 struct platform_device, dev);
5581 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305582 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5583 }
5584
5585 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5586 "wp-gpios", 0, &flags);
5587 if (gpio_is_valid(pdata->wpswitch_gpio))
5588 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5589}
5590
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305591static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5592 struct mmc_platform_data *pdata)
5593{
5594 int ret = 0, id = 0, cnt, i;
5595 struct msm_mmc_pin_data *pin_data;
5596 struct device_node *np = dev->of_node;
5597
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305598 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5599
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305600 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5601 if (!pin_data) {
5602 dev_err(dev, "No memory for pin_data\n");
5603 ret = -ENOMEM;
5604 goto err;
5605 }
5606
5607 cnt = of_gpio_count(np);
5608 if (cnt > 0) {
5609 pin_data->is_gpio = true;
5610
5611 pin_data->gpio_data = devm_kzalloc(dev,
5612 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5613 if (!pin_data->gpio_data) {
5614 dev_err(dev, "No memory for gpio_data\n");
5615 ret = -ENOMEM;
5616 goto err;
5617 }
5618 pin_data->gpio_data->size = cnt;
5619 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5620 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5621 if (!pin_data->gpio_data->gpio) {
5622 dev_err(dev, "No memory for gpio\n");
5623 ret = -ENOMEM;
5624 goto err;
5625 }
5626
5627 for (i = 0; i < cnt; i++) {
5628 const char *name = NULL;
5629 char result[32];
5630 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5631 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005632 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305633
5634 snprintf(result, 32, "%s-%s",
5635 dev_name(dev), name ? name : "?");
5636 pin_data->gpio_data->gpio[i].name = result;
5637 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5638 pin_data->gpio_data->gpio[i].name,
5639 pin_data->gpio_data->gpio[i].no);
5640 }
5641 } else {
5642 pin_data->pad_data = devm_kzalloc(dev,
5643 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5644 if (!pin_data->pad_data) {
5645 dev_err(dev, "No memory for pin_data->pad_data\n");
5646 ret = -ENOMEM;
5647 goto err;
5648 }
5649
5650 of_property_read_u32(np, "cell-index", &id);
5651
5652 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5653 &pin_data->pad_data->pull);
5654 if (ret)
5655 goto err;
5656 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5657 &pin_data->pad_data->drv);
5658 if (ret)
5659 goto err;
5660 }
5661
5662 pdata->pin_data = pin_data;
5663err:
5664 if (ret)
5665 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5666 return ret;
5667}
5668
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305669#define MAX_PROP_SIZE 32
5670static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5671 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5672{
5673 int len, ret = 0;
5674 const __be32 *prop;
5675 char prop_name[MAX_PROP_SIZE];
5676 struct msm_mmc_reg_data *vreg;
5677 struct device_node *np = dev->of_node;
5678
5679 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5680 if (of_parse_phandle(np, prop_name, 0)) {
5681 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5682 if (!vreg) {
5683 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5684 ret = -ENOMEM;
5685 goto err;
5686 }
5687
5688 vreg->name = vreg_name;
5689
5690 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005691 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305692 if (of_get_property(np, prop_name, NULL))
5693 vreg->always_on = true;
5694
5695 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005696 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305697 if (of_get_property(np, prop_name, NULL))
5698 vreg->lpm_sup = true;
5699
5700 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005701 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305702 prop = of_get_property(np, prop_name, &len);
5703 if (!prop || (len != (2 * sizeof(__be32)))) {
5704 dev_warn(dev, "%s %s property\n",
5705 prop ? "invalid format" : "no", prop_name);
5706 } else {
5707 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5708 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5709 }
5710
5711 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005712 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305713 prop = of_get_property(np, prop_name, &len);
5714 if (!prop || (len != (2 * sizeof(__be32)))) {
5715 dev_warn(dev, "%s %s property\n",
5716 prop ? "invalid format" : "no", prop_name);
5717 } else {
5718 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5719 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5720 }
5721
5722 *vreg_data = vreg;
5723 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5724 vreg->name, vreg->always_on ? "always_on," : "",
5725 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5726 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5727 }
5728
5729err:
5730 return ret;
5731}
5732
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305733static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5734{
5735 int i, ret;
5736 struct mmc_platform_data *pdata;
5737 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305738 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005739 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305740 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305741
5742 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5743 if (!pdata) {
5744 dev_err(dev, "could not allocate memory for platform data\n");
5745 goto err;
5746 }
5747
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005748 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305749 if (bus_width == 8) {
5750 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5751 } else if (bus_width == 4) {
5752 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5753 } else {
5754 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5755 pdata->mmc_bus_width = 0;
5756 }
5757
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005758 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305759 &sup_voltages, &sup_volt_len, 0);
5760 if (!ret) {
5761 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305762 u32 mask;
5763
5764 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5765 sup_voltages[i + 1]);
5766 if (!mask)
5767 dev_err(dev, "Invalide voltage range %d\n", i);
5768 pdata->ocr_mask |= mask;
5769 }
5770 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305771 }
5772
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005773 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305774 &clk_table, &clk_table_len, 0);
5775 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305776 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305777 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305778 }
5779
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305780 pdata->vreg_data = devm_kzalloc(dev,
5781 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5782 if (!pdata->vreg_data) {
5783 dev_err(dev, "could not allocate memory for vreg_data\n");
5784 goto err;
5785 }
5786
5787 if (msmsdcc_dt_parse_vreg_info(dev,
5788 &pdata->vreg_data->vdd_data, "vdd"))
5789 goto err;
5790
5791 if (msmsdcc_dt_parse_vreg_info(dev,
5792 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5793 goto err;
5794
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305795 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5796 goto err;
5797
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005798 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305799
5800 for (i = 0; i < len; i++) {
5801 const char *name = NULL;
5802
5803 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005804 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305805 if (!name)
5806 continue;
5807
5808 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5809 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5810 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5811 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5812 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5813 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5814 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5815 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5816 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5817 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5818 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5819 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5820 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5821 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5822 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5823 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5824 | MMC_CAP_UHS_DDR50;
5825 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5826 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5827 | MMC_CAP_UHS_DDR50;
5828 }
5829
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005830 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305831 if (current_limit == 800)
5832 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5833 else if (current_limit == 600)
5834 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5835 else if (current_limit == 400)
5836 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5837 else if (current_limit == 200)
5838 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5839
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005840 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305841 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005842 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305843 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005844 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305845 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305846 of_property_read_u32(np, "qcom,dat1-mpm-int",
5847 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305848
5849 return pdata;
5850err:
5851 return NULL;
5852}
5853
San Mehat9d2bd732009-09-22 16:44:22 -07005854static int
5855msmsdcc_probe(struct platform_device *pdev)
5856{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305857 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005858 struct msmsdcc_host *host;
5859 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005860 unsigned long flags;
5861 struct resource *core_irqres = NULL;
5862 struct resource *bam_irqres = NULL;
5863 struct resource *core_memres = NULL;
5864 struct resource *dml_memres = NULL;
5865 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005866 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005867 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305868 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005869
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305870 if (pdev->dev.of_node) {
5871 plat = msmsdcc_populate_pdata(&pdev->dev);
5872 of_property_read_u32((&pdev->dev)->of_node,
5873 "cell-index", &pdev->id);
5874 } else {
5875 plat = pdev->dev.platform_data;
5876 }
San Mehat9d2bd732009-09-22 16:44:22 -07005877
5878 /* must have platform data */
5879 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005880 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005881 ret = -EINVAL;
5882 goto out;
5883 }
5884
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -08005885 if (disable_slots & (1 << (pdev->id - 1))) {
5886 pr_info("%s: Slot %d disabled\n", __func__, pdev->id);
5887 return -ENODEV;
5888 }
5889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005890 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005891 return -EINVAL;
5892
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305893 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5894 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5895 return -EINVAL;
5896 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005897
San Mehat9d2bd732009-09-22 16:44:22 -07005898 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005899 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005900 return -ENXIO;
5901 }
5902
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305903 core_memres = platform_get_resource_byname(pdev,
5904 IORESOURCE_MEM, "core_mem");
5905 bam_memres = platform_get_resource_byname(pdev,
5906 IORESOURCE_MEM, "bam_mem");
5907 dml_memres = platform_get_resource_byname(pdev,
5908 IORESOURCE_MEM, "dml_mem");
5909 core_irqres = platform_get_resource_byname(pdev,
5910 IORESOURCE_IRQ, "core_irq");
5911 bam_irqres = platform_get_resource_byname(pdev,
5912 IORESOURCE_IRQ, "bam_irq");
5913 dmares = platform_get_resource_byname(pdev,
5914 IORESOURCE_DMA, "dma_chnl");
5915 dma_crci_res = platform_get_resource_byname(pdev,
5916 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005918 if (!core_irqres || !core_memres) {
5919 pr_err("%s: Invalid sdcc core resource\n", __func__);
5920 return -ENXIO;
5921 }
5922
5923 /*
5924 * Both BAM and DML memory resource should be preset.
5925 * BAM IRQ resource should also be present.
5926 */
5927 if ((bam_memres && !dml_memres) ||
5928 (!bam_memres && dml_memres) ||
5929 ((bam_memres && dml_memres) && !bam_irqres)) {
5930 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005931 return -ENXIO;
5932 }
5933
5934 /*
5935 * Setup our host structure
5936 */
San Mehat9d2bd732009-09-22 16:44:22 -07005937 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5938 if (!mmc) {
5939 ret = -ENOMEM;
5940 goto out;
5941 }
5942
5943 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305944 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005945 host->plat = plat;
5946 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005947 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305948
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305949 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305950 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005951 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305952 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07005953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005954 host->base = ioremap(core_memres->start,
5955 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07005956 if (!host->base) {
5957 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305958 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005959 }
5960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005961 host->core_irqres = core_irqres;
5962 host->bam_irqres = bam_irqres;
5963 host->core_memres = core_memres;
5964 host->dml_memres = dml_memres;
5965 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07005966 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07005967 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07005968 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305969 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07005970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005971#ifdef CONFIG_MMC_EMBEDDED_SDIO
5972 if (plat->embedded_sdio)
5973 mmc_set_embedded_sdio_data(mmc,
5974 &plat->embedded_sdio->cis,
5975 &plat->embedded_sdio->cccr,
5976 plat->embedded_sdio->funcs,
5977 plat->embedded_sdio->num_funcs);
5978#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005979
Sahitya Tummala62612cf2010-12-08 15:03:03 +05305980 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
5981 (unsigned long)host);
5982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005983 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
5984 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305985 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005986 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05305987 ret = msmsdcc_init_dma(host);
5988 if (ret)
5989 goto ioremap_free;
5990 } else {
5991 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07005992 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05305993 }
San Mehat9d2bd732009-09-22 16:44:22 -07005994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005995 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305996 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005997 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305998 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
5999 if (!IS_ERR_OR_NULL(host->bus_clk)) {
6000 /* Vote for max. clk rate for max. performance */
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05306001 ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306002 if (ret)
6003 goto bus_clk_put;
6004 ret = clk_prepare_enable(host->bus_clk);
6005 if (ret)
6006 goto bus_clk_put;
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05306007 host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
San Mehat9d2bd732009-09-22 16:44:22 -07006008 }
6009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006010 /*
6011 * Setup main peripheral bus clock
6012 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006013 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006014 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05306015 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006016 if (ret)
6017 goto pclk_put;
6018
6019 host->pclk_rate = clk_get_rate(host->pclk);
6020 }
6021
6022 /*
6023 * Setup SDC MMC clock
6024 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006025 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07006026 if (IS_ERR(host->clk)) {
6027 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006028 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07006029 }
6030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006031 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05306032 if (ret) {
6033 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
6034 goto clk_put;
6035 }
6036
Asutosh Dasf5298c32012-04-03 14:51:47 +05306037 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006038 if (ret)
6039 goto clk_put;
6040
San Mehat9d2bd732009-09-22 16:44:22 -07006041 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306042 if (!host->clk_rate)
6043 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05306044
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306045 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05306046 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306047
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306048 /*
6049 * Set the register write delay according to min. clock frequency
6050 * supported and update later when the host->clk_rate changes.
6051 */
6052 host->reg_write_delay =
6053 (1 + ((3 * USEC_PER_SEC) /
6054 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006055
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306056 atomic_set(&host->clks_on, 1);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306057
6058 ret = msmsdcc_msm_bus_register(host);
6059 if (ret)
6060 goto clk_disable;
6061
6062 if (host->msm_bus_vote.client_handle)
6063 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
6064 msmsdcc_msm_bus_work);
6065
6066 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
6067
Subhash Jadavani15f29db2011-10-13 09:57:13 +05306068 /* Apply Hard reset to SDCC to put it in power on default state */
6069 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006070
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006071#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306072 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006073 if (host->plat->cpu_dma_latency)
6074 host->cpu_dma_latency = host->plat->cpu_dma_latency;
6075 else
6076 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
6077 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306078 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
6079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006080 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07006081 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006082 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306083 goto pm_qos_remove;
San Mehat9d2bd732009-09-22 16:44:22 -07006084 }
6085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006086
6087 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306088 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006089 /* Initialize SPS */
6090 ret = msmsdcc_sps_init(host);
6091 if (ret)
6092 goto vreg_deinit;
6093 /* Initialize DML */
6094 ret = msmsdcc_dml_init(host);
6095 if (ret)
6096 goto sps_exit;
6097 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05306098 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07006099
San Mehat9d2bd732009-09-22 16:44:22 -07006100 /*
6101 * Setup MMC host structure
6102 */
6103 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006104 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
6105 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006106 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05306107 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
6108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006109 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
6110 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07006111 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05306112 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306113 /*
6114 * If we send the CMD23 before multi block write/read command
6115 * then we need not to send CMD12 at the end of the transfer.
6116 * If we don't send the CMD12 then only way to detect the PROG_DONE
6117 * status is to use the AUTO_PROG_DONE status provided by SDCC4
6118 * controller. So let's enable the CMD23 for SDCC4 only.
6119 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306120 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306121 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07006122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006123 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05306124 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006125 /*
6126 * XPC controls the maximum current in the default speed mode of SDXC
6127 * card. XPC=0 means 100mA (max.) but speed class is not supported.
6128 * XPC=1 means 150mA (max.) and speed class is supported.
6129 */
6130 if (plat->xpc_cap)
6131 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
6132 MMC_CAP_SET_XPC_180);
6133
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02006134 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02006135 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05306136 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03006137 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03006138 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02006139 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Konstantin Dorfmana2c84222013-03-12 15:33:53 +02006140 mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
Subhash Jadavani69245882013-05-27 16:58:41 +05306141 mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
Yaniv Gardi14098552012-06-04 10:56:03 +03006142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006143 if (plat->nonremovable)
6144 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006145 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006146
6147 if (plat->is_sdio_al_client)
6148 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07006149
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306150 mmc->max_segs = msmsdcc_get_nr_sg(host);
6151 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
6152 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07006153
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306154 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07006155 mmc->max_seg_size = mmc->max_req_size;
6156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006157 writel_relaxed(0, host->base + MMCIMASK0);
6158 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05306159 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006161 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
6162 mb();
6163 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07006164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006165 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
6166 DRIVER_NAME " (cmd)", host);
6167 if (ret)
6168 goto dml_exit;
6169
6170 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
6171 DRIVER_NAME " (pio)", host);
6172 if (ret)
6173 goto irq_free;
6174
6175 /*
6176 * Enable SDCC IRQ only when host is powered on. Otherwise, this
6177 * IRQ is un-necessarily being monitored by MPM (Modem power
6178 * management block) during idle-power collapse. The MPM will be
6179 * configured to monitor the DATA1 GPIO line with level-low trigger
6180 * and thus depending on the GPIO status, it prevents TCXO shutdown
6181 * during idle-power collapse.
6182 */
6183 disable_irq(core_irqres->start);
6184 host->sdcc_irq_disabled = 1;
6185
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05306186 if (!plat->sdiowakeup_irq) {
6187 /* Check if registered as IORESOURCE_IRQ */
6188 plat->sdiowakeup_irq =
6189 platform_get_irq_byname(pdev, "sdiowakeup_irq");
6190 if (plat->sdiowakeup_irq < 0)
6191 plat->sdiowakeup_irq = 0;
6192 }
6193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006194 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006195 ret = request_irq(plat->sdiowakeup_irq,
6196 msmsdcc_platform_sdiowakeup_irq,
6197 IRQF_SHARED | IRQF_TRIGGER_LOW,
6198 DRIVER_NAME "sdiowakeup", host);
6199 if (ret) {
6200 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6201 plat->sdiowakeup_irq, ret);
6202 goto pio_irq_free;
6203 } else {
6204 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306205 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006206 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306207 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006208 }
6209 spin_unlock_irqrestore(&host->lock, flags);
6210 }
6211 }
6212
Krishna Konda1963f432013-02-19 20:28:53 -08006213 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006214 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6215 mmc_hostname(mmc));
6216 }
6217
6218 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6219 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006220 /*
6221 * Setup card detect change
6222 */
6223
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306224 if (!plat->status_gpio)
6225 plat->status_gpio = -ENOENT;
6226 if (!plat->wpswitch_gpio)
6227 plat->wpswitch_gpio = -ENOENT;
6228
6229 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306230 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006231 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306232 } else {
6233 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006234 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306235 }
Krishna Konda941604a2012-01-10 17:46:34 -08006236 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006237 }
San Mehat9d2bd732009-09-22 16:44:22 -07006238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006239 if (plat->status_irq) {
6240 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006241 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006242 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006243 DRIVER_NAME " (slot)",
6244 host);
6245 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006246 pr_err("Unable to get slot IRQ %d (%d)\n",
6247 plat->status_irq, ret);
6248 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006249 }
6250 } else if (plat->register_status_notify) {
6251 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6252 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006253 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006254 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006255
6256 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006257
6258 ret = pm_runtime_set_active(&(pdev)->dev);
6259 if (ret < 0)
6260 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6261 __func__, ret);
6262 /*
6263 * There is no notion of suspend/resume for SD/MMC/SDIO
6264 * cards. So host can be suspended/resumed with out
6265 * worrying about its children.
6266 */
6267 pm_suspend_ignore_children(&(pdev)->dev, true);
6268
6269 /*
6270 * MMC/SD/SDIO bus suspend/resume operations are defined
6271 * only for the slots that will be used for non-removable
6272 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6273 * defined. Otherwise, they simply become card removal and
6274 * insertion events during suspend and resume respectively.
6275 * Hence, enable run-time PM only for slots for which bus
6276 * suspend/resume operations are defined.
6277 */
6278#ifdef CONFIG_MMC_UNSAFE_RESUME
6279 /*
6280 * If this capability is set, MMC core will enable/disable host
6281 * for every claim/release operation on a host. We use this
6282 * notification to increment/decrement runtime pm usage count.
6283 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006284 pm_runtime_enable(&(pdev)->dev);
6285#else
6286 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006287 pm_runtime_enable(&(pdev)->dev);
6288 }
6289#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306290 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006291 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6292 (unsigned long)host);
6293
San Mehat9d2bd732009-09-22 16:44:22 -07006294 mmc_add_host(mmc);
6295
Sujit Reddy Thumma97a35d22012-10-31 22:45:45 +05306296 mmc->clk_scaling.up_threshold = 35;
6297 mmc->clk_scaling.down_threshold = 5;
6298 mmc->clk_scaling.polling_delay_ms = 100;
6299 mmc->caps2 |= MMC_CAP2_CLK_SCALE;
6300
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006301 pr_info("%s: Qualcomm MSM SDCC-core %pr %pr,%d dma %d dmacrcri %d\n",
6302 mmc_hostname(mmc), core_memres, core_irqres,
Krishna Konda25786ec2011-07-25 16:21:36 -07006303 (unsigned int) plat->status_irq, host->dma.channel,
6304 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006305
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306306 pr_info("%s: Controller capabilities: 0x%.8x\n",
6307 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006308 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6309 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6310 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6311 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6312 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6313 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6314 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6315 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6316 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6317 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6318 host->eject);
6319 pr_info("%s: Power save feature enable = %d\n",
6320 mmc_hostname(mmc), msmsdcc_pwrsave);
6321
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306322 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006323 && host->dma.crci != -1) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006324 pr_info("%s: DM non-cached buffer at %p, dma_addr: %pa\n",
6325 mmc_hostname(mmc), host->dma.nc, &host->dma.nc_busaddr);
6326 pr_info("%s: DM cmd busaddr: %pa, cmdptr busaddr: %pa\n",
6327 mmc_hostname(mmc), &host->dma.cmd_busaddr,
6328 &host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306329 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006330 pr_info("%s: SPS-BAM data transfer mode available\n",
6331 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006332 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006333 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006335#if defined(CONFIG_DEBUG_FS)
6336 msmsdcc_dbg_createhost(host);
6337#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306338
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306339 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6340 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6341 sysfs_attr_init(&host->max_bus_bw.attr);
6342 host->max_bus_bw.attr.name = "max_bus_bw";
6343 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6344 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306345 if (ret)
6346 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306347
6348 if (!plat->status_irq) {
6349 host->polling.show = show_polling;
6350 host->polling.store = store_polling;
6351 sysfs_attr_init(&host->polling.attr);
6352 host->polling.attr.name = "polling";
6353 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6354 ret = device_create_file(&pdev->dev, &host->polling);
6355 if (ret)
6356 goto remove_max_bus_bw_file;
6357 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306358 host->idle_timeout.show = show_idle_timeout;
6359 host->idle_timeout.store = store_idle_timeout;
6360 sysfs_attr_init(&host->idle_timeout.attr);
6361 host->idle_timeout.attr.name = "idle_timeout";
6362 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6363 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6364 if (ret)
6365 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306366
6367 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306368 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306369
6370 /* Sysfs entry for AUTO CMD19 control */
6371 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6372 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6373 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6374 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6375 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6376 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6377 if (ret)
6378 goto remove_idle_timeout_file;
6379
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306380 add_auto_cmd21_atrr:
6381 if (!is_auto_cmd21(host))
6382 goto exit;
6383
6384 /* Sysfs entry for AUTO CMD21 control */
6385 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6386 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6387 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6388 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6389 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6390 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6391 if (ret)
6392 goto remove_auto_cmd19_attr_file;
6393
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306394 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006395 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006396
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306397 remove_auto_cmd19_attr_file:
6398 if (is_auto_cmd19(host))
6399 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306400 remove_idle_timeout_file:
6401 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306402 remove_polling_file:
6403 if (!plat->status_irq)
6404 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306405 remove_max_bus_bw_file:
6406 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006407 platform_irq_free:
6408 del_timer_sync(&host->req_tout_timer);
6409 pm_runtime_disable(&(pdev)->dev);
6410 pm_runtime_set_suspended(&(pdev)->dev);
6411
6412 if (plat->status_irq)
6413 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306414 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006415 sdiowakeup_irq_free:
Krishna Konda1963f432013-02-19 20:28:53 -08006416 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6417 wake_lock_destroy(&host->sdio_wlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006418 wake_lock_destroy(&host->sdio_suspend_wlock);
6419 if (plat->sdiowakeup_irq)
6420 free_irq(plat->sdiowakeup_irq, host);
6421 pio_irq_free:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006422 free_irq(core_irqres->start, host);
6423 irq_free:
6424 free_irq(core_irqres->start, host);
6425 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306426 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006427 msmsdcc_dml_exit(host);
6428 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306429 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006430 msmsdcc_sps_exit(host);
6431 vreg_deinit:
6432 msmsdcc_vreg_init(host, false);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306433 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006434 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306435 pm_qos_remove_request(&host->pm_qos_req_dma);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306436 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6437 msmsdcc_msm_bus_unregister(host);
6438 clk_disable:
6439 clk_disable_unprepare(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006440 clk_put:
6441 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006442 pclk_disable:
6443 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306444 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006445 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006446 if (!IS_ERR(host->pclk))
6447 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306448 if (!IS_ERR_OR_NULL(host->bus_clk))
6449 clk_disable_unprepare(host->bus_clk);
6450 bus_clk_put:
6451 if (!IS_ERR_OR_NULL(host->bus_clk))
6452 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306453 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006454 if (host->dmares)
6455 dma_free_coherent(NULL,
6456 sizeof(struct msmsdcc_nc_dmadata),
6457 host->dma.nc, host->dma.nc_busaddr);
6458 }
6459 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306460 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006461 host_free:
6462 mmc_free_host(mmc);
6463 out:
6464 return ret;
6465}
6466
Pratibhasagar V713817b2012-09-07 11:28:30 +05306467#ifdef CONFIG_DEBUG_FS
6468static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6469{
6470 debugfs_remove_recursive(host->debugfs_host_dir);
6471 host->debugfs_host_dir = NULL;
6472}
6473#else
6474static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6475#endif
6476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006477static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006478{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006479 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6480 struct mmc_platform_data *plat;
6481 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006483 if (!mmc)
6484 return -ENXIO;
6485
6486 if (pm_runtime_suspended(&(pdev)->dev))
6487 pm_runtime_resume(&(pdev)->dev);
6488
6489 host = mmc_priv(mmc);
6490
6491 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6492 plat = host->plat;
6493
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306494 if (is_auto_cmd19(host))
6495 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306496 if (is_auto_cmd21(host))
6497 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306498 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006499 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306500 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306501 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006502
Pratibhasagar V713817b2012-09-07 11:28:30 +05306503 msmsdcc_remove_debugfs(host);
6504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006505 del_timer_sync(&host->req_tout_timer);
6506 tasklet_kill(&host->dma_tlet);
6507 tasklet_kill(&host->sps.tlet);
6508 mmc_remove_host(mmc);
6509
6510 if (plat->status_irq)
6511 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306512 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006513
6514 wake_lock_destroy(&host->sdio_suspend_wlock);
6515 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006516 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6517 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006518 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006519
Krishna Konda1963f432013-02-19 20:28:53 -08006520 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6521 wake_lock_destroy(&host->sdio_wlock);
6522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006523 free_irq(host->core_irqres->start, host);
6524 free_irq(host->core_irqres->start, host);
6525
6526 clk_put(host->clk);
6527 if (!IS_ERR(host->pclk))
6528 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306529 if (!IS_ERR_OR_NULL(host->bus_clk))
6530 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006531
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006532 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306533 pm_qos_remove_request(&host->pm_qos_req_dma);
6534
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306535 if (host->msm_bus_vote.client_handle) {
6536 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6537 msmsdcc_msm_bus_unregister(host);
6538 }
6539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006540 msmsdcc_vreg_init(host, false);
6541
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306542 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006543 if (host->dmares)
6544 dma_free_coherent(NULL,
6545 sizeof(struct msmsdcc_nc_dmadata),
6546 host->dma.nc, host->dma.nc_busaddr);
6547 }
6548
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306549 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006550 msmsdcc_dml_exit(host);
6551 msmsdcc_sps_exit(host);
6552 }
6553
6554 iounmap(host->base);
6555 mmc_free_host(mmc);
6556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006557 pm_runtime_disable(&(pdev)->dev);
6558 pm_runtime_set_suspended(&(pdev)->dev);
6559
6560 return 0;
6561}
6562
6563#ifdef CONFIG_MSM_SDIO_AL
6564int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6565{
6566 struct msmsdcc_host *host = mmc_priv(mmc);
6567 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306568 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006569
Asutosh Dasf5298c32012-04-03 14:51:47 +05306570 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006571 spin_lock_irqsave(&host->lock, flags);
6572 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6573 enable ? "En" : "Dis");
6574
6575 if (enable) {
6576 if (!host->sdcc_irq_disabled) {
6577 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306578 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006579 host->sdcc_irq_disabled = 1;
6580 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306581 rc = msmsdcc_setup_clocks(host, false);
6582 if (rc)
6583 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006584
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306585 if (host->plat->sdio_lpm_gpio_setup &&
6586 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006587 spin_unlock_irqrestore(&host->lock, flags);
6588 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6589 spin_lock_irqsave(&host->lock, flags);
6590 host->sdio_gpio_lpm = 1;
6591 }
6592
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306593 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006594 msmsdcc_enable_irq_wake(host);
6595 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306596 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006597 }
6598 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306599 rc = msmsdcc_setup_clocks(host, true);
6600 if (rc)
6601 goto out;
6602
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306603 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006604 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306605 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006606 msmsdcc_disable_irq_wake(host);
6607 }
6608
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306609 if (host->plat->sdio_lpm_gpio_setup &&
6610 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006611 spin_unlock_irqrestore(&host->lock, flags);
6612 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6613 spin_lock_irqsave(&host->lock, flags);
6614 host->sdio_gpio_lpm = 0;
6615 }
6616
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306617 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006618 writel_relaxed(host->mci_irqenable,
6619 host->base + MMCIMASK0);
6620 mb();
6621 enable_irq(host->core_irqres->start);
6622 host->sdcc_irq_disabled = 0;
6623 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006624 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306625out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006626 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306627 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306628 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006629}
6630#else
6631int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6632{
6633 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006634}
6635#endif
6636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006637#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306638#ifdef CONFIG_MMC_CLKGATE
6639static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6640{
6641 struct mmc_host *mmc = host->mmc;
6642 unsigned long flags;
6643
6644 mmc_host_clk_hold(mmc);
6645 spin_lock_irqsave(&mmc->clk_lock, flags);
6646 mmc->clk_old = mmc->ios.clock;
6647 mmc->ios.clock = 0;
6648 mmc->clk_gated = true;
6649 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6650 mmc_set_ios(mmc);
6651 mmc_host_clk_release(mmc);
6652}
6653
6654static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6655{
6656 struct mmc_host *mmc = host->mmc;
6657
6658 mmc_host_clk_hold(mmc);
6659 mmc->ios.clock = host->clk_rate;
6660 mmc_set_ios(mmc);
6661 mmc_host_clk_release(mmc);
6662}
6663#else
6664static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6665{
6666 struct mmc_host *mmc = host->mmc;
6667
6668 mmc->ios.clock = 0;
6669 mmc_set_ios(mmc);
6670}
6671
6672static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6673{
6674 struct mmc_host *mmc = host->mmc;
6675
6676 mmc->ios.clock = host->clk_rate;
6677 mmc_set_ios(mmc);
6678}
6679#endif
6680
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306681#if CONFIG_DEBUG_FS
6682static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306683 const char *func, int err)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306684{
6685 ktime_t diff;
6686
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306687 if (host->print_pm_stats && !err) {
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306688 diff = ktime_sub(ktime_get(), start);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306689 pr_info("%s: %s: Completed in %llu usec\n",
6690 mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306691 }
6692}
6693#else
6694static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306695 const char *func, int err) {}
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306696#endif
6697
San Mehat9d2bd732009-09-22 16:44:22 -07006698static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006699msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006700{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006701 struct mmc_host *mmc = dev_get_drvdata(dev);
6702 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006703 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306704 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306705 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006706
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306707 if (host->plat->is_sdio_al_client) {
6708 rc = 0;
6709 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006710 }
San Mehat9d2bd732009-09-22 16:44:22 -07006711
Sahitya Tummala7661a452011-07-18 13:28:35 +05306712 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006713 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006714 host->sdcc_suspending = 1;
6715 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006717 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006718 * MMC core thinks that host is disabled by now since
6719 * runtime suspend is scheduled after msmsdcc_disable()
6720 * is called. Thus, MMC core will try to enable the host
6721 * while suspending it. This results in a synchronous
6722 * runtime resume request while in runtime suspending
6723 * context and hence inorder to complete this resume
6724 * requet, it will wait for suspend to be complete,
6725 * but runtime suspend also can not proceed further
6726 * until the host is resumed. Thus, it leads to a hang.
6727 * Hence, increase the pm usage count before suspending
6728 * the host so that any resume requests after this will
6729 * simple become pm usage counter increment operations.
6730 */
6731 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306732 /* If there is pending detect work abort runtime suspend */
6733 if (unlikely(work_busy(&mmc->detect.work)))
6734 rc = -EAGAIN;
6735 else
6736 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006737 pm_runtime_put_noidle(dev);
6738
6739 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306740 spin_lock_irqsave(&host->lock, flags);
6741 host->sdcc_suspended = true;
6742 spin_unlock_irqrestore(&host->lock, flags);
6743 if (mmc->card && mmc_card_sdio(mmc->card) &&
6744 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006745 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306746 * If SDIO function driver doesn't want
6747 * to power off the card, atleast turn off
6748 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006749 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306750 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006751 }
6752 }
6753 host->sdcc_suspending = 0;
6754 mmc->suspend_task = NULL;
6755 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6756 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006757 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306758 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306759out:
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306760 /*
6761 * Remove the vote immediately only if clocks are off in which
6762 * case we might have queued work to remove vote but it may not
6763 * be completed before runtime suspend or system suspend.
6764 */
6765 if (!atomic_read(&host->clks_on))
6766 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306767 msmsdcc_print_pm_stats(host, start, __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07006768 return rc;
6769}
6770
6771static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006772msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006773{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006774 struct mmc_host *mmc = dev_get_drvdata(dev);
6775 struct msmsdcc_host *host = mmc_priv(mmc);
6776 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306777 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006779 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306780 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006781
Sahitya Tummala7661a452011-07-18 13:28:35 +05306782 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006783 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306784 if (mmc->card && mmc_card_sdio(mmc->card) &&
6785 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306786 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306787 }
San Mehat9d2bd732009-09-22 16:44:22 -07006788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006789 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006790
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006791 /*
6792 * FIXME: Clearing of flags must be handled in clients
6793 * resume handler.
6794 */
6795 spin_lock_irqsave(&host->lock, flags);
6796 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306797 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006798 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006800 /*
6801 * After resuming the host wait for sometime so that
6802 * the SDIO work will be processed.
6803 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306804 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306805 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006806 host->plat->sdiowakeup_irq) &&
6807 wake_lock_active(&host->sdio_wlock))
6808 wake_lock_timeout(&host->sdio_wlock, 1);
6809 }
6810
6811 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006812 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306813 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306814 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306815out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306816 msmsdcc_print_pm_stats(host, start, __func__, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07006817 return 0;
6818}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006819
6820static int msmsdcc_runtime_idle(struct device *dev)
6821{
6822 struct mmc_host *mmc = dev_get_drvdata(dev);
6823 struct msmsdcc_host *host = mmc_priv(mmc);
6824
6825 if (host->plat->is_sdio_al_client)
6826 return 0;
6827
6828 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306829 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006830
6831 return -EAGAIN;
6832}
6833
6834static int msmsdcc_pm_suspend(struct device *dev)
6835{
6836 struct mmc_host *mmc = dev_get_drvdata(dev);
6837 struct msmsdcc_host *host = mmc_priv(mmc);
6838 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306839 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006840
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306841 if (host->plat->is_sdio_al_client) {
6842 rc = 0;
6843 goto out;
6844 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306845 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006846 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306847 msmsdcc_disable_status_gpio(host);
6848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006849
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306850 /*
6851 * If system comes out of suspend, msmsdcc_pm_resume() sets the
6852 * host->pending_resume flag if the SDCC wasn't runtime suspended.
6853 * Now if the system again goes to suspend without any SDCC activity
6854 * then host->pending_resume flag will remain set which may cause
6855 * the SDCC resume to happen first and then suspend.
6856 * To avoid this unnecessary resume/suspend, make sure that
6857 * pending_resume flag is cleared before calling the
6858 * msmsdcc_runtime_suspend().
6859 */
6860 if (!pm_runtime_suspended(dev) && !host->pending_resume)
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006861 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306862 out:
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306863 /* This flag must not be set if system is entering into suspend */
6864 host->pending_resume = false;
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306865 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006866 return rc;
6867}
6868
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306869static int msmsdcc_suspend_noirq(struct device *dev)
6870{
6871 struct mmc_host *mmc = dev_get_drvdata(dev);
6872 struct msmsdcc_host *host = mmc_priv(mmc);
6873 int rc = 0;
6874
6875 /*
6876 * After platform suspend there may be active request
6877 * which might have enabled clocks. For example, in SDIO
6878 * case, ksdioirq thread might have scheduled after sdcc
6879 * suspend but before system freeze. In that case abort
6880 * suspend and retry instead of keeping the clocks on
6881 * during suspend and not allowing TCXO.
6882 */
6883
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306884 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306885 pr_warn("%s: clocks are on after suspend, aborting system "
6886 "suspend\n", mmc_hostname(mmc));
6887 rc = -EAGAIN;
6888 }
6889
6890 return rc;
6891}
6892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006893static int msmsdcc_pm_resume(struct device *dev)
6894{
6895 struct mmc_host *mmc = dev_get_drvdata(dev);
6896 struct msmsdcc_host *host = mmc_priv(mmc);
6897 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306898 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006899
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306900 if (host->plat->is_sdio_al_client) {
6901 rc = 0;
6902 goto out;
6903 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006904 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306905 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306906 /*
6907 * As runtime PM is enabled before calling the device's platform resume
6908 * callback, we use the pm_runtime_suspended API to know if SDCC is
6909 * really runtime suspended or not and set the pending_resume flag only
6910 * if its not runtime suspended.
6911 */
6912 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006913 host->pending_resume = true;
6914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006915 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306916 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006917 msmsdcc_check_status((unsigned long)host);
6918 enable_irq(host->plat->status_irq);
6919 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306920out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306921 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006922 return rc;
6923}
6924
Daniel Walker08ecfde2010-06-23 12:32:20 -07006925#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006926static int msmsdcc_runtime_suspend(struct device *dev)
6927{
6928 return 0;
6929}
6930static int msmsdcc_runtime_idle(struct device *dev)
6931{
6932 return 0;
6933}
6934static int msmsdcc_pm_suspend(struct device *dev)
6935{
6936 return 0;
6937}
6938static int msmsdcc_pm_resume(struct device *dev)
6939{
6940 return 0;
6941}
6942static int msmsdcc_suspend_noirq(struct device *dev)
6943{
6944 return 0;
6945}
6946static int msmsdcc_runtime_resume(struct device *dev)
6947{
6948 return 0;
6949}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006950#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006951
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006952static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
6953 .runtime_suspend = msmsdcc_runtime_suspend,
6954 .runtime_resume = msmsdcc_runtime_resume,
6955 .runtime_idle = msmsdcc_runtime_idle,
6956 .suspend = msmsdcc_pm_suspend,
6957 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306958 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006959};
6960
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306961static const struct of_device_id msmsdcc_dt_match[] = {
6962 {.compatible = "qcom,msm-sdcc"},
6963
6964};
6965MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
6966
San Mehat9d2bd732009-09-22 16:44:22 -07006967static struct platform_driver msmsdcc_driver = {
6968 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006969 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07006970 .driver = {
6971 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006972 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05306973 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07006974 },
6975};
6976
6977static int __init msmsdcc_init(void)
6978{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006979#if defined(CONFIG_DEBUG_FS)
6980 int ret = 0;
6981 ret = msmsdcc_dbg_init();
6982 if (ret) {
6983 pr_err("Failed to create debug fs dir \n");
6984 return ret;
6985 }
6986#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006987 return platform_driver_register(&msmsdcc_driver);
6988}
San Mehat9d2bd732009-09-22 16:44:22 -07006989
San Mehat9d2bd732009-09-22 16:44:22 -07006990static void __exit msmsdcc_exit(void)
6991{
6992 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006993
6994#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006995 debugfs_remove(debugfs_dir);
6996#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006997}
6998
6999module_init(msmsdcc_init);
7000module_exit(msmsdcc_exit);
7001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007002MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07007003MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007004
7005#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05307006static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007007{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307008 struct msmsdcc_host *host = data;
7009
7010 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007011 return 0;
7012}
7013
Pratibhasagar V713817b2012-09-07 11:28:30 +05307014static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007015{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307016 struct msmsdcc_host *host = data;
7017 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007018
Pratibhasagar V713817b2012-09-07 11:28:30 +05307019 spin_lock_irqsave(&host->lock, flags);
7020 host->idle_tout = (u32)val * 1000;
7021 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007022
Pratibhasagar V713817b2012-09-07 11:28:30 +05307023 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007024}
7025
Pratibhasagar V713817b2012-09-07 11:28:30 +05307026DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
7027 msmsdcc_dbg_idle_tout_get,
7028 msmsdcc_dbg_idle_tout_set,
7029 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007030
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307031static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
7032{
7033 struct msmsdcc_host *host = data;
7034
7035 *val = (u64) host->enforce_pio_mode;
7036 return 0;
7037}
7038
7039static int msmsdcc_dbg_pio_mode_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->enforce_pio_mode = !!val;
7046 spin_unlock_irqrestore(&host->lock, flags);
7047
7048 return 0;
7049}
7050
7051DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
7052 msmsdcc_dbg_pio_mode_get,
7053 msmsdcc_dbg_pio_mode_set,
7054 "%llu\n");
7055
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307056static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
7057{
7058 struct msmsdcc_host *host = data;
7059
7060 *val = !!host->print_pm_stats;
7061 return 0;
7062}
7063
7064static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
7065{
7066 struct msmsdcc_host *host = data;
7067 unsigned long flags;
7068
7069 spin_lock_irqsave(&host->lock, flags);
7070 host->print_pm_stats = !!val;
7071 spin_unlock_irqrestore(&host->lock, flags);
7072
7073 return 0;
7074}
7075
7076DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
7077 msmsdcc_dbg_pm_stats_get,
7078 msmsdcc_dbg_pm_stats_set,
7079 "%llu\n");
7080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007081static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
7082{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307083 int err = 0;
7084
7085 if (!debugfs_dir)
7086 return;
7087
7088 host->debugfs_host_dir = debugfs_create_dir(
7089 mmc_hostname(host->mmc), debugfs_dir);
7090 if (IS_ERR(host->debugfs_host_dir)) {
7091 err = PTR_ERR(host->debugfs_host_dir);
7092 host->debugfs_host_dir = NULL;
7093 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
7094 mmc_hostname(host->mmc), err);
7095 return;
7096 }
7097
7098 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
7099 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7100 &msmsdcc_dbg_idle_tout_ops);
7101
7102 if (IS_ERR(host->debugfs_idle_tout)) {
7103 err = PTR_ERR(host->debugfs_idle_tout);
7104 host->debugfs_idle_tout = NULL;
7105 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
7106 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007107 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307108
7109 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
7110 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7111 &msmsdcc_dbg_pio_mode_ops);
7112
7113 if (IS_ERR(host->debugfs_pio_mode)) {
7114 err = PTR_ERR(host->debugfs_pio_mode);
7115 host->debugfs_pio_mode = NULL;
7116 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
7117 mmc_hostname(host->mmc), err);
7118 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307119
7120 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
7121 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7122 &msmsdcc_dbg_pm_stats_ops);
7123 if (IS_ERR(host->debugfs_pm_stats)) {
7124 err = PTR_ERR(host->debugfs_pm_stats);
7125 host->debugfs_pm_stats = NULL;
7126 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
7127 mmc_hostname(host->mmc), err);
7128 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007129}
7130
7131static int __init msmsdcc_dbg_init(void)
7132{
7133 int err;
7134
Pratibhasagar V713817b2012-09-07 11:28:30 +05307135 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007136 if (IS_ERR(debugfs_dir)) {
7137 err = PTR_ERR(debugfs_dir);
7138 debugfs_dir = NULL;
7139 return err;
7140 }
7141
7142 return 0;
7143}
7144#endif