blob: e285bfa26a106bec8af5a4c99fd02cce5505bebe [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
San Mehat1cd22962010-02-03 12:59:29 -08001659static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001660msmsdcc_pio_irq(int irq, void *dev_id)
1661{
1662 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001664 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001665 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001666 unsigned int remain;
1667 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001668
Murali Palnati36448a42011-09-02 15:06:18 +05301669 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301670
Oluwafemi Adeyemi0bcb1332012-12-07 16:21:22 -08001671 if (!atomic_read(&host->clks_on)) {
1672 spin_unlock(&host->lock);
1673 return IRQ_NONE;
1674 }
1675
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301679 (MCI_IRQ_PIO)) == 0) {
1680 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301681 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301682 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683#if IRQ_DEBUG
1684 msmsdcc_print_status(host, "irq1-r", status);
1685#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001686 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001687
1688 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001689 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1692 | MCI_RXDATAAVLBL)))
1693 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001694
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001695 if (!msmsdcc_sg_next(host, &buffer, &remain))
1696 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001697
San Mehat9d2bd732009-09-22 16:44:22 -07001698 len = 0;
1699 if (status & MCI_RXACTIVE)
1700 len = msmsdcc_pio_read(host, buffer, remain);
1701 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001703
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301704 /* len might have aligned to 32bits above */
1705 if (len > remain)
1706 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001707
San Mehat9d2bd732009-09-22 16:44:22 -07001708 host->curr.xfer_remain -= len;
1709 host->curr.data_xfered += len;
1710 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001711 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713 if (remain) /* Done with this page? */
1714 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001717 } while (1);
1718
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001719 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001720 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1723 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1724 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1725 host->base + MMCIMASK0);
1726 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301727 /*
1728 * back to back write to MASK0 register don't need
1729 * synchronization delay.
1730 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1732 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1733 }
1734 mb();
1735 } else if (!host->curr.xfer_remain) {
1736 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1737 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1738 mb();
1739 }
San Mehat9d2bd732009-09-22 16:44:22 -07001740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001742
1743 return IRQ_HANDLED;
1744}
1745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746static void
1747msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1748
1749static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1750 struct mmc_data *data)
1751{
1752 u32 loop_cnt = 0;
1753
1754 /*
1755 * For read commands with data less than fifo size, it is possible to
1756 * get DATAEND first and RXDATA_AVAIL might be set later because of
1757 * synchronization delay through the asynchronous RX FIFO. Thus, for
1758 * such cases, even after DATAEND interrupt is received software
1759 * should poll for RXDATA_AVAIL until the requested data is read out
1760 * of FIFO. This change is needed to get around this abnormal but
1761 * sometimes expected behavior of SDCC3 controller.
1762 *
1763 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1764 * after the data is loaded into RX FIFO. This would amount to less
1765 * than a microsecond and thus looping for 1000 times is good enough
1766 * for that delay.
1767 */
1768 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1769 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1770 spin_unlock(&host->lock);
1771 msmsdcc_pio_irq(1, host);
1772 spin_lock(&host->lock);
1773 }
1774 }
1775 if (loop_cnt == 1000) {
1776 pr_info("%s: Timed out while polling for Rx Data\n",
1777 mmc_hostname(host->mmc));
1778 data->error = -ETIMEDOUT;
1779 msmsdcc_reset_and_restore(host);
1780 }
1781}
1782
San Mehat9d2bd732009-09-22 16:44:22 -07001783static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1784{
1785 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001786
1787 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301788 if (mmc_resp_type(cmd))
1789 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1790 /*
1791 * Read rest of the response registers only if
1792 * long response is expected for this command
1793 */
1794 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1795 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1796 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1797 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1798 }
San Mehat9d2bd732009-09-22 16:44:22 -07001799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301801 pr_debug("%s: CMD%d: Command timeout\n",
1802 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001803 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301805 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301806 pr_err("%s: CMD%d: Command CRC error\n",
1807 mmc_hostname(host->mmc), cmd->opcode);
1808 msmsdcc_dump_sdcc_state(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05301809 /* Execute full tuning in case of CRC errors */
1810 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Subhash Jadavani355df542012-10-09 19:06:49 +05301811 if (host->tuning_needed)
1812 host->tuning_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001813 cmd->error = -EILSEQ;
1814 }
1815
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301816 if (!cmd->error) {
1817 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1818 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1819 mod_timer(&host->req_tout_timer, (jiffies +
1820 msecs_to_jiffies(host->curr.req_tout_ms)));
1821 }
1822 }
1823
San Mehat9d2bd732009-09-22 16:44:22 -07001824 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 if (host->curr.data && host->dma.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301826 is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001827 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 else if (host->curr.data && host->sps.sg &&
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301829 is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 /* Stop current SPS transfer */
1831 msmsdcc_sps_exit_curr_xfer(host);
1832 }
San Mehat9d2bd732009-09-22 16:44:22 -07001833 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301834 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001835 msmsdcc_stop_data(host);
1836 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301837 } else { /* host->data == NULL */
1838 if (!cmd->error && host->prog_enable) {
1839 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301841 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301843 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301844 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301845 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301846 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001847 if (host->dummy_52_needed)
1848 host->dummy_52_needed = 0;
1849 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301851 msmsdcc_request_end(host, cmd->mrq);
1852 }
1853 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301854 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301855 if (cmd == host->curr.mrq->sbc)
1856 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1857 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1858 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301859 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001860 }
1861}
1862
San Mehat9d2bd732009-09-22 16:44:22 -07001863static irqreturn_t
1864msmsdcc_irq(int irq, void *dev_id)
1865{
1866 struct msmsdcc_host *host = dev_id;
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301867 struct mmc_host *mmc = host->mmc;
San Mehat9d2bd732009-09-22 16:44:22 -07001868 u32 status;
1869 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001871
1872 spin_lock(&host->lock);
1873
1874 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875 struct mmc_command *cmd;
1876 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 if (timer) {
1879 timer = 0;
1880 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001881 }
San Mehat9d2bd732009-09-22 16:44:22 -07001882
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05301883 if (!atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884 pr_debug("%s: %s: SDIO async irq received\n",
1885 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301886
1887 /*
1888 * Only async interrupt can come when clocks are off,
1889 * disable further interrupts and enable them when
1890 * clocks are on.
1891 */
1892 if (!host->sdcc_irq_disabled) {
1893 disable_irq_nosync(irq);
1894 host->sdcc_irq_disabled = 1;
1895 }
1896
1897 /*
1898 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1899 * will take care of signaling sdio irq during
1900 * mmc_sdio_resume().
1901 */
Krishna Konda1963f432013-02-19 20:28:53 -08001902 if (host->sdcc_suspended &&
1903 (host->plat->mpm_sdiowakeup_int ||
1904 host->plat->sdiowakeup_irq)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301905 /*
1906 * This is a wakeup interrupt so hold wakelock
1907 * until SDCC resume is handled.
1908 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301910 } else {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301911 if (!mmc->card || (mmc->card &&
1912 !mmc_card_sdio(mmc->card))) {
1913 pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
1914 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301915 ret = 1;
1916 break;
1917 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301918 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301919 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301920 spin_lock(&host->lock);
1921 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301922 ret = 1;
1923 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 }
1925
1926 status = readl_relaxed(host->base + MMCISTATUS);
1927
1928 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1929 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001930 break;
1931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932#if IRQ_DEBUG
1933 msmsdcc_print_status(host, "irq0-r", status);
1934#endif
1935 status &= readl_relaxed(host->base + MMCIMASK0);
1936 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301937 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301938 if (host->clk_rate <=
1939 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301940 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941#if IRQ_DEBUG
1942 msmsdcc_print_status(host, "irq0-p", status);
1943#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 if (status & MCI_SDIOINTROPE) {
Subhash Jadavani94f2f1f2012-11-22 22:17:49 +05301946 if (!mmc->card || (mmc->card &&
1947 !mmc_card_sdio(mmc->card))) {
1948 pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
1949 mmc_hostname(mmc));
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05301950 ret = 1;
1951 break;
1952 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 if (host->sdcc_suspending)
1954 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301955 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301957 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001958 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001959 data = host->curr.data;
1960
1961 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1963 MCI_CMDTIMEOUT)) {
1964 if (status & MCI_CMDTIMEOUT)
1965 pr_debug("%s: dummy CMD52 timeout\n",
1966 mmc_hostname(host->mmc));
1967 if (status & MCI_CMDCRCFAIL)
1968 pr_debug("%s: dummy CMD52 CRC failed\n",
1969 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001970 host->dummy_52_sent = 0;
1971 host->dummy_52_needed = 0;
1972 if (data) {
1973 msmsdcc_stop_data(host);
1974 msmsdcc_request_end(host, data->mrq);
1975 }
1976 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001977 spin_unlock(&host->lock);
1978 return IRQ_HANDLED;
1979 }
1980 break;
1981 }
1982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 /*
1984 * Check for proper command response
1985 */
1986 cmd = host->curr.cmd;
1987 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1988 MCI_CMDTIMEOUT | MCI_PROGDONE |
1989 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1990 msmsdcc_do_cmdirq(host, status);
1991 }
1992
Subhash Jadavani2d7980f2013-01-09 16:18:08 +05301993 if (data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 /* Check for data errors */
1995 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1996 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1997 msmsdcc_data_err(host, data, status);
1998 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05301999 if (host->dma.sg && is_dma_mode(host))
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07002000 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05302001 else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 /* Stop current SPS transfer */
2003 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302004 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 msmsdcc_reset_and_restore(host);
2006 if (host->curr.data)
2007 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302008 if (!data->stop || (host->curr.mrq->sbc
2009 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 timer |=
2011 msmsdcc_request_end(host,
2012 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302013 else if ((host->curr.mrq->sbc
2014 && data->error) ||
2015 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 msmsdcc_start_command(host,
2017 data->stop,
2018 0);
2019 timer = 1;
2020 }
2021 }
2022 }
2023
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302024 /* Check for prog done */
2025 if (host->curr.wait_for_auto_prog_done &&
2026 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302027 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 /* Check for data done */
2030 if (!host->curr.got_dataend && (status & MCI_DATAEND))
2031 host->curr.got_dataend = 1;
2032
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302033 if (host->curr.got_dataend &&
2034 (!host->curr.wait_for_auto_prog_done ||
2035 (host->curr.wait_for_auto_prog_done &&
2036 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 /*
2038 * If DMA is still in progress, we complete
2039 * via the completion handler
2040 */
2041 if (!host->dma.busy && !host->sps.busy) {
2042 /*
2043 * There appears to be an issue in the
2044 * controller where if you request a
2045 * small block transfer (< fifo size),
2046 * you may get your DATAEND/DATABLKEND
2047 * irq without the PIO data irq.
2048 *
2049 * Check to see if theres still data
2050 * to be read, and simulate a PIO irq.
2051 */
2052 if (data->flags & MMC_DATA_READ)
2053 msmsdcc_wait_for_rxdata(host,
2054 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002055 if (!data->error) {
2056 host->curr.data_xfered =
2057 host->curr.xfer_size;
2058 host->curr.xfer_remain -=
2059 host->curr.xfer_size;
2060 }
2061
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002062 if (!host->dummy_52_needed) {
2063 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302064 if (!data->stop ||
2065 (host->curr.mrq->sbc
2066 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002067 msmsdcc_request_end(
2068 host,
2069 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302070 else if ((host->curr.mrq->sbc
2071 && data->error) ||
2072 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002073 msmsdcc_start_command(
2074 host,
2075 data->stop, 0);
2076 timer = 1;
2077 }
2078 } else {
2079 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002081 &dummy52cmd,
2082 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002083 }
2084 }
2085 }
2086 }
2087
San Mehat9d2bd732009-09-22 16:44:22 -07002088 ret = 1;
2089 } while (status);
2090
2091 spin_unlock(&host->lock);
2092
San Mehat9d2bd732009-09-22 16:44:22 -07002093 return IRQ_RETVAL(ret);
2094}
2095
2096static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05302097msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
2098 bool is_first_request)
2099{
2100 struct msmsdcc_host *host = mmc_priv(mmc);
2101 struct mmc_data *data = mrq->data;
2102 int rc = 0;
2103
2104 if (unlikely(!data)) {
2105 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
2106 __func__);
2107 return;
2108 }
2109 if (unlikely(data->host_cookie)) {
2110 /* Very wrong */
2111 data->host_cookie = 0;
2112 pr_err("%s: %s Request reposted for prepare\n",
2113 mmc_hostname(mmc), __func__);
2114 return;
2115 }
2116
2117 if (!msmsdcc_is_dma_possible(host, data))
2118 return;
2119
2120 rc = msmsdcc_prep_xfer(host, data);
2121 if (unlikely(rc < 0)) {
2122 data->host_cookie = 0;
2123 return;
2124 }
2125
2126 data->host_cookie = 1;
2127}
2128
2129static void
2130msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
2131{
2132 struct msmsdcc_host *host = mmc_priv(mmc);
2133 unsigned int dir;
2134 struct mmc_data *data = mrq->data;
2135
2136 if (unlikely(!data)) {
2137 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
2138 __func__);
2139 return;
2140 }
2141 if (data->flags & MMC_DATA_READ)
2142 dir = DMA_FROM_DEVICE;
2143 else
2144 dir = DMA_TO_DEVICE;
2145
2146 if (data->host_cookie)
2147 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
2148 data->sg_len, dir);
2149
2150 data->host_cookie = 0;
2151}
2152
2153static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
2155{
Subhash Jadavanif5277752011-10-12 16:47:52 +05302156 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05302158 if ((mrq->data->flags & MMC_DATA_READ) ||
2159 host->curr.use_wr_data_pend)
2160 msmsdcc_start_data(host, mrq->data,
2161 mrq->sbc ? mrq->sbc : mrq->cmd,
2162 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302163 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05302164 msmsdcc_start_command(host,
2165 mrq->sbc ? mrq->sbc : mrq->cmd,
2166 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002167 } else {
2168 msmsdcc_start_command(host, mrq->cmd, 0);
2169 }
2170}
2171
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302172/*
2173 * This function returns true if AUTO_PROG_DONE feature of host is
2174 * applicable for current request, returns "false" otherwise.
2175 *
2176 * NOTE: Caller should call this function only for data write operations.
2177 */
2178static bool msmsdcc_is_wait_for_auto_prog_done(struct msmsdcc_host *host,
2179 struct mmc_request *mrq)
2180{
2181 /*
2182 * Auto-prog done will be enabled for following cases:
2183 * mrq->sbc | mrq->stop
2184 * _____________|________________
2185 * True | Don't care
2186 * False | False (CMD24, ACMD25 use case)
2187 */
2188 if (is_auto_prog_done(host) && (mrq->sbc || !mrq->stop))
2189 return true;
2190
2191 return false;
2192}
2193
2194/*
2195 * This function returns true if controller can wait for prog done
2196 * for current request, returns "false" otherwise.
2197 *
2198 * NOTE: Caller should call this function only for data write operations.
2199 */
2200static bool msmsdcc_is_wait_for_prog_done(struct msmsdcc_host *host,
2201 struct mmc_request *mrq)
2202{
2203 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq) || mrq->stop)
2204 return true;
2205
2206 return false;
2207}
2208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002209static void
San Mehat9d2bd732009-09-22 16:44:22 -07002210msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
2211{
2212 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302213 unsigned long flags;
Krishna Konda3d47c822013-02-21 18:28:11 -08002214 unsigned int error = 0;
Krishna Konda3ca90f02012-08-29 16:29:21 -07002215 int retries = 5;
San Mehat9d2bd732009-09-22 16:44:22 -07002216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217 /*
2218 * Get the SDIO AL client out of LPM.
2219 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07002220 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 if (host->plat->is_sdio_al_client)
2222 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002223
Krishna Konda3d47c822013-02-21 18:28:11 -08002224 /*
2225 * Don't start the request if SDCC is not in proper state to handle it
2226 * BAM state is checked below if applicable
2227 */
2228 if (!host->pwr || !atomic_read(&host->clks_on) ||
2229 host->sdcc_irq_disabled) {
2230 WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
2231 mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
2232 error = EIO;
2233 goto bad_state;
2234 }
2235
Krishna Konda3ca90f02012-08-29 16:29:21 -07002236 /* check if sps bam needs to be reset */
2237 if (is_sps_mode(host) && host->sps.reset_bam) {
2238 while (retries) {
2239 if (!msmsdcc_bam_dml_reset_and_restore(host))
2240 break;
2241 pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
2242 mmc_hostname(host->mmc), --retries);
2243 }
Krishna Konda3d47c822013-02-21 18:28:11 -08002244
2245 /* check if BAM reset succeeded or not */
2246 if (host->sps.reset_bam) {
2247 pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
2248 mmc_hostname(host->mmc), mrq->cmd->opcode);
2249 error = EAGAIN;
2250 goto bad_state;
2251 }
Subhash Jadavanib5b07742011-08-29 17:48:07 +05302252 }
San Mehat9d2bd732009-09-22 16:44:22 -07002253
Subhash Jadavani355df542012-10-09 19:06:49 +05302254 /*
2255 * Check if DLL retuning is required? If yes, perform it here before
2256 * starting new request.
2257 */
2258 if (host->tuning_needed && !host->tuning_in_progress &&
2259 !host->tuning_done) {
2260 pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
2261 mmc_hostname(mmc), __func__, host->mmc->ios.timing);
2262 if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
2263 msmsdcc_execute_tuning(mmc,
2264 MMC_SEND_TUNING_BLOCK);
2265 else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
2266 msmsdcc_execute_tuning(mmc,
2267 MMC_SEND_TUNING_BLOCK_HS200);
2268 }
2269
San Mehat9d2bd732009-09-22 16:44:22 -07002270 if (host->eject) {
Krishna Konda3d47c822013-02-21 18:28:11 -08002271 error = ENOMEDIUM;
2272 goto card_ejected;
subhashjf181c292012-05-02 13:07:40 +05302273 }
2274
2275 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2276 " other request (CMD%d) is in progress\n",
2277 mmc_hostname(host->mmc), __func__,
2278 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2279
Krishna Konda3d47c822013-02-21 18:28:11 -08002280 spin_lock_irqsave(&host->lock, flags);
2281
subhashjf181c292012-05-02 13:07:40 +05302282 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302283 * Set timeout value to 10 secs (or more in case of buggy cards)
2284 */
2285 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302286 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302287 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302288 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302289 /*
2290 * Kick the software request timeout timer here with the timeout
2291 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302292 */
2293 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302294 (jiffies +
2295 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002296
San Mehat9d2bd732009-09-22 16:44:22 -07002297 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302298 if (mrq->sbc) {
2299 mrq->sbc->mrq = mrq;
2300 mrq->sbc->data = mrq->data;
2301 }
2302
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302303 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanie6aba7a2012-12-19 19:03:57 +05302304 if (msmsdcc_is_wait_for_auto_prog_done(host, mrq)) {
2305 host->curr.wait_for_auto_prog_done = true;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302306 } else {
2307 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2308 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309 host->dummy_52_needed = 1;
2310 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302311
Subhash Jadavanif5277752011-10-12 16:47:52 +05302312 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
Subhash Jadavanicf58e6f2012-10-05 20:45:54 +05302313 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
2314 ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
2315 is_data_pend_for_cmd53(host)))
Subhash Jadavanif5277752011-10-12 16:47:52 +05302316 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002317 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302318
Subhash Jadavanif5277752011-10-12 16:47:52 +05302319 msmsdcc_request_start(host, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002320 spin_unlock_irqrestore(&host->lock, flags);
Krishna Konda3d47c822013-02-21 18:28:11 -08002321 return;
2322
2323bad_state:
2324 msmsdcc_dump_sdcc_state(host);
2325card_ejected:
2326 mrq->cmd->error = -error;
2327 if (mrq->data) {
2328 mrq->data->error = -error;
2329 mrq->data->bytes_xfered = 0;
2330 }
2331 mmc_request_done(mmc, mrq);
San Mehat9d2bd732009-09-22 16:44:22 -07002332}
2333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2335 int min_uV, int max_uV)
2336{
2337 int rc = 0;
2338
2339 if (vreg->set_voltage_sup) {
2340 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2341 if (rc) {
2342 pr_err("%s: regulator_set_voltage(%s) failed."
2343 " min_uV=%d, max_uV=%d, rc=%d\n",
2344 __func__, vreg->name, min_uV, max_uV, rc);
2345 }
2346 }
2347
2348 return rc;
2349}
2350
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302351static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
2352{
2353 int rc = 0;
2354
2355 rc = regulator_get_voltage(vreg->reg);
2356 if (rc < 0)
2357 pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
2358 __func__, vreg->name, rc);
2359
2360 return rc;
2361}
2362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2364 int uA_load)
2365{
2366 int rc = 0;
2367
Krishna Kondafea60182011-11-01 16:01:34 -07002368 /* regulators that do not support regulator_set_voltage also
2369 do not support regulator_set_optimum_mode */
2370 if (vreg->set_voltage_sup) {
2371 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2372 if (rc < 0)
2373 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2374 "uA_load=%d) failed. rc=%d\n", __func__,
2375 vreg->name, uA_load, rc);
2376 else
2377 /* regulator_set_optimum_mode() can return non zero
2378 * value even for success case.
2379 */
2380 rc = 0;
2381 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382
2383 return rc;
2384}
2385
2386static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2387 struct device *dev)
2388{
2389 int rc = 0;
2390
2391 /* check if regulator is already initialized? */
2392 if (vreg->reg)
2393 goto out;
2394
2395 /* Get the regulator handle */
2396 vreg->reg = regulator_get(dev, vreg->name);
2397 if (IS_ERR(vreg->reg)) {
2398 rc = PTR_ERR(vreg->reg);
2399 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2400 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002401 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002403
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302404 if (regulator_count_voltages(vreg->reg) > 0) {
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002405 vreg->set_voltage_sup = 1;
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05302406 /* sanity check */
2407 if (!vreg->high_vol_level || !vreg->hpm_uA) {
2408 pr_err("%s: %s invalid constraints specified\n",
2409 __func__, vreg->name);
2410 rc = -EINVAL;
2411 }
2412 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414out:
2415 return rc;
2416}
2417
2418static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2419{
2420 if (vreg->reg)
2421 regulator_put(vreg->reg);
2422}
2423
2424/* This init function should be called only once for each SDCC slot */
2425static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2426{
2427 int rc = 0;
2428 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302429 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430 struct device *dev = mmc_dev(host->mmc);
2431
2432 curr_slot = host->plat->vreg_data;
2433 if (!curr_slot)
2434 goto out;
2435
2436 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302437 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438
2439 if (is_init) {
2440 /*
2441 * Get the regulator handle from voltage regulator framework
2442 * and then try to set the voltage level for the regulator
2443 */
2444 if (curr_vdd_reg) {
2445 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2446 if (rc)
2447 goto out;
2448 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302449 if (curr_vdd_io_reg) {
2450 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 if (rc)
2452 goto vdd_reg_deinit;
2453 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002454 rc = msmsdcc_vreg_reset(host);
2455 if (rc)
2456 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05302457 host->pdev->id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 goto out;
2459 } else {
2460 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302461 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302463vdd_io_reg_deinit:
2464 if (curr_vdd_io_reg)
2465 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466vdd_reg_deinit:
2467 if (curr_vdd_reg)
2468 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2469out:
2470 return rc;
2471}
2472
2473static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2474{
2475 int rc = 0;
2476
Subhash Jadavanicc922692011-08-01 23:05:01 +05302477 /* Put regulator in HPM (high power mode) */
2478 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2479 if (rc < 0)
2480 goto out;
2481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482 if (!vreg->is_enabled) {
2483 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302484 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2485 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486 if (rc)
2487 goto out;
2488
2489 rc = regulator_enable(vreg->reg);
2490 if (rc) {
2491 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2492 __func__, vreg->name, rc);
2493 goto out;
2494 }
2495 vreg->is_enabled = true;
2496 }
2497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498out:
2499 return rc;
2500}
2501
Krishna Konda3c4142d2012-06-27 11:01:56 -07002502static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503{
2504 int rc = 0;
2505
2506 /* Never disable regulator marked as always_on */
2507 if (vreg->is_enabled && !vreg->always_on) {
2508 rc = regulator_disable(vreg->reg);
2509 if (rc) {
2510 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2511 __func__, vreg->name, rc);
2512 goto out;
2513 }
2514 vreg->is_enabled = false;
2515
2516 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2517 if (rc < 0)
2518 goto out;
2519
2520 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302521 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 if (rc)
2523 goto out;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002524 } else if (vreg->is_enabled && vreg->always_on) {
2525 if (!is_init && vreg->lpm_sup) {
2526 /* Put always_on regulator in LPM (low power mode) */
2527 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2528 if (rc < 0)
2529 goto out;
2530 } else if (is_init && vreg->reset_at_init) {
2531 /**
2532 * The regulator might not actually be disabled if it
2533 * is shared and in use by other drivers.
2534 */
2535 rc = regulator_disable(vreg->reg);
2536 if (rc) {
2537 pr_err("%s: regulator_disable(%s) failed at " \
2538 "bootup. rc=%d\n", __func__,
2539 vreg->name, rc);
2540 goto out;
2541 }
2542 vreg->is_enabled = false;
2543 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 }
2545out:
2546 return rc;
2547}
2548
Krishna Konda3c4142d2012-06-27 11:01:56 -07002549static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
2550 bool is_init)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551{
2552 int rc = 0, i;
2553 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302554 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555
2556 curr_slot = host->plat->vreg_data;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302557 if (!curr_slot) {
Asutosh Dasd5902bf2012-10-03 18:28:20 +05302558 pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
2559 mmc_hostname(host->mmc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560 goto out;
Asutosh Dasebd7d092012-07-09 19:08:26 +05302561 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562
Subhash Jadavani937c7502012-06-01 15:34:46 +05302563 vreg_table[0] = curr_slot->vdd_data;
2564 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565
2566 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2567 if (vreg_table[i]) {
2568 if (enable)
2569 rc = msmsdcc_vreg_enable(vreg_table[i]);
2570 else
Krishna Konda3c4142d2012-06-27 11:01:56 -07002571 rc = msmsdcc_vreg_disable(vreg_table[i],
2572 is_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002573 if (rc)
2574 goto out;
2575 }
2576 }
2577out:
2578 return rc;
2579}
2580
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002581/*
2582 * Reset vreg by ensuring it is off during probe. A call
2583 * to enable vreg is needed to balance disable vreg
2584 */
2585static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2586{
2587 int rc;
2588
Krishna Konda3c4142d2012-06-27 11:01:56 -07002589 rc = msmsdcc_setup_vreg(host, 1, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002590 if (rc)
2591 return rc;
Krishna Konda3c4142d2012-06-27 11:01:56 -07002592 rc = msmsdcc_setup_vreg(host, 0, true);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002593 return rc;
2594}
2595
Subhash Jadavani937c7502012-06-01 15:34:46 +05302596enum vdd_io_level {
2597 /* set vdd_io_data->low_vol_level */
2598 VDD_IO_LOW,
2599 /* set vdd_io_data->high_vol_level */
2600 VDD_IO_HIGH,
2601 /*
2602 * set whatever there in voltage_level (third argument) of
2603 * msmsdcc_set_vdd_io_vol() function.
2604 */
2605 VDD_IO_SET_LEVEL,
2606};
2607
Subhash Jadavani341b9e72012-08-11 18:11:57 +05302608/*
2609 * This function returns the current VDD IO voltage level.
2610 * Returns negative value if it fails to read the voltage level
2611 * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
2612 * regulator were not defined for host.
2613 */
2614static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
2615{
2616 int rc = 0;
2617
2618 if (host->plat->vreg_data) {
2619 struct msm_mmc_reg_data *io_reg =
2620 host->plat->vreg_data->vdd_io_data;
2621
2622 /*
2623 * If vdd_io is not defined, then we can consider that
2624 * IO voltage is same as VDD.
2625 */
2626 if (!io_reg)
2627 io_reg = host->plat->vreg_data->vdd_data;
2628
2629 if (io_reg && io_reg->is_enabled)
2630 rc = msmsdcc_vreg_get_voltage(io_reg);
2631 }
2632
2633 return rc;
2634}
2635
2636/*
2637 * This function updates the IO pad power switch bit in MCI_CLK register
2638 * based on currrent IO pad voltage level.
2639 * NOTE: This function assumes that host lock was not taken by caller.
2640 */
2641static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
2642{
2643 int rc = 0;
2644 unsigned long flags;
2645
2646 if (!is_io_pad_pwr_switch(host))
2647 return;
2648
2649 rc = msmsdcc_get_vdd_io_vol(host);
2650
2651 spin_lock_irqsave(&host->lock, flags);
2652 /*
2653 * Dual voltage pad is the SDCC's (chipset) functionality and not all
2654 * the SDCC instances support the dual voltage pads.
2655 * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
2656 * bit before using the pads in 1.8V mode.
2657 * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
2658 * IO_PAD_PWR_SWITCH bit is a don't care.
2659 * But we don't have an option to know (by reading some SDCC register)
2660 * that a particular SDCC instance supports dual voltage pads or not,
2661 * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
2662 * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
2663 * is anyway ignored.
2664 */
2665 if (rc > 0 && rc < 2700000)
2666 host->io_pad_pwr_switch = 1;
2667 else
2668 host->io_pad_pwr_switch = 0;
2669
2670 if (atomic_read(&host->clks_on)) {
2671 if (host->io_pad_pwr_switch)
2672 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2673 IO_PAD_PWR_SWITCH),
2674 host->base + MMCICLOCK);
2675 else
2676 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
2677 ~IO_PAD_PWR_SWITCH),
2678 host->base + MMCICLOCK);
2679 msmsdcc_sync_reg_wr(host);
2680 }
2681 spin_unlock_irqrestore(&host->lock, flags);
2682}
2683
Subhash Jadavani937c7502012-06-01 15:34:46 +05302684static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2685 enum vdd_io_level level,
2686 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687{
2688 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302689 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690
2691 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302692 struct msm_mmc_reg_data *vdd_io_reg =
2693 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694
Subhash Jadavani937c7502012-06-01 15:34:46 +05302695 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2696 switch (level) {
2697 case VDD_IO_LOW:
2698 set_level = vdd_io_reg->low_vol_level;
2699 break;
2700 case VDD_IO_HIGH:
2701 set_level = vdd_io_reg->high_vol_level;
2702 break;
2703 case VDD_IO_SET_LEVEL:
2704 set_level = voltage_level;
2705 break;
2706 default:
2707 pr_err("%s: %s: invalid argument level = %d",
2708 mmc_hostname(host->mmc), __func__,
2709 level);
2710 rc = -EINVAL;
2711 goto out;
2712 }
2713 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2714 set_level, set_level);
2715 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 }
2717
Subhash Jadavani937c7502012-06-01 15:34:46 +05302718out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302719 return rc;
2720}
2721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2723{
2724 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2725 return 1;
2726 return 0;
2727}
2728
Asutosh Dasf5298c32012-04-03 14:51:47 +05302729/*
2730 * Any function calling msmsdcc_setup_clocks must
2731 * acquire clk_mutex. May sleep.
2732 */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302733static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734{
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302735 int rc = 0;
2736
2737 if (enable && !atomic_read(&host->clks_on)) {
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302738 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &host->mmc->ios);
2739
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302740 if (!IS_ERR_OR_NULL(host->bus_clk)) {
2741 rc = clk_prepare_enable(host->bus_clk);
2742 if (rc) {
2743 pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
2744 mmc_hostname(host->mmc), __func__, rc);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302745 goto remove_vote;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302746 }
2747 }
2748 if (!IS_ERR(host->pclk)) {
2749 rc = clk_prepare_enable(host->pclk);
2750 if (rc) {
2751 pr_err("%s: %s: failed to enable the pclk with error %d\n",
2752 mmc_hostname(host->mmc), __func__, rc);
2753 goto disable_bus;
2754 }
2755 }
2756 rc = clk_prepare_enable(host->clk);
2757 if (rc) {
2758 pr_err("%s: %s: failed to enable the host-clk with error %d\n",
2759 mmc_hostname(host->mmc), __func__, rc);
2760 goto disable_pclk;
2761 }
Subhash Jadavanidd432952012-03-28 11:25:56 +05302762 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302763 msmsdcc_delay(host);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302764 atomic_set(&host->clks_on, 1);
2765 } else if (!enable && atomic_read(&host->clks_on)) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302766 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302767 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302768 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302770 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302771 if (!IS_ERR_OR_NULL(host->bus_clk))
2772 clk_disable_unprepare(host->bus_clk);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302773
2774 /*
2775 * If clock gating is enabled, then remove the vote
2776 * immediately because clocks will be disabled only
2777 * after MSM_MMC_CLK_GATE_DELAY and thus no additional
2778 * delay is required to remove the bus vote.
2779 */
2780 if (host->mmc->clkgate_delay)
2781 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
2782 else
2783 msmsdcc_msm_bus_queue_work(host);
2784
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302785 atomic_set(&host->clks_on, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302787 goto out;
2788
2789disable_pclk:
2790 if (!IS_ERR_OR_NULL(host->pclk))
2791 clk_disable_unprepare(host->pclk);
2792disable_bus:
2793 if (!IS_ERR_OR_NULL(host->bus_clk))
2794 clk_disable_unprepare(host->bus_clk);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05302795remove_vote:
2796 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05302797out:
2798 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799}
2800
2801static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2802 unsigned int req_clk)
2803{
2804 unsigned int sel_clk = -1;
2805
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302806 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2807 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2808 goto out;
2809 }
2810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2812 unsigned char cnt;
2813
2814 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2815 if (host->plat->sup_clk_table[cnt] > req_clk)
2816 break;
2817 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2818 sel_clk = host->plat->sup_clk_table[cnt];
2819 break;
2820 } else
2821 sel_clk = host->plat->sup_clk_table[cnt];
2822 }
2823 } else {
2824 if ((req_clk < host->plat->msmsdcc_fmax) &&
2825 (req_clk > host->plat->msmsdcc_fmid))
2826 sel_clk = host->plat->msmsdcc_fmid;
2827 else
2828 sel_clk = req_clk;
2829 }
2830
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302831out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832 return sel_clk;
2833}
2834
2835static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2836 struct msmsdcc_host *host)
2837{
2838 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2839 return host->plat->sup_clk_table[0];
2840 else
2841 return host->plat->msmsdcc_fmin;
2842}
2843
2844static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2845 struct msmsdcc_host *host)
2846{
2847 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2848 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2849 else
2850 return host->plat->msmsdcc_fmax;
2851}
2852
2853static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302854{
2855 struct msm_mmc_gpio_data *curr;
2856 int i, rc = 0;
2857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302859 for (i = 0; i < curr->size; i++) {
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302860 if (!gpio_is_valid(curr->gpio[i].no)) {
2861 rc = -EINVAL;
2862 pr_err("%s: Invalid gpio = %d\n",
2863 mmc_hostname(host->mmc), curr->gpio[i].no);
2864 goto free_gpios;
2865 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302866 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 if (curr->gpio[i].is_always_on &&
2868 curr->gpio[i].is_enabled)
2869 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302870 rc = gpio_request(curr->gpio[i].no,
2871 curr->gpio[i].name);
2872 if (rc) {
2873 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2874 mmc_hostname(host->mmc),
2875 curr->gpio[i].no,
2876 curr->gpio[i].name, rc);
2877 goto free_gpios;
2878 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302880 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002881 if (curr->gpio[i].is_always_on)
2882 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302883 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302885 }
2886 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002887 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302888
2889free_gpios:
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05302890 for (i--; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302891 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 curr->gpio[i].is_enabled = false;
2893 }
2894out:
2895 return rc;
2896}
2897
2898static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2899{
2900 struct msm_mmc_pad_data *curr;
2901 int i;
2902
2903 curr = host->plat->pin_data->pad_data;
2904 for (i = 0; i < curr->drv->size; i++) {
2905 if (enable)
2906 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2907 curr->drv->on[i].val);
2908 else
2909 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2910 curr->drv->off[i].val);
2911 }
2912
2913 for (i = 0; i < curr->pull->size; i++) {
2914 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002915 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916 curr->pull->on[i].val);
2917 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002918 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002919 curr->pull->off[i].val);
2920 }
2921
2922 return 0;
2923}
2924
2925static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2926{
2927 int rc = 0;
2928
2929 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2930 return 0;
2931
2932 if (host->plat->pin_data->is_gpio)
2933 rc = msmsdcc_setup_gpio(host, enable);
2934 else
2935 rc = msmsdcc_setup_pad(host, enable);
2936
2937 if (!rc)
2938 host->plat->pin_data->cfg_sts = enable;
2939
2940 return rc;
2941}
2942
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302943static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2944 unsigned mode)
2945{
2946 int ret = 0;
2947 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2948
2949 if (!pin)
2950 return 0;
2951
2952 switch (mode) {
2953 case SDC_DAT1_DISABLE:
2954 ret = msm_mpm_enable_pin(pin, 0);
2955 break;
2956 case SDC_DAT1_ENABLE:
2957 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2958 ret = msm_mpm_enable_pin(pin, 1);
2959 break;
2960 case SDC_DAT1_ENWAKE:
2961 ret = msm_mpm_set_pin_wake(pin, 1);
2962 break;
2963 case SDC_DAT1_DISWAKE:
2964 ret = msm_mpm_set_pin_wake(pin, 0);
2965 break;
2966 default:
2967 ret = -EINVAL;
2968 break;
2969 }
2970
2971 return ret;
2972}
2973
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302974static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2975{
2976 u32 pwr = 0;
2977 int ret = 0;
2978 struct mmc_host *mmc = host->mmc;
2979
2980 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2981 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2982 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
Krishna Konda3c4142d2012-06-27 11:01:56 -07002983 ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302984
2985 if (ret) {
2986 pr_err("%s: Failed to setup voltage regulators\n",
2987 mmc_hostname(host->mmc));
2988 goto out;
2989 }
2990
2991 switch (ios->power_mode) {
2992 case MMC_POWER_OFF:
2993 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302994 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302995 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302996 * If VDD IO rail is always on, set low voltage for VDD
2997 * IO rail when slot is not in use (like when card is not
2998 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302999 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303000 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303001 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303002 msmsdcc_setup_pins(host, false);
Pratibhasagar Va3f8f792012-09-20 19:46:11 +05303003 /*
3004 * Reset the mask to prevent hitting any pending interrupts
3005 * after powering up the card again.
3006 */
3007 if (atomic_read(&host->clks_on)) {
3008 writel_relaxed(0, host->base + MMCIMASK0);
3009 mb();
3010 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303011 break;
3012 case MMC_POWER_UP:
3013 /* writing PWR_UP bit is redundant */
3014 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303015 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303016
Subhash Jadavani937c7502012-06-01 15:34:46 +05303017 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303018 msmsdcc_update_io_pad_pwr_switch(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303019 msmsdcc_setup_pins(host, true);
3020 break;
3021 case MMC_POWER_ON:
3022 pwr = MCI_PWR_ON;
3023 break;
3024 }
3025
3026out:
3027 return pwr;
3028}
3029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
3031{
3032 unsigned int wakeup_irq;
3033
3034 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3035 host->plat->sdiowakeup_irq :
3036 host->core_irqres->start;
3037
3038 if (!host->irq_wake_enabled) {
3039 enable_irq_wake(wakeup_irq);
3040 host->irq_wake_enabled = true;
3041 }
3042}
3043
3044static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
3045{
3046 unsigned int wakeup_irq;
3047
3048 wakeup_irq = (host->plat->sdiowakeup_irq) ?
3049 host->plat->sdiowakeup_irq :
3050 host->core_irqres->start;
3051
3052 if (host->irq_wake_enabled) {
3053 disable_irq_wake(wakeup_irq);
3054 host->irq_wake_enabled = false;
3055 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05303056}
3057
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303058/* Returns required bandwidth in Bytes per Sec */
3059static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
3060 struct mmc_ios *ios)
3061{
3062 unsigned int bw;
3063
3064 bw = host->clk_rate;
3065 /*
3066 * For DDR mode, SDCC controller clock will be at
3067 * the double rate than the actual clock that goes to card.
3068 */
3069 if (ios->bus_width == MMC_BUS_WIDTH_4)
3070 bw /= 2;
3071 else if (ios->bus_width == MMC_BUS_WIDTH_1)
3072 bw /= 8;
3073
3074 return bw;
3075}
3076
3077static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
3078 unsigned int bw)
3079{
3080 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
3081 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
3082 int i;
3083
3084 if (host->msm_bus_vote.is_max_bw_needed && bw)
3085 return host->msm_bus_vote.max_bw_vote;
3086
3087 for (i = 0; i < size; i++) {
3088 if (bw <= table[i])
3089 break;
3090 }
3091
3092 if (i && (i == size))
3093 i--;
3094
3095 return i;
3096}
3097
3098static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
3099{
3100 int rc = 0;
3101 struct msm_bus_scale_pdata *use_cases;
3102
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303103 if (host->pdev->dev.of_node) {
3104 struct msm_mmc_bus_voting_data *data;
3105 struct device *dev = &host->pdev->dev;
3106
3107 data = devm_kzalloc(dev,
3108 sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
3109 if (!data) {
3110 dev_err(&host->pdev->dev,
3111 "%s: failed to allocate memory\n", __func__);
3112 rc = -ENOMEM;
3113 goto out;
3114 }
3115
3116 rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
3117 &data->bw_vecs, &data->bw_vecs_size, 0);
3118 if (!rc) {
3119 data->use_cases = msm_bus_cl_get_pdata(host->pdev);
3120 host->plat->msm_bus_voting_data = data;
3121 }
3122 }
3123
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303124 if (host->plat->msm_bus_voting_data &&
3125 host->plat->msm_bus_voting_data->use_cases &&
3126 host->plat->msm_bus_voting_data->bw_vecs &&
3127 host->plat->msm_bus_voting_data->bw_vecs_size) {
3128 use_cases = host->plat->msm_bus_voting_data->use_cases;
3129 host->msm_bus_vote.client_handle =
3130 msm_bus_scale_register_client(use_cases);
3131 } else {
3132 return 0;
3133 }
3134
3135 if (!host->msm_bus_vote.client_handle) {
3136 pr_err("%s: msm_bus_scale_register_client() failed\n",
3137 mmc_hostname(host->mmc));
3138 rc = -EFAULT;
3139 } else {
3140 /* cache the vote index for minimum and maximum bandwidth */
3141 host->msm_bus_vote.min_bw_vote =
3142 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
3143 host->msm_bus_vote.max_bw_vote =
3144 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
3145 }
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05303146out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303147 return rc;
3148}
3149
3150static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
3151{
3152 if (host->msm_bus_vote.client_handle)
3153 msm_bus_scale_unregister_client(
3154 host->msm_bus_vote.client_handle);
3155}
3156
3157/*
3158 * This function must be called with host lock acquired.
3159 * Caller of this function should also ensure that msm bus client
3160 * handle is not null.
3161 */
3162static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
3163 int vote,
3164 unsigned long flags)
3165{
3166 int rc = 0;
3167
3168 if (vote != host->msm_bus_vote.curr_vote) {
3169 spin_unlock_irqrestore(&host->lock, flags);
3170 rc = msm_bus_scale_client_update_request(
3171 host->msm_bus_vote.client_handle, vote);
3172 if (rc)
3173 pr_err("%s: msm_bus_scale_client_update_request() failed."
3174 " bus_client_handle=0x%x, vote=%d, err=%d\n",
3175 mmc_hostname(host->mmc),
3176 host->msm_bus_vote.client_handle, vote, rc);
3177 spin_lock_irqsave(&host->lock, flags);
3178 if (!rc)
3179 host->msm_bus_vote.curr_vote = vote;
3180 }
3181
3182 return rc;
3183}
3184
3185/*
3186 * Internal work. Work to set 0 bandwidth for msm bus.
3187 */
3188static void msmsdcc_msm_bus_work(struct work_struct *work)
3189{
3190 struct msmsdcc_host *host = container_of(work,
3191 struct msmsdcc_host,
3192 msm_bus_vote.vote_work.work);
3193 unsigned long flags;
3194
3195 if (!host->msm_bus_vote.client_handle)
3196 return;
3197
3198 spin_lock_irqsave(&host->lock, flags);
3199 /* don't vote for 0 bandwidth if any request is in progress */
3200 if (!host->curr.mrq)
3201 msmsdcc_msm_bus_set_vote(host,
3202 host->msm_bus_vote.min_bw_vote, flags);
3203 else
3204 pr_warning("%s: %s: SDCC transfer in progress. skipping"
3205 " bus voting to 0 bandwidth\n",
3206 mmc_hostname(host->mmc), __func__);
3207 spin_unlock_irqrestore(&host->lock, flags);
3208}
3209
3210/*
3211 * This function cancels any scheduled delayed work
3212 * and sets the bus vote based on ios argument.
3213 * If "ios" argument is NULL, bandwidth required is 0 else
3214 * calculate the bandwidth based on ios parameters.
3215 */
3216static void msmsdcc_msm_bus_cancel_work_and_set_vote(
3217 struct msmsdcc_host *host,
3218 struct mmc_ios *ios)
3219{
3220 unsigned long flags;
3221 unsigned int bw;
3222 int vote;
3223
3224 if (!host->msm_bus_vote.client_handle)
3225 return;
3226
3227 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
3228
3229 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
3230 spin_lock_irqsave(&host->lock, flags);
3231 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
3232 msmsdcc_msm_bus_set_vote(host, vote, flags);
3233 spin_unlock_irqrestore(&host->lock, flags);
3234}
3235
3236/* This function queues a work which will set the bandwidth requiement to 0 */
3237static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
3238{
3239 unsigned long flags;
3240
3241 if (!host->msm_bus_vote.client_handle)
3242 return;
3243
3244 spin_lock_irqsave(&host->lock, flags);
3245 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
3246 queue_delayed_work(system_nrt_wq,
3247 &host->msm_bus_vote.vote_work,
3248 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
3249 spin_unlock_irqrestore(&host->lock, flags);
3250}
3251
San Mehat9d2bd732009-09-22 16:44:22 -07003252static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303253msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
3254{
3255 struct mmc_host *mmc = host->mmc;
3256
3257 /*
3258 * SDIO_AL clients has different mechanism of handling LPM through
3259 * sdio_al driver itself. The sdio wakeup interrupt is configured as
3260 * part of that. Here, we are interested only in clients like WLAN.
3261 */
3262 if (!(mmc->card && mmc_card_sdio(mmc->card))
3263 || host->plat->is_sdio_al_client)
3264 goto out;
3265
3266 if (!host->sdcc_suspended) {
3267 /*
3268 * When MSM is not in power collapse and we
3269 * are disabling clocks, enable bit 22 in MASK0
3270 * to handle asynchronous SDIO interrupts.
3271 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303272 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303273 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303274 mb();
3275 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303276 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303277 msmsdcc_sync_reg_wr(host);
3278 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303279 goto out;
3280 } else if (!mmc_card_wake_sdio_irq(mmc)) {
3281 /*
3282 * Wakeup MSM only if SDIO function drivers set
3283 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
3284 */
3285 goto out;
3286 }
3287
3288 if (enable_wakeup_irq) {
3289 if (!host->plat->sdiowakeup_irq) {
3290 /*
3291 * When there is no gpio line that can be configured
3292 * as wakeup interrupt handle it by configuring
3293 * asynchronous sdio interrupts and DAT1 line.
3294 */
3295 writel_relaxed(MCI_SDIOINTMASK,
3296 host->base + MMCIMASK0);
3297 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303298 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303299 /* configure sdcc core interrupt as wakeup interrupt */
3300 msmsdcc_enable_irq_wake(host);
3301 } else {
3302 /* Let gpio line handle wakeup interrupt */
3303 writel_relaxed(0, host->base + MMCIMASK0);
3304 mb();
3305 if (host->sdio_wakeupirq_disabled) {
3306 host->sdio_wakeupirq_disabled = 0;
3307 /* configure gpio line as wakeup interrupt */
3308 msmsdcc_enable_irq_wake(host);
3309 enable_irq(host->plat->sdiowakeup_irq);
3310 }
3311 }
3312 } else {
3313 if (!host->plat->sdiowakeup_irq) {
3314 /*
3315 * We may not have cleared bit 22 in the interrupt
3316 * handler as the clocks might be off at that time.
3317 */
3318 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303319 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05303320 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303321 msmsdcc_disable_irq_wake(host);
3322 } else if (!host->sdio_wakeupirq_disabled) {
3323 disable_irq_nosync(host->plat->sdiowakeup_irq);
3324 msmsdcc_disable_irq_wake(host);
3325 host->sdio_wakeupirq_disabled = 1;
3326 }
3327 }
3328out:
3329 return;
San Mehat9d2bd732009-09-22 16:44:22 -07003330}
3331
3332static void
3333msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3334{
3335 struct msmsdcc_host *host = mmc_priv(mmc);
3336 u32 clk = 0, pwr = 0;
3337 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08003338 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07003340
Sahitya Tummala7a892482011-01-18 11:22:49 +05303341
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303342 /*
3343 * Disable SDCC core interrupt until set_ios is completed.
3344 * This avoids any race conditions with interrupt raised
3345 * when turning on/off the clocks. One possible
3346 * scenario is SDIO operational interrupt while the clock
3347 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05303348 * host->lock is being released intermittently below.
3349 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303350 */
3351
Asutosh Dasf5298c32012-04-03 14:51:47 +05303352 mutex_lock(&host->clk_mutex);
3353 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07003354 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303355 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303356 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303357 host->sdcc_irq_disabled = 1;
3358 }
San Mehatd0719e52009-12-03 10:58:54 -08003359 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003360
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05303361 /* Make sure sdcc core irq is synchronized */
3362 synchronize_irq(host->core_irqres->start);
3363
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303364 pwr = msmsdcc_setup_pwr(host, ios);
3365
3366 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07003367 if (ios->clock) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303368 spin_unlock_irqrestore(&host->lock, flags);
3369 rc = msmsdcc_setup_clocks(host, true);
3370 if (rc)
3371 goto out;
3372 spin_lock_irqsave(&host->lock, flags);
3373 writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
3374 mb();
3375 msmsdcc_cfg_sdio_wakeup(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 /*
3379 * For DDR50 mode, controller needs clock rate to be
3380 * double than what is required on the SD card CLK pin.
Subhash Jadavani2877d912012-10-09 20:01:56 +05303381 *
3382 * Setting DDR timing mode in controller before setting the
3383 * clock rate will make sure that card don't see the double
3384 * clock rate even for very small duration. Some eMMC
3385 * cards seems to lock up if they see clock frequency > 52MHz.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303387 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Subhash Jadavani2877d912012-10-09 20:01:56 +05303388 u32 clk;
3389
3390 clk = readl_relaxed(host->base + MMCICLOCK);
3391 clk &= ~(0x7 << 14); /* clear SELECT_IN field */
3392 clk |= (3 << 14); /* set DDR timing mode */
3393 writel_relaxed(clk, host->base + MMCICLOCK);
3394 msmsdcc_sync_reg_wr(host);
3395
Subhash Jadavani879856d2013-03-04 16:28:04 +05303396 clock = msmsdcc_get_sup_clk_rate(host, ios->clock * 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 }
3398
3399 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303400 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303402 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303404 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405 mmc_hostname(mmc), clock);
3406 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303407 host->reg_write_delay =
3408 (1 + ((3 * USEC_PER_SEC) /
3409 (host->clk_rate ? host->clk_rate :
3410 msmsdcc_get_min_sup_clk_rate(host))));
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05303411 spin_unlock_irqrestore(&host->lock, flags);
3412 /*
3413 * Update bus vote incase of frequency change due to
3414 * clock scaling.
3415 */
3416 msmsdcc_msm_bus_cancel_work_and_set_vote(host,
3417 &mmc->ios);
3418 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003419 }
3420 /*
3421 * give atleast 2 MCLK cycles delay for clocks
3422 * and SDCC core to stabilize
3423 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05303424 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003425 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003426 clk |= MCI_CLK_ENABLE;
3427 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 if (ios->bus_width == MMC_BUS_WIDTH_8)
3429 clk |= MCI_CLK_WIDEBUS_8;
3430 else if (ios->bus_width == MMC_BUS_WIDTH_4)
3431 clk |= MCI_CLK_WIDEBUS_4;
3432 else
3433 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07003434
Subhash Jadavani568907c2013-05-27 16:37:52 +05303435 if (msmsdcc_is_pwrsave(host) && mmc_host_may_gate_card(host->mmc->card))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07003437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07003439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 host->tuning_needed = 0;
3441 /*
3442 * Select the controller timing mode according
3443 * to current bus speed mode
3444 */
Subhash Jadavanif97d2992012-07-13 14:47:47 +05303445 if (host->clk_rate > (100 * 1000 * 1000) &&
3446 (ios->timing == MMC_TIMING_UHS_SDR104 ||
3447 ios->timing == MMC_TIMING_MMC_HS200)) {
3448 /* Card clock frequency must be > 100MHz to enable tuning */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449 clk |= (4 << 14);
3450 host->tuning_needed = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451 } else {
Subhash Jadavani355df542012-10-09 19:06:49 +05303452 if (ios->timing == MMC_TIMING_UHS_DDR50)
3453 clk |= (3 << 14);
3454 else
3455 clk |= (2 << 14); /* feedback clock */
3456
3457 host->tuning_done = false;
3458 if (atomic_read(&host->clks_on)) {
3459 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3460 writel_relaxed((readl_relaxed(host->base +
3461 MCI_DLL_CONFIG) | MCI_DLL_RST),
3462 host->base + MCI_DLL_CONFIG);
3463
3464 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3465 writel_relaxed((readl_relaxed(host->base +
3466 MCI_DLL_CONFIG) | MCI_DLL_PDN),
3467 host->base + MCI_DLL_CONFIG);
3468 }
San Mehat9d2bd732009-09-22 16:44:22 -07003469 }
3470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3472 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07003473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 if (host->io_pad_pwr_switch)
3475 clk |= IO_PAD_PWR_SWITCH;
3476
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303477 /* Don't write into registers if clocks are disabled */
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303478 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303479 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3480 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303481 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303483 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3484 host->pwr = pwr;
3485 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303486 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 }
San Mehat9d2bd732009-09-22 16:44:22 -07003488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303490 if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303491 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303492 spin_unlock_irqrestore(&host->lock, flags);
3493 /*
3494 * May get a wake-up interrupt the instant we disable the
3495 * clocks. This would disable the wake-up interrupt.
3496 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303498 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303500
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303501 if (host->tuning_in_progress)
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303502 WARN(!atomic_read(&host->clks_on),
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303503 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303504
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303505 /* Let interrupts be disabled if the host is powered off */
3506 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3507 enable_irq(host->core_irqres->start);
3508 host->sdcc_irq_disabled = 0;
3509 }
San Mehat4adbbcc2009-11-08 13:00:37 -08003510 spin_unlock_irqrestore(&host->lock, flags);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303511out:
Asutosh Dasf5298c32012-04-03 14:51:47 +05303512 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003513}
3514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3516{
3517 struct msmsdcc_host *host = mmc_priv(mmc);
3518 u32 clk;
3519
3520 clk = readl_relaxed(host->base + MMCICLOCK);
3521 pr_debug("Changing to pwr_save=%d", pwrsave);
3522 if (pwrsave && msmsdcc_is_pwrsave(host))
3523 clk |= MCI_CLK_PWRSAVE;
3524 else
3525 clk &= ~MCI_CLK_PWRSAVE;
3526 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303527 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003528
3529 return 0;
3530}
3531
3532static int msmsdcc_get_ro(struct mmc_host *mmc)
3533{
3534 int status = -ENOSYS;
3535 struct msmsdcc_host *host = mmc_priv(mmc);
3536
3537 if (host->plat->wpswitch) {
3538 status = host->plat->wpswitch(mmc_dev(mmc));
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05303539 } else if (gpio_is_valid(host->plat->wpswitch_gpio)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003540 status = gpio_request(host->plat->wpswitch_gpio,
3541 "SD_WP_Switch");
3542 if (status) {
3543 pr_err("%s: %s: Failed to request GPIO %d\n",
3544 mmc_hostname(mmc), __func__,
3545 host->plat->wpswitch_gpio);
3546 } else {
3547 status = gpio_direction_input(
3548 host->plat->wpswitch_gpio);
3549 if (!status) {
3550 /*
3551 * Wait for atleast 300ms as debounce
3552 * time for GPIO input to stabilize.
3553 */
3554 msleep(300);
3555 status = gpio_get_value_cansleep(
3556 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303557 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003558 }
3559 gpio_free(host->plat->wpswitch_gpio);
3560 }
3561 }
3562
3563 if (status < 0)
3564 status = -ENOSYS;
3565 pr_debug("%s: Card read-only status %d\n", __func__, status);
3566
3567 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003568}
3569
3570static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3571{
3572 struct msmsdcc_host *host = mmc_priv(mmc);
3573 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303575 /*
3576 * We may come here with clocks turned off in that case don't
3577 * attempt to write into MASK0 register. While turning on the
3578 * clocks mci_irqenable will be written to MASK0 register.
3579 */
San Mehat9d2bd732009-09-22 16:44:22 -07003580
3581 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003582 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003583 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303584 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303585 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303587 mb();
3588 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003589 } else {
3590 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303591 if (atomic_read(&host->clks_on)) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303592 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303594 mb();
3595 }
San Mehat9d2bd732009-09-22 16:44:22 -07003596 }
3597 spin_unlock_irqrestore(&host->lock, flags);
3598}
3599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303601static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003602{
subhashj245831e2012-04-30 18:46:17 +05303603 struct device *dev = mmc_dev(host->mmc);
3604
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303605 pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
Subhash Jadavani386ad802012-08-16 18:46:57 +05303606 mmc_hostname(host->mmc), host->sdcc_suspended,
3607 host->pending_resume, host->sdcc_suspending);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05303608 pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
subhashj245831e2012-04-30 18:46:17 +05303609 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3610 " request_pending=%d, request=%d\n",
3611 mmc_hostname(host->mmc), dev->power.runtime_status,
3612 atomic_read(&dev->power.usage_count),
3613 dev->power.is_suspended, dev->power.disable_depth,
3614 dev->power.runtime_error, dev->power.request_pending,
3615 dev->power.request);
3616}
3617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618static int msmsdcc_enable(struct mmc_host *mmc)
3619{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003620 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003621 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003622 struct msmsdcc_host *host = mmc_priv(mmc);
3623
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303624 msmsdcc_pm_qos_update_latency(host, 1);
3625
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003626 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303627 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628
Subhash Jadavani386ad802012-08-16 18:46:57 +05303629 if (host->sdcc_suspended && host->pending_resume) {
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003630 host->pending_resume = false;
3631 pm_runtime_get_noresume(dev);
3632 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303633 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003634 }
3635
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303636 if (dev->power.runtime_status == RPM_SUSPENDING) {
3637 if (mmc->suspend_task == current) {
3638 pm_runtime_get_noresume(dev);
3639 goto out;
3640 }
Sujit Reddy Thumma112bd752012-06-20 12:29:45 +05303641 } else if (dev->power.runtime_status == RPM_RESUMING) {
3642 pm_runtime_get_noresume(dev);
3643 goto out;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303644 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003645
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303646 rc = pm_runtime_get_sync(dev);
3647
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303648skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303649 if (rc < 0) {
Subhash Jadavani386ad802012-08-16 18:46:57 +05303650 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3651 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303652 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303653 return rc;
3654 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303655out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303656 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003657}
3658
Steve Mucklef132c6c2012-06-06 18:30:57 -07003659static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660{
3661 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303662 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303664 msmsdcc_pm_qos_update_latency(host, 0);
3665
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303666 if (mmc->card && mmc_card_sdio(mmc->card)) {
3667 rc = 0;
3668 goto out;
3669 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303670
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303671 if (host->plat->disable_runtime_pm)
3672 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003673
3674 rc = pm_runtime_put_sync(mmc->parent);
3675
Subhash Jadavani386ad802012-08-16 18:46:57 +05303676 if (rc < 0) {
3677 WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
3678 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303679 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003680 return rc;
3681 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303682
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303683out:
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303684 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003685}
3686#else
subhashj245831e2012-04-30 18:46:17 +05303687static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3688
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303689static int msmsdcc_enable(struct mmc_host *mmc)
3690{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003691 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303692 struct msmsdcc_host *host = mmc_priv(mmc);
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303693 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303694
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303695 msmsdcc_pm_qos_update_latency(host, 1);
3696
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303697 if (mmc->card && mmc_card_sdio(mmc->card)) {
3698 rc = 0;
3699 goto out;
3700 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003701
3702 if (host->sdcc_suspended && host->pending_resume) {
3703 host->pending_resume = false;
3704 rc = msmsdcc_runtime_resume(dev);
3705 goto out;
3706 }
3707
Asutosh Dasf5298c32012-04-03 14:51:47 +05303708 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303709 rc = msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303710 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303711
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003712out:
3713 if (rc < 0) {
3714 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3715 __func__, rc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303716 msmsdcc_pm_qos_update_latency(host, 0);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003717 return rc;
3718 }
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303719 return 0;
3720}
3721
Steve Mucklef132c6c2012-06-06 18:30:57 -07003722static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303723{
3724 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303725 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303726
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303727 msmsdcc_pm_qos_update_latency(host, 0);
3728
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303729 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303730 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303731
Asutosh Dasf5298c32012-04-03 14:51:47 +05303732 mutex_lock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303733 rc = msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303734 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303735
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303736 if (rc) {
3737 msmsdcc_pm_qos_update_latency(host, 1);
3738 return rc;
3739 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303740out:
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05303741 return rc;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303742}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743#endif
3744
Subhash Jadavani937c7502012-06-01 15:34:46 +05303745static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3746 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747{
3748 struct msmsdcc_host *host = mmc_priv(mmc);
3749 unsigned long flags;
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303750 bool prev_pwrsave, curr_pwrsave;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303751 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752
Subhash Jadavani937c7502012-06-01 15:34:46 +05303753 switch (ios->signal_voltage) {
3754 case MMC_SIGNAL_VOLTAGE_330:
3755 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3756 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303757 if (!rc)
3758 msmsdcc_update_io_pad_pwr_switch(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303759 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303760 case MMC_SIGNAL_VOLTAGE_180:
3761 break;
3762 case MMC_SIGNAL_VOLTAGE_120:
3763 /*
3764 * For eMMC cards, VDD_IO voltage range must be changed
3765 * only if it operates in HS200 SDR 1.2V mode or in
3766 * DDR 1.2V mode.
3767 */
3768 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303769 if (!rc)
3770 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303772 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303774 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 goto out;
3776 }
San Mehat9d2bd732009-09-22 16:44:22 -07003777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 /*
3779 * If we are here means voltage switch from high voltage to
3780 * low voltage is required
3781 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303782 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303783 prev_pwrsave = !!(readl_relaxed(host->base + MMCICLOCK) &
3784 MCI_CLK_PWRSAVE);
3785 curr_pwrsave = prev_pwrsave;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003786 /*
3787 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3788 * register until they become all zeros.
3789 */
3790 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303791 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003792 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3793 mmc_hostname(mmc), __func__);
3794 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003795 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003796
3797 /* Stop SD CLK output. */
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303798 if (!prev_pwrsave) {
3799 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3800 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
3801 msmsdcc_sync_reg_wr(host);
3802 curr_pwrsave = true;
3803 }
San Mehat9d2bd732009-09-22 16:44:22 -07003804 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003805
3806 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303807 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3808 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303810 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303811 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813
Subhash Jadavani341b9e72012-08-11 18:11:57 +05303814 msmsdcc_update_io_pad_pwr_switch(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003815
3816 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3817 usleep_range(5000, 5500);
3818
3819 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303820 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3822 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303823 msmsdcc_sync_reg_wr(host);
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303824 curr_pwrsave = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 spin_unlock_irqrestore(&host->lock, flags);
3826
3827 /*
3828 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3829 * don't become all ones within 1 ms then a Voltage Switch
3830 * sequence has failed and a power cycle to the card is required.
3831 * Otherwise Voltage Switch sequence is completed successfully.
3832 */
3833 usleep_range(1000, 1500);
3834
3835 spin_lock_irqsave(&host->lock, flags);
3836 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3837 != (0xF << 1)) {
3838 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3839 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303840 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841 goto out_unlock;
3842 }
3843
3844out_unlock:
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303845 /* Restore the correct PWRSAVE state */
3846 if (prev_pwrsave ^ curr_pwrsave)
3847 msmsdcc_set_pwrsave(mmc, prev_pwrsave);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848 spin_unlock_irqrestore(&host->lock, flags);
3849out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303850 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003851}
3852
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303853static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856
3857 /* Program the MCLK value to MCLK_FREQ bit field */
3858 if (host->clk_rate <= 112000000)
3859 mclk_freq = 0;
3860 else if (host->clk_rate <= 125000000)
3861 mclk_freq = 1;
3862 else if (host->clk_rate <= 137000000)
3863 mclk_freq = 2;
3864 else if (host->clk_rate <= 150000000)
3865 mclk_freq = 3;
3866 else if (host->clk_rate <= 162000000)
3867 mclk_freq = 4;
3868 else if (host->clk_rate <= 175000000)
3869 mclk_freq = 5;
3870 else if (host->clk_rate <= 187000000)
3871 mclk_freq = 6;
3872 else if (host->clk_rate <= 200000000)
3873 mclk_freq = 7;
3874
3875 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3876 & ~(7 << 24)) | (mclk_freq << 24)),
3877 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878}
3879
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303880/* Initialize the DLL (Programmable Delay Line ) */
3881static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003882{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303884 unsigned long flags;
3885 u32 wait_cnt;
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303886 bool prev_pwrsave, curr_pwrsave;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003887
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303888 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303889 prev_pwrsave = !!(readl_relaxed(host->base + MMCICLOCK) &
3890 MCI_CLK_PWRSAVE);
3891 curr_pwrsave = prev_pwrsave;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 /*
3893 * Make sure that clock is always enabled when DLL
3894 * tuning is in progress. Keeping PWRSAVE ON may
3895 * turn off the clock. So let's disable the PWRSAVE
3896 * here and re-enable it once tuning is completed.
3897 */
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303898 if (prev_pwrsave) {
3899 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3900 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
3901 msmsdcc_sync_reg_wr(host);
3902 curr_pwrsave = false;
3903 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303904
3905 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3906 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3907 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3908
3909 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3910 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3911 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3912
3913 msmsdcc_cm_sdc4_dll_set_freq(host);
3914
3915 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3916 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3917 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3918
3919 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3920 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3921 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3922
3923 /* Set DLL_EN bit to 1. */
3924 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3925 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3926
3927 /* Set CK_OUT_EN bit to 1. */
3928 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3929 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3930
3931 wait_cnt = 50;
3932 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3933 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3934 /* max. wait for 50us sec for LOCK bit to be set */
3935 if (--wait_cnt == 0) {
3936 pr_err("%s: %s: DLL failed to LOCK\n",
3937 mmc_hostname(host->mmc), __func__);
3938 rc = -ETIMEDOUT;
3939 goto out;
3940 }
3941 /* wait for 1us before polling again */
3942 udelay(1);
3943 }
3944
3945out:
Subhash Jadavanice4834c2013-05-24 16:37:49 +05303946 /* Restore the correct PWRSAVE state */
3947 if (prev_pwrsave ^ curr_pwrsave)
3948 msmsdcc_set_pwrsave(host->mmc, prev_pwrsave);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303949 spin_unlock_irqrestore(&host->lock, flags);
3950
3951 return rc;
3952}
3953
3954static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3955 u8 poll)
3956{
3957 int rc = 0;
3958 u32 wait_cnt = 50;
3959 u8 ck_out_en = 0;
3960
3961 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3962 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3963 MCI_CK_OUT_EN);
3964
3965 while (ck_out_en != poll) {
3966 if (--wait_cnt == 0) {
3967 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3968 mmc_hostname(host->mmc), __func__, poll);
3969 rc = -ETIMEDOUT;
3970 goto out;
3971 }
3972 udelay(1);
3973
3974 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3975 MCI_CK_OUT_EN);
3976 }
3977out:
3978 return rc;
3979}
3980
3981/*
3982 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3983 * calibration sequence. This function should be called before
3984 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3985 * commands (CMD17/CMD18).
3986 *
3987 * This function gets called when host spinlock acquired.
3988 */
3989static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3990{
3991 int rc = 0;
3992 u32 config;
3993
3994 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3995 config |= MCI_CDR_EN;
3996 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3997 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3998
3999 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
4000 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
4001 if (rc)
4002 goto err_out;
4003
4004 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4005 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4006 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4007
4008 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4009 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4010 if (rc)
4011 goto err_out;
4012
4013 goto out;
4014
4015err_out:
4016 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
4017out:
4018 return rc;
4019}
4020
4021static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
4022 u8 phase)
4023{
4024 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05304025 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
4026 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
4027 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304028 unsigned long flags;
4029 u32 config;
4030
4031 spin_lock_irqsave(&host->lock, flags);
4032
4033 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4034 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
4035 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
4036 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4037
4038 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
4039 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
4040 if (rc)
4041 goto err_out;
4042
4043 /*
4044 * Write the selected DLL clock output phase (0 ... 15)
4045 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
4046 */
4047 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
4048 & ~(0xF << 20))
4049 | (grey_coded_phase_table[phase] << 20)),
4050 host->base + MCI_DLL_CONFIG);
4051
4052 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
4053 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
4054 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
4055
4056 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
4057 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
4058 if (rc)
4059 goto err_out;
4060
4061 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
4062 config |= MCI_CDR_EN;
4063 config &= ~MCI_CDR_EXT_EN;
4064 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
4065 goto out;
4066
4067err_out:
4068 pr_err("%s: %s: Failed to set DLL phase: %d\n",
4069 mmc_hostname(host->mmc), __func__, phase);
4070out:
4071 spin_unlock_irqrestore(&host->lock, flags);
4072 return rc;
4073}
4074
4075/*
4076 * Find out the greatest range of consecuitive selected
4077 * DLL clock output phases that can be used as sampling
4078 * setting for SD3.0 UHS-I card read operation (in SDR104
4079 * timing mode) or for eMMC4.5 card read operation (in HS200
4080 * timing mode).
4081 * Select the 3/4 of the range and configure the DLL with the
4082 * selected DLL clock output phase.
4083*/
Subhash Jadavani34187042012-03-02 10:59:49 +05304084static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304085 u8 *phase_table, u8 total_phases)
4086{
Subhash Jadavani6159c622012-03-15 19:05:55 +05304087 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05304088 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05304089 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
4090 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304091 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304092 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
4093 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304094
Subhash Jadavani6159c622012-03-15 19:05:55 +05304095 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304096 pr_err("%s: %s: invalid argument: total_phases=%d\n",
4097 mmc_hostname(host->mmc), __func__, total_phases);
4098 return -EINVAL;
4099 }
4100
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304101 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304102 ranges[row_index][col_index] = phase_table[cnt];
4103 phases_per_row[row_index] += 1;
4104 col_index++;
4105
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304106 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304107 continue;
4108 /* check if next phase in phase_table is consecutive or not */
4109 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
4110 row_index++;
4111 col_index = 0;
4112 }
4113 }
4114
Subhash Jadavani6159c622012-03-15 19:05:55 +05304115 if (row_index >= MAX_PHASES)
4116 return -EINVAL;
4117
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304118 /* Check if phase-0 is present in first valid window? */
4119 if (!ranges[0][0]) {
4120 phase_0_found = true;
4121 phase_0_raw_index = 0;
4122 /* Check if cycle exist between 2 valid windows */
4123 for (cnt = 1; cnt <= row_index; cnt++) {
4124 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05304125 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304126 if (ranges[cnt][i] == 15) {
4127 phase_15_found = true;
4128 phase_15_raw_index = cnt;
4129 break;
4130 }
4131 }
4132 }
4133 }
4134 }
4135
4136 /* If 2 valid windows form cycle then merge them as single window */
4137 if (phase_0_found && phase_15_found) {
4138 /* number of phases in raw where phase 0 is present */
4139 u8 phases_0 = phases_per_row[phase_0_raw_index];
4140 /* number of phases in raw where phase 15 is present */
4141 u8 phases_15 = phases_per_row[phase_15_raw_index];
4142
Subhash Jadavani6159c622012-03-15 19:05:55 +05304143 if (phases_0 + phases_15 >= MAX_PHASES)
4144 /*
4145 * If there are more than 1 phase windows then total
4146 * number of phases in both the windows should not be
4147 * more than or equal to MAX_PHASES.
4148 */
4149 return -EINVAL;
4150
4151 /* Merge 2 cyclic windows */
4152 i = phases_15;
4153 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304154 ranges[phase_15_raw_index][i] =
4155 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05304156 if (++i >= MAX_PHASES)
4157 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304158 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05304159
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304160 phases_per_row[phase_0_raw_index] = 0;
4161 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
4162 }
4163
4164 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304165 if (phases_per_row[cnt] > curr_max) {
4166 curr_max = phases_per_row[cnt];
4167 selected_row_index = cnt;
4168 }
4169 }
4170
Subhash Jadavani6159c622012-03-15 19:05:55 +05304171 i = ((curr_max * 3) / 4);
4172 if (i)
4173 i--;
4174
Subhash Jadavani34187042012-03-02 10:59:49 +05304175 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304176
Subhash Jadavani6159c622012-03-15 19:05:55 +05304177 if (ret >= MAX_PHASES) {
4178 ret = -EINVAL;
4179 pr_err("%s: %s: invalid phase selected=%d\n",
4180 mmc_hostname(host->mmc), __func__, ret);
4181 }
4182
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304183 return ret;
4184}
4185
Girish K Sa3f41692012-02-29 12:00:09 +05304186static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304187{
4188 int rc = 0;
4189 struct msmsdcc_host *host = mmc_priv(mmc);
4190 unsigned long flags;
4191 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304192 const u32 *tuning_block_pattern = tuning_block_64;
4193 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304194 bool is_tuning_all_phases;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304195
4196 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
4197
4198 /* Tuning is only required for SDR104 modes */
4199 if (!host->tuning_needed) {
4200 rc = 0;
4201 goto exit;
4202 }
4203
4204 spin_lock_irqsave(&host->lock, flags);
4205 WARN(!host->pwr, "SDCC power is turned off\n");
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05304206 WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304207 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
4208
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304209 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304210 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
4211 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
4212 tuning_block_pattern = tuning_block_128;
4213 size = sizeof(tuning_block_128);
4214 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304215 spin_unlock_irqrestore(&host->lock, flags);
4216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004217 /* first of all reset the tuning block */
4218 rc = msmsdcc_init_cm_sdc4_dll(host);
4219 if (rc)
4220 goto out;
4221
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304222 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 if (!data_buf) {
4224 rc = -ENOMEM;
4225 goto out;
4226 }
4227
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304228 is_tuning_all_phases = !(host->mmc->card &&
4229 (host->saved_tuning_phase != INVALID_TUNING_PHASE));
4230retry:
4231 if (is_tuning_all_phases)
4232 phase = 0; /* start from phase 0 during init */
4233 else
4234 phase = (u8)host->saved_tuning_phase;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 do {
4236 struct mmc_command cmd = {0};
4237 struct mmc_data data = {0};
4238 struct mmc_request mrq = {
4239 .cmd = &cmd,
4240 .data = &data
4241 };
4242 struct scatterlist sg;
4243
4244 /* set the phase in delay line hw block */
4245 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4246 if (rc)
4247 goto kfree;
4248
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304249 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004250 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
4251
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304252 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253 data.blocks = 1;
4254 data.flags = MMC_DATA_READ;
4255 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
4256
4257 data.sg = &sg;
4258 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304259 sg_init_one(&sg, data_buf, size);
4260 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261 mmc_wait_for_req(mmc, &mrq);
4262
4263 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304264 !memcmp(data_buf, tuning_block_pattern, size)) {
4265 /* tuning is successful at this tuning point */
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304266 if (!is_tuning_all_phases)
4267 goto kfree;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004268 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05304269 pr_debug("%s: %s: found good phase = %d\n",
4270 mmc_hostname(mmc), __func__, phase);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304271 } else if (!is_tuning_all_phases) {
4272 pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
4273 mmc_hostname(mmc), (u32)phase);
4274 is_tuning_all_phases = true;
4275 goto retry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004276 }
4277 } while (++phase < 16);
4278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004279 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05304280 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304281 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05304282 if (rc < 0)
4283 goto kfree;
4284 else
4285 phase = (u8)rc;
4286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287 /*
4288 * Finally set the selected phase in delay
4289 * line hw block.
4290 */
4291 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
4292 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304293 goto kfree;
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05304294 else
4295 host->saved_tuning_phase = phase;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304296 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
4297 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004298 } else {
4299 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304300 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004301 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304302 msmsdcc_dump_sdcc_state(host);
4303 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004305
4306kfree:
4307 kfree(data_buf);
4308out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304309 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304310 host->tuning_in_progress = 0;
Subhash Jadavani355df542012-10-09 19:06:49 +05304311 if (!rc)
4312 host->tuning_done = true;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05304313 spin_unlock_irqrestore(&host->lock, flags);
4314exit:
4315 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04004317}
4318
Asutosh Dasebd7d092012-07-09 19:08:26 +05304319/*
4320 * Work around of the unavailability of a power_reset functionality in SD cards
4321 * by turning the OFF & back ON the regulators supplying the SD card.
4322 */
4323void msmsdcc_hw_reset(struct mmc_host *mmc)
4324{
4325 struct mmc_card *card = mmc->card;
4326 struct msmsdcc_host *host = mmc_priv(mmc);
4327 int rc;
4328
4329 /* Write-protection bits would be lost on a hardware reset in emmc */
4330 if (!card || !mmc_card_sd(card))
4331 return;
4332
Pratibhasagar V1aa03dc2012-11-29 12:48:17 +05304333 pr_debug("%s: Starting h/w reset\n", mmc_hostname(host->mmc));
4334
4335 if (host->plat->translate_vdd || host->plat->vreg_data) {
4336
4337 /* Disable the regulators */
4338 if (host->plat->translate_vdd)
4339 rc = host->plat->translate_vdd(mmc_dev(mmc), 0);
4340 else if (host->plat->vreg_data)
4341 rc = msmsdcc_setup_vreg(host, false, false);
4342
4343 if (rc) {
4344 pr_err("%s: Failed to disable voltage regulator\n",
4345 mmc_hostname(host->mmc));
4346 BUG_ON(rc);
4347 }
4348
4349 /* 10ms delay for supply to reach the desired voltage level */
4350 usleep_range(10000, 12000);
4351
4352 /* Enable the regulators */
4353 if (host->plat->translate_vdd)
4354 rc = host->plat->translate_vdd(mmc_dev(mmc), 1);
4355 else if (host->plat->vreg_data)
4356 rc = msmsdcc_setup_vreg(host, true, false);
4357
4358 if (rc) {
4359 pr_err("%s: Failed to enable voltage regulator\n",
4360 mmc_hostname(host->mmc));
4361 BUG_ON(rc);
4362 }
4363
4364 /* 10ms delay for supply to reach the desired voltage level */
4365 usleep_range(10000, 12000);
Asutosh Dasebd7d092012-07-09 19:08:26 +05304366 }
Asutosh Dasebd7d092012-07-09 19:08:26 +05304367}
4368
Subhash Jadavanid076af72013-02-17 23:36:03 +02004369/**
4370 * msmsdcc_stop_request - stops ongoing request
4371 * @mmc: MMC host, running the request
4372 *
4373 * Stops currently running request synchronously. All relevant request
4374 * information is cleared.
4375 */
4376int msmsdcc_stop_request(struct mmc_host *mmc)
4377{
4378 struct msmsdcc_host *host = mmc_priv(mmc);
4379 struct mmc_request *mrq;
4380 unsigned long flags;
4381 int rc = 0;
4382
4383 spin_lock_irqsave(&host->lock, flags);
4384 mrq = host->curr.mrq;
4385 if (mrq) {
4386 msmsdcc_reset_and_restore(host);
4387 /*
4388 * Note: We are just taking care of SPS. We may also
4389 * need to think about ADM (and PIO?) later if required.
4390 */
4391 if (host->sps.sg && is_sps_mode(host)) {
4392 if (!mrq->data->host_cookie)
4393 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
4394 host->sps.num_ents, host->sps.dir);
4395 host->sps.sg = NULL;
4396 host->sps.busy = 0;
4397 }
4398
4399 /*
4400 * Clear current request information as current
4401 * request has ended
4402 */
4403 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
4404 del_timer(&host->req_tout_timer);
4405 } else {
4406 rc = -EINVAL;
4407 }
4408 spin_unlock_irqrestore(&host->lock, flags);
4409
4410 return rc;
4411}
4412
4413/**
4414 * msmsdcc_get_xfer_remain - returns number of bytes passed on bus
4415 * @mmc: MMC host, running the request
4416 *
4417 * Returns the number of bytes passed for SPS transfer. 0 - for non-SPS
4418 * transfer.
4419 */
4420unsigned int msmsdcc_get_xfer_remain(struct mmc_host *mmc)
4421{
4422 struct msmsdcc_host *host = mmc_priv(mmc);
4423 u32 data_cnt = 0;
4424
4425 /* Currently, we don't support to stop the non-SPS transfer */
4426 if (host->sps.busy && atomic_read(&host->clks_on))
4427 data_cnt = readl_relaxed(host->base + MMCIDATACNT);
4428
4429 return data_cnt;
4430}
4431
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05304432static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
4433{
4434 int err = 0;
4435 unsigned long rate;
4436 struct msmsdcc_host *host = mmc_priv(mmc);
4437
4438 if (IS_ERR_OR_NULL(host->bus_clk))
4439 goto out;
4440
4441 switch (state) {
4442 case MMC_LOAD_HIGH:
4443 rate = MSMSDCC_BUS_VOTE_MAX_RATE;
4444 break;
4445 case MMC_LOAD_LOW:
4446 rate = MSMSDCC_BUS_VOTE_MIN_RATE;
4447 break;
4448 default:
4449 err = -EINVAL;
4450 goto out;
4451 }
4452
4453 if (rate != host->bus_clk_rate) {
4454 err = clk_set_rate(host->bus_clk, rate);
4455 if (err)
4456 pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
4457 mmc_hostname(mmc), __func__, rate, err);
4458 else
4459 host->bus_clk_rate = rate;
4460 }
4461out:
4462 return err;
4463}
4464
San Mehat9d2bd732009-09-22 16:44:22 -07004465static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004466 .enable = msmsdcc_enable,
4467 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05304468 .pre_req = msmsdcc_pre_req,
4469 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07004470 .request = msmsdcc_request,
4471 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004472 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07004473 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05304474 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Asutosh Dasebd7d092012-07-09 19:08:26 +05304475 .execute_tuning = msmsdcc_execute_tuning,
4476 .hw_reset = msmsdcc_hw_reset,
Subhash Jadavanid076af72013-02-17 23:36:03 +02004477 .stop_request = msmsdcc_stop_request,
4478 .get_xfer_remain = msmsdcc_get_xfer_remain,
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05304479 .notify_load = msmsdcc_notify_load,
San Mehat9d2bd732009-09-22 16:44:22 -07004480};
4481
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304482static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
4483{
4484 unsigned int gpio_no = host->plat->status_gpio;
4485 int status;
4486
4487 if (!gpio_is_valid(gpio_no))
4488 return;
4489
4490 status = gpio_request(gpio_no, "SD_HW_Detect");
4491 if (status)
4492 pr_err("%s: %s: gpio_request(%d) failed\n",
4493 mmc_hostname(host->mmc), __func__, gpio_no);
4494}
4495
4496static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
4497{
4498 if (gpio_is_valid(host->plat->status_gpio))
4499 gpio_free(host->plat->status_gpio);
4500}
4501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004502static unsigned int
4503msmsdcc_slot_status(struct msmsdcc_host *host)
4504{
4505 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05304507 status = gpio_get_value_cansleep(host->plat->status_gpio);
4508 if (host->plat->is_status_gpio_active_low)
4509 status = !status;
4510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511 return status;
4512}
4513
San Mehat9d2bd732009-09-22 16:44:22 -07004514static void
4515msmsdcc_check_status(unsigned long data)
4516{
4517 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4518 unsigned int status;
4519
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05304520 if (host->plat->status || gpio_is_valid(host->plat->status_gpio)) {
Krishna Konda941604a2012-01-10 17:46:34 -08004521 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004522 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004523 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 status = msmsdcc_slot_status(host);
4525
Krishna Konda941604a2012-01-10 17:46:34 -08004526 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08004527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08004529 if (host->plat->status)
4530 pr_info("%s: Slot status change detected "
4531 "(%d -> %d)\n",
4532 mmc_hostname(host->mmc),
4533 host->oldstat, status);
4534 else if (host->plat->is_status_gpio_active_low)
4535 pr_info("%s: Slot status change detected "
4536 "(%d -> %d) and the card detect GPIO"
4537 " is ACTIVE_LOW\n",
4538 mmc_hostname(host->mmc),
4539 host->oldstat, status);
4540 else
4541 pr_info("%s: Slot status change detected "
4542 "(%d -> %d) and the card detect GPIO"
4543 " is ACTIVE_HIGH\n",
4544 mmc_hostname(host->mmc),
4545 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07004546 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004547 }
4548 host->oldstat = status;
4549 } else {
4550 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07004551 }
San Mehat9d2bd732009-09-22 16:44:22 -07004552}
4553
4554static irqreturn_t
4555msmsdcc_platform_status_irq(int irq, void *dev_id)
4556{
4557 struct msmsdcc_host *host = dev_id;
4558
Girish K Sa3c76eb2011-10-11 11:44:09 +05304559 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07004560 msmsdcc_check_status((unsigned long) host);
4561 return IRQ_HANDLED;
4562}
4563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004564static irqreturn_t
4565msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
4566{
4567 struct msmsdcc_host *host = dev_id;
4568
4569 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
4570 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304571 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004572 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304573 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004574 wake_lock(&host->sdio_wlock);
4575 msmsdcc_disable_irq_wake(host);
4576 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304577 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004578 }
4579 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304581 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304582 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304583 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584 }
4585 spin_unlock(&host->lock);
4586
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05304587out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004588 return IRQ_HANDLED;
4589}
4590
San Mehat9d2bd732009-09-22 16:44:22 -07004591static void
4592msmsdcc_status_notify_cb(int card_present, void *dev_id)
4593{
4594 struct msmsdcc_host *host = dev_id;
4595
Girish K Sa3c76eb2011-10-11 11:44:09 +05304596 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07004597 card_present);
4598 msmsdcc_check_status((unsigned long) host);
4599}
4600
San Mehat9d2bd732009-09-22 16:44:22 -07004601static int
4602msmsdcc_init_dma(struct msmsdcc_host *host)
4603{
4604 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
4605 host->dma.host = host;
4606 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004607 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004608
4609 if (!host->dmares)
4610 return -ENODEV;
4611
4612 host->dma.nc = dma_alloc_coherent(NULL,
4613 sizeof(struct msmsdcc_nc_dmadata),
4614 &host->dma.nc_busaddr,
4615 GFP_KERNEL);
4616 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004617 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07004618 return -ENOMEM;
4619 }
4620 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
4621 host->dma.cmd_busaddr = host->dma.nc_busaddr;
4622 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
4623 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
4624 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07004625 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07004626
4627 return 0;
4628}
4629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4631/**
4632 * Allocate and Connect a SDCC peripheral's SPS endpoint
4633 *
4634 * This function allocates endpoint context and
4635 * connect it with memory endpoint by calling
4636 * appropriate SPS driver APIs.
4637 *
4638 * Also registers a SPS callback function with
4639 * SPS driver
4640 *
4641 * This function should only be called once typically
4642 * during driver probe.
4643 *
4644 * @host - Pointer to sdcc host structure
4645 * @ep - Pointer to sps endpoint data structure
4646 * @is_produce - 1 means Producer endpoint
4647 * 0 means Consumer endpoint
4648 *
4649 * @return - 0 if successful else negative value.
4650 *
4651 */
4652static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4653 struct msmsdcc_sps_ep_conn_data *ep,
4654 bool is_producer)
4655{
4656 int rc = 0;
4657 struct sps_pipe *sps_pipe_handle;
4658 struct sps_connect *sps_config = &ep->config;
4659 struct sps_register_event *sps_event = &ep->event;
4660
4661 /* Allocate endpoint context */
4662 sps_pipe_handle = sps_alloc_endpoint();
4663 if (!sps_pipe_handle) {
4664 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4665 mmc_hostname(host->mmc), is_producer);
4666 rc = -ENOMEM;
4667 goto out;
4668 }
4669
4670 /* Get default connection configuration for an endpoint */
4671 rc = sps_get_config(sps_pipe_handle, sps_config);
4672 if (rc) {
4673 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4674 " rc=%d", mmc_hostname(host->mmc),
4675 (u32)sps_pipe_handle, rc);
4676 goto get_config_err;
4677 }
4678
4679 /* Modify the default connection configuration */
4680 if (is_producer) {
4681 /*
4682 * For SDCC producer transfer, source should be
4683 * SDCC peripheral where as destination should
4684 * be system memory.
4685 */
4686 sps_config->source = host->sps.bam_handle;
4687 sps_config->destination = SPS_DEV_HANDLE_MEM;
4688 /* Producer pipe will handle this connection */
4689 sps_config->mode = SPS_MODE_SRC;
4690 sps_config->options =
4691 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4692 } else {
4693 /*
4694 * For SDCC consumer transfer, source should be
4695 * system memory where as destination should
4696 * SDCC peripheral
4697 */
4698 sps_config->source = SPS_DEV_HANDLE_MEM;
4699 sps_config->destination = host->sps.bam_handle;
4700 sps_config->mode = SPS_MODE_DEST;
4701 sps_config->options =
4702 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4703 }
4704
4705 /* Producer pipe index */
4706 sps_config->src_pipe_index = host->sps.src_pipe_index;
4707 /* Consumer pipe index */
4708 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4709 /*
4710 * This event thresold value is only significant for BAM-to-BAM
4711 * transfer. It's ignored for BAM-to-System mode transfer.
4712 */
4713 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304714
4715 /* Allocate maximum descriptor fifo size */
4716 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4717 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004718 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4719 sps_config->desc.size,
4720 &sps_config->desc.phys_base,
4721 GFP_KERNEL);
4722
Pratibhasagar V00b94332011-10-18 14:57:27 +05304723 if (!sps_config->desc.base) {
4724 rc = -ENOMEM;
4725 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4726 , mmc_hostname(host->mmc));
4727 goto get_config_err;
4728 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004729 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4730
4731 /* Establish connection between peripheral and memory endpoint */
4732 rc = sps_connect(sps_pipe_handle, sps_config);
4733 if (rc) {
4734 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4735 " rc=%d", mmc_hostname(host->mmc),
4736 (u32)sps_pipe_handle, rc);
4737 goto sps_connect_err;
4738 }
4739
4740 sps_event->mode = SPS_TRIGGER_CALLBACK;
4741 sps_event->options = SPS_O_EOT;
4742 sps_event->callback = msmsdcc_sps_complete_cb;
4743 sps_event->xfer_done = NULL;
4744 sps_event->user = (void *)host;
4745
4746 /* Register callback event for EOT (End of transfer) event. */
4747 rc = sps_register_event(sps_pipe_handle, sps_event);
4748 if (rc) {
4749 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4750 " rc=%d", mmc_hostname(host->mmc),
4751 (u32)sps_pipe_handle, rc);
4752 goto reg_event_err;
4753 }
4754 /* Now save the sps pipe handle */
4755 ep->pipe_handle = sps_pipe_handle;
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004756 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"\
4757 " desc_fifo.phys_base=%pa\n", mmc_hostname(host->mmc),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 __func__, is_producer ? "READ" : "WRITE",
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07004759 (u32)sps_pipe_handle, &sps_config->desc.phys_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004760 goto out;
4761
4762reg_event_err:
4763 sps_disconnect(sps_pipe_handle);
4764sps_connect_err:
4765 dma_free_coherent(mmc_dev(host->mmc),
4766 sps_config->desc.size,
4767 sps_config->desc.base,
4768 sps_config->desc.phys_base);
4769get_config_err:
4770 sps_free_endpoint(sps_pipe_handle);
4771out:
4772 return rc;
4773}
4774
4775/**
4776 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4777 *
4778 * This function disconnect endpoint and deallocates
4779 * endpoint context.
4780 *
4781 * This function should only be called once typically
4782 * during driver remove.
4783 *
4784 * @host - Pointer to sdcc host structure
4785 * @ep - Pointer to sps endpoint data structure
4786 *
4787 */
4788static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4789 struct msmsdcc_sps_ep_conn_data *ep)
4790{
4791 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4792 struct sps_connect *sps_config = &ep->config;
4793 struct sps_register_event *sps_event = &ep->event;
4794
4795 sps_event->xfer_done = NULL;
4796 sps_event->callback = NULL;
4797 sps_register_event(sps_pipe_handle, sps_event);
4798 sps_disconnect(sps_pipe_handle);
4799 dma_free_coherent(mmc_dev(host->mmc),
4800 sps_config->desc.size,
4801 sps_config->desc.base,
4802 sps_config->desc.phys_base);
4803 sps_free_endpoint(sps_pipe_handle);
4804}
4805
4806/**
4807 * Reset SDCC peripheral's SPS endpoint
4808 *
4809 * This function disconnects an endpoint.
4810 *
4811 * This function should be called for reseting
4812 * SPS endpoint when data transfer error is
4813 * encountered during data transfer. This
4814 * can be considered as soft reset to endpoint.
4815 *
4816 * This function should only be called if
4817 * msmsdcc_sps_init() is already called.
4818 *
4819 * @host - Pointer to sdcc host structure
4820 * @ep - Pointer to sps endpoint data structure
4821 *
4822 * @return - 0 if successful else negative value.
4823 */
4824static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4825 struct msmsdcc_sps_ep_conn_data *ep)
4826{
4827 int rc = 0;
4828 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4829
4830 rc = sps_disconnect(sps_pipe_handle);
4831 if (rc) {
4832 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4833 " rc=%d", mmc_hostname(host->mmc), __func__,
4834 (u32)sps_pipe_handle, rc);
4835 goto out;
4836 }
4837 out:
4838 return rc;
4839}
4840
4841/**
4842 * Restore SDCC peripheral's SPS endpoint
4843 *
4844 * This function connects an endpoint.
4845 *
4846 * This function should be called for restoring
4847 * SPS endpoint after data transfer error is
4848 * encountered during data transfer. This
4849 * can be considered as soft reset to endpoint.
4850 *
4851 * This function should only be called if
4852 * msmsdcc_sps_reset_ep() is called before.
4853 *
4854 * @host - Pointer to sdcc host structure
4855 * @ep - Pointer to sps endpoint data structure
4856 *
4857 * @return - 0 if successful else negative value.
4858 */
4859static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4860 struct msmsdcc_sps_ep_conn_data *ep)
4861{
4862 int rc = 0;
4863 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4864 struct sps_connect *sps_config = &ep->config;
4865 struct sps_register_event *sps_event = &ep->event;
4866
4867 /* Establish connection between peripheral and memory endpoint */
4868 rc = sps_connect(sps_pipe_handle, sps_config);
4869 if (rc) {
4870 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4871 " rc=%d", mmc_hostname(host->mmc), __func__,
4872 (u32)sps_pipe_handle, rc);
4873 goto out;
4874 }
4875
4876 /* Register callback event for EOT (End of transfer) event. */
4877 rc = sps_register_event(sps_pipe_handle, sps_event);
4878 if (rc) {
4879 pr_err("%s: %s: sps_register_event() failed!!!"
4880 " pipe_handle=0x%x, rc=%d",
4881 mmc_hostname(host->mmc), __func__,
4882 (u32)sps_pipe_handle, rc);
4883 goto reg_event_err;
4884 }
4885 goto out;
4886
4887reg_event_err:
4888 sps_disconnect(sps_pipe_handle);
4889out:
4890 return rc;
4891}
4892
4893/**
Krishna Konda5af8f972012-05-14 16:15:24 -07004894 * Handle BAM device's global error condition
4895 *
4896 * This is an error handler for the SDCC bam device
4897 *
4898 * This function is registered as a callback with SPS-BAM
4899 * driver and will called in case there are an errors for
4900 * the SDCC BAM deivce. Any error conditions in the BAM
4901 * device are global and will be result in this function
4902 * being called once per device.
4903 *
4904 * This function will be called from the sps driver's
4905 * interrupt context.
4906 *
4907 * @sps_cb_case - indicates what error it is
4908 * @user - Pointer to sdcc host structure
4909 */
4910static void
4911msmsdcc_sps_bam_global_irq_cb(enum sps_callback_case sps_cb_case, void *user)
4912{
4913 struct msmsdcc_host *host = (struct msmsdcc_host *)user;
4914 struct mmc_request *mrq;
4915 unsigned long flags;
4916 int32_t error = 0;
4917
4918 BUG_ON(!host);
4919 BUG_ON(!is_sps_mode(host));
4920
4921 if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
Krishna Konda3ca90f02012-08-29 16:29:21 -07004922 /* Reset all endpoints along with resetting bam. */
4923 host->sps.reset_bam = true;
Krishna Konda5af8f972012-05-14 16:15:24 -07004924
4925 pr_err("%s: BAM Global ERROR IRQ happened\n",
4926 mmc_hostname(host->mmc));
4927 error = EAGAIN;
4928 } else if (sps_cb_case == SPS_CALLBACK_BAM_HRESP_ERR_IRQ) {
4929 /**
4930 * This means that there was an AHB access error and
4931 * the address we are trying to read/write is something
4932 * we dont have priviliges to do so.
4933 */
4934 pr_err("%s: BAM HRESP_ERR_IRQ happened\n",
4935 mmc_hostname(host->mmc));
4936 error = EACCES;
4937 } else {
4938 /**
4939 * This should not have happened ideally. If this happens
4940 * there is some seriously wrong.
4941 */
4942 pr_err("%s: BAM global IRQ callback received, type:%d\n",
4943 mmc_hostname(host->mmc), (u32) sps_cb_case);
4944 error = EIO;
4945 }
4946
4947 spin_lock_irqsave(&host->lock, flags);
4948
4949 mrq = host->curr.mrq;
4950
4951 if (mrq && mrq->cmd) {
4952 msmsdcc_dump_sdcc_state(host);
4953
4954 if (!mrq->cmd->error)
4955 mrq->cmd->error = -error;
4956 if (host->curr.data) {
4957 if (mrq->data && !mrq->data->error)
4958 mrq->data->error = -error;
4959 host->curr.data_xfered = 0;
4960 if (host->sps.sg && is_sps_mode(host)) {
4961 /* Stop current SPS transfer */
4962 msmsdcc_sps_exit_curr_xfer(host);
4963 } else {
4964 /* this condition should not have happened */
4965 pr_err("%s: something is seriously wrong. "\
4966 "Funtion: %s, line: %d\n",
4967 mmc_hostname(host->mmc),
4968 __func__, __LINE__);
4969 }
4970 } else {
4971 /* this condition should not have happened */
4972 pr_err("%s: something is seriously wrong. Funtion: "\
4973 "%s, line: %d\n", mmc_hostname(host->mmc),
4974 __func__, __LINE__);
4975 }
4976 }
4977 spin_unlock_irqrestore(&host->lock, flags);
4978}
4979
4980/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004981 * Initialize SPS HW connected with SDCC core
4982 *
4983 * This function register BAM HW resources with
4984 * SPS driver and then initialize 2 SPS endpoints
4985 *
4986 * This function should only be called once typically
4987 * during driver probe.
4988 *
4989 * @host - Pointer to sdcc host structure
4990 *
4991 * @return - 0 if successful else negative value.
4992 *
4993 */
4994static int msmsdcc_sps_init(struct msmsdcc_host *host)
4995{
4996 int rc = 0;
4997 struct sps_bam_props bam = {0};
4998
4999 host->bam_base = ioremap(host->bam_memres->start,
5000 resource_size(host->bam_memres));
5001 if (!host->bam_base) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005002 pr_err("%s: BAM ioremap() failed!!! resource: %pr\n",
5003 mmc_hostname(host->mmc), host->bam_memres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004 rc = -ENOMEM;
5005 goto out;
5006 }
5007
5008 bam.phys_addr = host->bam_memres->start;
5009 bam.virt_addr = host->bam_base;
5010 /*
5011 * This event thresold value is only significant for BAM-to-BAM
5012 * transfer. It's ignored for BAM-to-System mode transfer.
5013 */
5014 bam.event_threshold = 0x10; /* Pipe event threshold */
5015 /*
5016 * This threshold controls when the BAM publish
5017 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305018 * SPS HW will be used for data transfer size even
5019 * less than SDCC FIFO size. So let's set BAM summing
5020 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005021 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305022 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005023 /* SPS driver wll handle the SDCC BAM IRQ */
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005024 bam.irq = host->bam_irqres->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005025 bam.manage = SPS_BAM_MGR_LOCAL;
Krishna Konda5af8f972012-05-14 16:15:24 -07005026 bam.callback = msmsdcc_sps_bam_global_irq_cb;
5027 bam.user = (void *)host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005028
Krishna Kondacdff0902013-04-09 17:57:22 -07005029 /* bam reset messages will be limited to 5 times */
5030 bam.constrained_logging = true;
5031 bam.logging_number = 5;
5032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
5034 (u32)bam.phys_addr);
5035 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
5036 (u32)bam.virt_addr);
5037
5038 /* Register SDCC Peripheral BAM device to SPS driver */
5039 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
5040 if (rc) {
5041 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
5042 mmc_hostname(host->mmc), rc);
5043 goto reg_bam_err;
5044 }
5045 pr_info("%s: BAM device registered. bam_handle=0x%x",
5046 mmc_hostname(host->mmc), host->sps.bam_handle);
5047
5048 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
5049 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
5050
5051 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
5052 SPS_PROD_PERIPHERAL);
5053 if (rc)
5054 goto sps_reset_err;
5055 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
5056 SPS_CONS_PERIPHERAL);
5057 if (rc)
5058 goto cons_conn_err;
5059
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005060 pr_info("%s: Qualcomm MSM SDCC-BAM at %pr %pr\n",
5061 mmc_hostname(host->mmc), host->bam_memres, host->bam_irqres);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005062 goto out;
5063
5064cons_conn_err:
5065 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5066sps_reset_err:
5067 sps_deregister_bam_device(host->sps.bam_handle);
5068reg_bam_err:
5069 iounmap(host->bam_base);
5070out:
5071 return rc;
5072}
5073
5074/**
5075 * De-initialize SPS HW connected with SDCC core
5076 *
5077 * This function deinitialize SPS endpoints and then
5078 * deregisters BAM resources from SPS driver.
5079 *
5080 * This function should only be called once typically
5081 * during driver remove.
5082 *
5083 * @host - Pointer to sdcc host structure
5084 *
5085 */
5086static void msmsdcc_sps_exit(struct msmsdcc_host *host)
5087{
5088 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
5089 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
5090 sps_deregister_bam_device(host->sps.bam_handle);
5091 iounmap(host->bam_base);
5092}
5093#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
5094
5095static ssize_t
5096show_polling(struct device *dev, struct device_attribute *attr, char *buf)
5097{
5098 struct mmc_host *mmc = dev_get_drvdata(dev);
5099 struct msmsdcc_host *host = mmc_priv(mmc);
5100 int poll;
5101 unsigned long flags;
5102
5103 spin_lock_irqsave(&host->lock, flags);
5104 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
5105 spin_unlock_irqrestore(&host->lock, flags);
5106
5107 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
5108}
5109
5110static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305111store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005112 const char *buf, size_t count)
5113{
5114 struct mmc_host *mmc = dev_get_drvdata(dev);
5115 struct msmsdcc_host *host = mmc_priv(mmc);
5116 int value;
5117 unsigned long flags;
5118
5119 sscanf(buf, "%d", &value);
5120
5121 spin_lock_irqsave(&host->lock, flags);
5122 if (value) {
5123 mmc->caps |= MMC_CAP_NEEDS_POLL;
5124 mmc_detect_change(host->mmc, 0);
5125 } else {
5126 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
5127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005128 spin_unlock_irqrestore(&host->lock, flags);
5129 return count;
5130}
5131
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305132static ssize_t
5133show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
5134 char *buf)
5135{
5136 struct mmc_host *mmc = dev_get_drvdata(dev);
5137 struct msmsdcc_host *host = mmc_priv(mmc);
5138
5139 return snprintf(buf, PAGE_SIZE, "%u\n",
5140 host->msm_bus_vote.is_max_bw_needed);
5141}
5142
5143static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305144store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305145 const char *buf, size_t count)
5146{
5147 struct mmc_host *mmc = dev_get_drvdata(dev);
5148 struct msmsdcc_host *host = mmc_priv(mmc);
5149 uint32_t value;
5150 unsigned long flags;
5151
5152 if (!kstrtou32(buf, 0, &value)) {
5153 spin_lock_irqsave(&host->lock, flags);
5154 host->msm_bus_vote.is_max_bw_needed = !!value;
5155 spin_unlock_irqrestore(&host->lock, flags);
5156 }
5157
5158 return count;
5159}
5160
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305161static ssize_t
5162show_idle_timeout(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, "%u (Min 5 sec)\n",
Pratibhasagar V713817b2012-09-07 11:28:30 +05305169 host->idle_tout / 1000);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305170}
5171
5172static ssize_t
5173store_idle_timeout(struct device *dev, struct device_attribute *attr,
5174 const char *buf, size_t count)
5175{
5176 struct mmc_host *mmc = dev_get_drvdata(dev);
5177 struct msmsdcc_host *host = mmc_priv(mmc);
5178 unsigned int long flags;
5179 int timeout; /* in secs */
5180
5181 if (!kstrtou32(buf, 0, &timeout)
5182 && (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
5183 spin_lock_irqsave(&host->lock, flags);
Pratibhasagar V713817b2012-09-07 11:28:30 +05305184 host->idle_tout = timeout * 1000;
Pratibhasagar V13d1d032012-07-09 20:12:38 +05305185 spin_unlock_irqrestore(&host->lock, flags);
5186 }
5187 return count;
5188}
5189
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305190static inline void set_auto_cmd_setting(struct device *dev,
5191 const char *buf,
5192 bool is_cmd19)
5193{
5194 struct mmc_host *mmc = dev_get_drvdata(dev);
5195 struct msmsdcc_host *host = mmc_priv(mmc);
5196 unsigned int long flags;
5197 int temp;
5198
5199 if (!kstrtou32(buf, 0, &temp)) {
5200 spin_lock_irqsave(&host->lock, flags);
5201 if (is_cmd19)
5202 host->en_auto_cmd19 = !!temp;
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305203 else
5204 host->en_auto_cmd21 = !!temp;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05305205 spin_unlock_irqrestore(&host->lock, flags);
5206 }
5207}
5208
5209static ssize_t
5210show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5211 char *buf)
5212{
5213 struct mmc_host *mmc = dev_get_drvdata(dev);
5214 struct msmsdcc_host *host = mmc_priv(mmc);
5215
5216 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
5217}
5218
5219static ssize_t
5220store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
5221 const char *buf, size_t count)
5222{
5223 set_auto_cmd_setting(dev, buf, true);
5224
5225 return count;
5226}
5227
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05305228static ssize_t
5229show_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5230 char *buf)
5231{
5232 struct mmc_host *mmc = dev_get_drvdata(dev);
5233 struct msmsdcc_host *host = mmc_priv(mmc);
5234
5235 return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd21);
5236}
5237
5238static ssize_t
5239store_enable_auto_cmd21(struct device *dev, struct device_attribute *attr,
5240 const char *buf, size_t count)
5241{
5242 set_auto_cmd_setting(dev, buf, false);
5243
5244 return count;
5245}
5246
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305247static void msmsdcc_print_regs(const char *name, void __iomem *base,
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005248 resource_size_t phys_base,
5249 unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305250{
5251 unsigned int i;
5252
5253 if (!base)
5254 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305255
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07005256 pr_err("===== %s: Register Dumps @phys_base=%pa, @virt_base=0x%x"\
5257 " =====\n", name, &phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305258 for (i = 0; i < no_of_regs; i = i + 4) {
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305259 pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305260 (u32)readl_relaxed(base + i*4),
5261 (u32)readl_relaxed(base + ((i+1)*4)),
5262 (u32)readl_relaxed(base + ((i+2)*4)),
5263 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305264 }
5265}
5266
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305267/*
5268 * This function prints the testbus debug output for all the
5269 * available SDCC controller test bus.
5270 *
5271 * Note: This function should only be called if the SDCC is clocked.
5272 */
5273static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
5274{
5275 int testbus_num;
5276
5277 if (!is_testbus_debug(host))
5278 return;
5279
5280 pr_err("== SDCC Test Bus Debug ==");
5281 for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
5282 writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
5283 | MCI_TESTBUS_ENA),
5284 host->base + MCI_TESTBUS_CONFIG);
5285 pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
5286 (u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
5287 }
5288 /* Disable the test bus output */
5289 writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
5290}
5291
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305292static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
5293{
5294 /* Dump current state of SDCC clocks, power and irq */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305295 pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305296 (host->pwr ? "ON" : "OFF"));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305297 pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305298 mmc_hostname(host->mmc),
5299 (atomic_read(&host->clks_on) ? "ON" : "OFF"),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305300 (u32)clk_get_rate(host->clk));
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305301 pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305302 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
5303
5304 /* Now dump SDCC registers. Don't print FIFO registers */
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305305 if (atomic_read(&host->clks_on)) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305306 msmsdcc_print_regs("SDCC-CORE", host->base,
5307 host->core_memres->start, 28);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305308 pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
5309 mmc_hostname(host->mmc),
5310 readl_relaxed(host->base + MCI_TEST_INPUT));
Subhash Jadavani1b677d52012-12-10 20:12:19 +05305311 msmsdcc_print_testbus_info(host);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305312 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305313
5314 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05305315 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305316 pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305317 else if (is_dma_mode(host))
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305318 pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305319 mmc_hostname(host->mmc), host->dma.busy,
5320 host->dma.channel, host->dma.crci);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305321 else if (is_sps_mode(host)) {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05305322 if (host->sps.busy && atomic_read(&host->clks_on))
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305323 msmsdcc_print_regs("SDCC-DML", host->dml_base,
5324 host->dml_memres->start,
5325 16);
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305326 pr_err("%s: SPS mode: busy=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305327 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305328 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305329
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305330 pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305331 mmc_hostname(host->mmc), host->curr.xfer_size,
5332 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305333 }
5334
Krishna Konda3ca90f02012-08-29 16:29:21 -07005335 if (host->sps.reset_bam)
5336 pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
5337 mmc_hostname(host->mmc), host->sps.reset_bam);
5338
Pratibhasagar V74bff7c2012-08-21 14:52:30 +05305339 pr_err("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05305340 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
5341 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
5342 host->curr.got_dataend, host->prog_enable,
5343 host->curr.wait_for_auto_prog_done,
5344 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05305345 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305346}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05305347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005348static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
5349{
5350 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
5351 struct mmc_request *mrq;
5352 unsigned long flags;
5353
5354 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005355 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005356 pr_info("%s: %s: dummy CMD52 timeout\n",
5357 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07005358 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005359 }
5360
5361 mrq = host->curr.mrq;
5362
5363 if (mrq && mrq->cmd) {
Subhash Jadavani926a9cb2012-12-15 22:05:54 +05305364 if (!mrq->cmd->bkops_busy) {
5365 pr_info("%s: CMD%d: Request timeout\n",
5366 mmc_hostname(host->mmc), mrq->cmd->opcode);
5367 msmsdcc_dump_sdcc_state(host);
5368 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005370 if (!mrq->cmd->error)
5371 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05305372 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005373 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005374 if (mrq->data && !mrq->data->error)
5375 mrq->data->error = -ETIMEDOUT;
5376 host->curr.data_xfered = 0;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305377 if (host->dma.sg && is_dma_mode(host)) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07005378 msm_dmov_flush(host->dma.channel, 0);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305379 } else if (host->sps.sg && is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005380 /* Stop current SPS transfer */
5381 msmsdcc_sps_exit_curr_xfer(host);
5382 } else {
5383 msmsdcc_reset_and_restore(host);
5384 msmsdcc_stop_data(host);
5385 if (mrq->data && mrq->data->stop)
5386 msmsdcc_start_command(host,
5387 mrq->data->stop, 0);
5388 else
5389 msmsdcc_request_end(host, mrq);
5390 }
5391 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05305392 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05305393 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005394 msmsdcc_reset_and_restore(host);
5395 msmsdcc_request_end(host, mrq);
5396 }
5397 }
5398 spin_unlock_irqrestore(&host->lock, flags);
5399}
5400
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305401/*
5402 * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
5403 *
5404 * @dev: device node from which the property value is to be read.
5405 * @prop_name: name of the property to be searched.
5406 * @out_array: filled array returned to caller
5407 * @len: filled array size returned to caller
5408 * @size: expected size of the array
5409 *
5410 * If expected "size" doesn't match with "len" an error is returned. If
5411 * expected size is zero, the length of actual array is returned provided
5412 * return value is zero.
5413 *
5414 * RETURNS:
5415 * zero on success, negative error if failed.
5416 */
5417static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
5418 u32 **out_array, int *len, int size)
5419{
5420 int ret = 0;
5421 u32 *array = NULL;
5422 struct device_node *np = dev->of_node;
5423
5424 if (of_get_property(np, prop_name, len)) {
5425 size_t sz;
5426 sz = *len = *len / sizeof(*array);
5427
5428 if (sz > 0 && !(size > 0 && (sz != size))) {
5429 array = devm_kzalloc(dev, sz * sizeof(*array),
5430 GFP_KERNEL);
5431 if (!array) {
5432 dev_err(dev, "%s: no memory\n", prop_name);
5433 ret = -ENOMEM;
5434 goto out;
5435 }
5436
5437 ret = of_property_read_u32_array(np, prop_name,
5438 array, sz);
5439 if (ret < 0) {
5440 dev_err(dev, "%s: error reading array %d\n",
5441 prop_name, ret);
5442 goto out;
5443 }
5444 } else {
5445 dev_err(dev, "%s invalid size\n", prop_name);
5446 ret = -EINVAL;
5447 goto out;
5448 }
5449 } else {
5450 dev_err(dev, "%s not specified\n", prop_name);
5451 ret = -EINVAL;
5452 goto out;
5453 }
5454 *out_array = array;
5455out:
5456 if (ret)
5457 *len = 0;
5458 return ret;
5459}
5460
5461static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
5462 struct msm_mmc_pad_pull_data **pad_pull_data)
5463{
5464 int ret = 0, base = 0, len, i;
5465 u32 *tmp;
5466 struct msm_mmc_pad_pull_data *pull_data;
5467 struct msm_mmc_pad_pull *pull;
5468
5469 switch (id) {
5470 case 1:
5471 base = TLMM_PULL_SDC1_CLK;
5472 break;
5473 case 2:
5474 base = TLMM_PULL_SDC2_CLK;
5475 break;
5476 case 3:
5477 base = TLMM_PULL_SDC3_CLK;
5478 break;
5479 case 4:
5480 base = TLMM_PULL_SDC4_CLK;
5481 break;
5482 default:
5483 dev_err(dev, "%s: Invalid slot id\n", __func__);
5484 ret = -EINVAL;
5485 goto err;
5486 }
5487
5488 pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
5489 GFP_KERNEL);
5490 if (!pull_data) {
5491 dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
5492 ret = -ENOMEM;
5493 goto err;
5494 }
5495 pull_data->size = 3; /* array size for clk, cmd, data */
5496
5497 /* Allocate on, off configs for clk, cmd, data */
5498 pull = devm_kzalloc(dev, 2 * pull_data->size *\
5499 sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
5500 if (!pull) {
5501 dev_err(dev, "No memory for msm_mmc_pad_pull\n");
5502 ret = -ENOMEM;
5503 goto err;
5504 }
5505 pull_data->on = pull;
5506 pull_data->off = pull + pull_data->size;
5507
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005508 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305509 &tmp, &len, pull_data->size);
5510 if (!ret) {
5511 for (i = 0; i < len; i++) {
5512 pull_data->on[i].no = base + i;
5513 pull_data->on[i].val = tmp[i];
5514 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5515 i, pull_data->on[i].val);
5516 }
5517 } else {
5518 goto err;
5519 }
5520
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005521 ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305522 &tmp, &len, pull_data->size);
5523 if (!ret) {
5524 for (i = 0; i < len; i++) {
5525 pull_data->off[i].no = base + i;
5526 pull_data->off[i].val = tmp[i];
5527 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5528 i, pull_data->off[i].val);
5529 }
5530 } else {
5531 goto err;
5532 }
5533
5534 *pad_pull_data = pull_data;
5535err:
5536 return ret;
5537}
5538
5539static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
5540 struct msm_mmc_pad_drv_data **pad_drv_data)
5541{
5542 int ret = 0, base = 0, len, i;
5543 u32 *tmp;
5544 struct msm_mmc_pad_drv_data *drv_data;
5545 struct msm_mmc_pad_drv *drv;
5546
5547 switch (id) {
5548 case 1:
5549 base = TLMM_HDRV_SDC1_CLK;
5550 break;
5551 case 2:
5552 base = TLMM_HDRV_SDC2_CLK;
5553 break;
5554 case 3:
5555 base = TLMM_HDRV_SDC3_CLK;
5556 break;
5557 case 4:
5558 base = TLMM_HDRV_SDC4_CLK;
5559 break;
5560 default:
5561 dev_err(dev, "%s: Invalid slot id\n", __func__);
5562 ret = -EINVAL;
5563 goto err;
5564 }
5565
5566 drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
5567 GFP_KERNEL);
5568 if (!drv_data) {
5569 dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
5570 ret = -ENOMEM;
5571 goto err;
5572 }
5573 drv_data->size = 3; /* array size for clk, cmd, data */
5574
5575 /* Allocate on, off configs for clk, cmd, data */
5576 drv = devm_kzalloc(dev, 2 * drv_data->size *\
5577 sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
5578 if (!drv) {
5579 dev_err(dev, "No memory msm_mmc_pad_drv\n");
5580 ret = -ENOMEM;
5581 goto err;
5582 }
5583 drv_data->on = drv;
5584 drv_data->off = drv + drv_data->size;
5585
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005586 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305587 &tmp, &len, drv_data->size);
5588 if (!ret) {
5589 for (i = 0; i < len; i++) {
5590 drv_data->on[i].no = base + i;
5591 drv_data->on[i].val = tmp[i];
5592 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5593 i, drv_data->on[i].val);
5594 }
5595 } else {
5596 goto err;
5597 }
5598
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005599 ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305600 &tmp, &len, drv_data->size);
5601 if (!ret) {
5602 for (i = 0; i < len; i++) {
5603 drv_data->off[i].no = base + i;
5604 drv_data->off[i].val = tmp[i];
5605 dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
5606 i, drv_data->off[i].val);
5607 }
5608 } else {
5609 goto err;
5610 }
5611
5612 *pad_drv_data = drv_data;
5613err:
5614 return ret;
5615}
5616
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305617static void msmsdcc_dt_get_cd_wp_gpio(struct device *dev,
5618 struct mmc_platform_data *pdata)
5619{
5620 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
5621 struct device_node *np = dev->of_node;
5622
5623 pdata->status_gpio = of_get_named_gpio_flags(np,
5624 "cd-gpios", 0, &flags);
5625 if (gpio_is_valid(pdata->status_gpio)) {
Krishna Kondab6da6932012-08-19 12:04:05 -07005626 struct platform_device *pdev = container_of(dev,
5627 struct platform_device, dev);
5628 pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305629 pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
5630 }
5631
5632 pdata->wpswitch_gpio = of_get_named_gpio_flags(np,
5633 "wp-gpios", 0, &flags);
5634 if (gpio_is_valid(pdata->wpswitch_gpio))
5635 pdata->is_wpswitch_active_low = flags & OF_GPIO_ACTIVE_LOW;
5636}
5637
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305638static int msmsdcc_dt_parse_gpio_info(struct device *dev,
5639 struct mmc_platform_data *pdata)
5640{
5641 int ret = 0, id = 0, cnt, i;
5642 struct msm_mmc_pin_data *pin_data;
5643 struct device_node *np = dev->of_node;
5644
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05305645 msmsdcc_dt_get_cd_wp_gpio(dev, pdata);
5646
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305647 pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
5648 if (!pin_data) {
5649 dev_err(dev, "No memory for pin_data\n");
5650 ret = -ENOMEM;
5651 goto err;
5652 }
5653
5654 cnt = of_gpio_count(np);
5655 if (cnt > 0) {
5656 pin_data->is_gpio = true;
5657
5658 pin_data->gpio_data = devm_kzalloc(dev,
5659 sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
5660 if (!pin_data->gpio_data) {
5661 dev_err(dev, "No memory for gpio_data\n");
5662 ret = -ENOMEM;
5663 goto err;
5664 }
5665 pin_data->gpio_data->size = cnt;
5666 pin_data->gpio_data->gpio = devm_kzalloc(dev,
5667 cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
5668 if (!pin_data->gpio_data->gpio) {
5669 dev_err(dev, "No memory for gpio\n");
5670 ret = -ENOMEM;
5671 goto err;
5672 }
5673
5674 for (i = 0; i < cnt; i++) {
5675 const char *name = NULL;
5676 char result[32];
5677 pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
5678 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005679 "qcom,gpio-names", i, &name);
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305680
5681 snprintf(result, 32, "%s-%s",
5682 dev_name(dev), name ? name : "?");
5683 pin_data->gpio_data->gpio[i].name = result;
5684 dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
5685 pin_data->gpio_data->gpio[i].name,
5686 pin_data->gpio_data->gpio[i].no);
5687 }
5688 } else {
5689 pin_data->pad_data = devm_kzalloc(dev,
5690 sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
5691 if (!pin_data->pad_data) {
5692 dev_err(dev, "No memory for pin_data->pad_data\n");
5693 ret = -ENOMEM;
5694 goto err;
5695 }
5696
5697 of_property_read_u32(np, "cell-index", &id);
5698
5699 ret = msmsdcc_dt_get_pad_pull_info(dev, id,
5700 &pin_data->pad_data->pull);
5701 if (ret)
5702 goto err;
5703 ret = msmsdcc_dt_get_pad_drv_info(dev, id,
5704 &pin_data->pad_data->drv);
5705 if (ret)
5706 goto err;
5707 }
5708
5709 pdata->pin_data = pin_data;
5710err:
5711 if (ret)
5712 dev_err(dev, "%s failed with err %d\n", __func__, ret);
5713 return ret;
5714}
5715
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305716#define MAX_PROP_SIZE 32
5717static int msmsdcc_dt_parse_vreg_info(struct device *dev,
5718 struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
5719{
5720 int len, ret = 0;
5721 const __be32 *prop;
5722 char prop_name[MAX_PROP_SIZE];
5723 struct msm_mmc_reg_data *vreg;
5724 struct device_node *np = dev->of_node;
5725
5726 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
5727 if (of_parse_phandle(np, prop_name, 0)) {
5728 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
5729 if (!vreg) {
5730 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
5731 ret = -ENOMEM;
5732 goto err;
5733 }
5734
5735 vreg->name = vreg_name;
5736
5737 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005738 "qcom,%s-always-on", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305739 if (of_get_property(np, prop_name, NULL))
5740 vreg->always_on = true;
5741
5742 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005743 "qcom,%s-lpm-sup", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305744 if (of_get_property(np, prop_name, NULL))
5745 vreg->lpm_sup = true;
5746
5747 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005748 "qcom,%s-voltage-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305749 prop = of_get_property(np, prop_name, &len);
5750 if (!prop || (len != (2 * sizeof(__be32)))) {
5751 dev_warn(dev, "%s %s property\n",
5752 prop ? "invalid format" : "no", prop_name);
5753 } else {
5754 vreg->low_vol_level = be32_to_cpup(&prop[0]);
5755 vreg->high_vol_level = be32_to_cpup(&prop[1]);
5756 }
5757
5758 snprintf(prop_name, MAX_PROP_SIZE,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005759 "qcom,%s-current-level", vreg_name);
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305760 prop = of_get_property(np, prop_name, &len);
5761 if (!prop || (len != (2 * sizeof(__be32)))) {
5762 dev_warn(dev, "%s %s property\n",
5763 prop ? "invalid format" : "no", prop_name);
5764 } else {
5765 vreg->lpm_uA = be32_to_cpup(&prop[0]);
5766 vreg->hpm_uA = be32_to_cpup(&prop[1]);
5767 }
5768
5769 *vreg_data = vreg;
5770 dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
5771 vreg->name, vreg->always_on ? "always_on," : "",
5772 vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
5773 vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
5774 }
5775
5776err:
5777 return ret;
5778}
5779
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305780static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
5781{
5782 int i, ret;
5783 struct mmc_platform_data *pdata;
5784 struct device_node *np = dev->of_node;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305785 u32 bus_width = 0, current_limit = 0;
Rohit Vaswani5dab6e12012-10-04 10:58:26 -07005786 u32 *clk_table = NULL, *sup_voltages = NULL;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305787 int clk_table_len, sup_volt_len, len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305788
5789 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
5790 if (!pdata) {
5791 dev_err(dev, "could not allocate memory for platform data\n");
5792 goto err;
5793 }
5794
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005795 of_property_read_u32(np, "qcom,bus-width", &bus_width);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305796 if (bus_width == 8) {
5797 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
5798 } else if (bus_width == 4) {
5799 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
5800 } else {
5801 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
5802 pdata->mmc_bus_width = 0;
5803 }
5804
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005805 ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305806 &sup_voltages, &sup_volt_len, 0);
5807 if (!ret) {
5808 for (i = 0; i < sup_volt_len; i += 2) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305809 u32 mask;
5810
5811 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
5812 sup_voltages[i + 1]);
5813 if (!mask)
5814 dev_err(dev, "Invalide voltage range %d\n", i);
5815 pdata->ocr_mask |= mask;
5816 }
5817 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305818 }
5819
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005820 ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305821 &clk_table, &clk_table_len, 0);
5822 if (!ret) {
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305823 pdata->sup_clk_table = clk_table;
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305824 pdata->sup_clk_cnt = clk_table_len;
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305825 }
5826
Sujit Reddy Thummab9ff7f02012-05-04 09:57:49 +05305827 pdata->vreg_data = devm_kzalloc(dev,
5828 sizeof(struct msm_mmc_slot_reg_data), GFP_KERNEL);
5829 if (!pdata->vreg_data) {
5830 dev_err(dev, "could not allocate memory for vreg_data\n");
5831 goto err;
5832 }
5833
5834 if (msmsdcc_dt_parse_vreg_info(dev,
5835 &pdata->vreg_data->vdd_data, "vdd"))
5836 goto err;
5837
5838 if (msmsdcc_dt_parse_vreg_info(dev,
5839 &pdata->vreg_data->vdd_io_data, "vdd-io"))
5840 goto err;
5841
Sujit Reddy Thumma38459152012-06-26 00:07:59 +05305842 if (msmsdcc_dt_parse_gpio_info(dev, pdata))
5843 goto err;
5844
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005845 len = of_property_count_strings(np, "qcom,bus-speed-mode");
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305846
5847 for (i = 0; i < len; i++) {
5848 const char *name = NULL;
5849
5850 of_property_read_string_index(np,
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005851 "qcom,bus-speed-mode", i, &name);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305852 if (!name)
5853 continue;
5854
5855 if (!strncmp(name, "SDR12", sizeof("SDR12")))
5856 pdata->uhs_caps |= MMC_CAP_UHS_SDR12;
5857 else if (!strncmp(name, "SDR25", sizeof("SDR25")))
5858 pdata->uhs_caps |= MMC_CAP_UHS_SDR25;
5859 else if (!strncmp(name, "SDR50", sizeof("SDR50")))
5860 pdata->uhs_caps |= MMC_CAP_UHS_SDR50;
5861 else if (!strncmp(name, "DDR50", sizeof("DDR50")))
5862 pdata->uhs_caps |= MMC_CAP_UHS_DDR50;
5863 else if (!strncmp(name, "SDR104", sizeof("SDR104")))
5864 pdata->uhs_caps |= MMC_CAP_UHS_SDR104;
5865 else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
5866 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5867 else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
5868 pdata->uhs_caps2 |= MMC_CAP2_HS200_1_2V_SDR;
5869 else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
5870 pdata->uhs_caps |= MMC_CAP_1_8V_DDR
5871 | MMC_CAP_UHS_DDR50;
5872 else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
5873 pdata->uhs_caps |= MMC_CAP_1_2V_DDR
5874 | MMC_CAP_UHS_DDR50;
5875 }
5876
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005877 of_property_read_u32(np, "qcom,current-limit", &current_limit);
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305878 if (current_limit == 800)
5879 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
5880 else if (current_limit == 600)
5881 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_600;
5882 else if (current_limit == 400)
5883 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_400;
5884 else if (current_limit == 200)
5885 pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
5886
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005887 if (of_get_property(np, "qcom,xpc", NULL))
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05305888 pdata->xpc_cap = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005889 if (of_get_property(np, "qcom,nonremovable", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305890 pdata->nonremovable = true;
Oluwafemi Adeyemi6cdfdb82012-11-02 13:36:29 -07005891 if (of_get_property(np, "qcom,disable-cmd23", NULL))
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305892 pdata->disable_cmd23 = true;
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05305893 of_property_read_u32(np, "qcom,dat1-mpm-int",
5894 &pdata->mpm_sdiowakeup_int);
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305895
5896 return pdata;
5897err:
5898 return NULL;
5899}
5900
San Mehat9d2bd732009-09-22 16:44:22 -07005901static int
5902msmsdcc_probe(struct platform_device *pdev)
5903{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305904 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07005905 struct msmsdcc_host *host;
5906 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005907 unsigned long flags;
5908 struct resource *core_irqres = NULL;
5909 struct resource *bam_irqres = NULL;
5910 struct resource *core_memres = NULL;
5911 struct resource *dml_memres = NULL;
5912 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07005913 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07005914 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05305915 int ret = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005916
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305917 if (pdev->dev.of_node) {
5918 plat = msmsdcc_populate_pdata(&pdev->dev);
5919 of_property_read_u32((&pdev->dev)->of_node,
5920 "cell-index", &pdev->id);
5921 } else {
5922 plat = pdev->dev.platform_data;
5923 }
San Mehat9d2bd732009-09-22 16:44:22 -07005924
5925 /* must have platform data */
5926 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005927 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005928 ret = -EINVAL;
5929 goto out;
5930 }
5931
Venkat Gopalakrishnanfbcfb6e2013-01-07 15:02:23 -08005932 if (disable_slots & (1 << (pdev->id - 1))) {
5933 pr_info("%s: Slot %d disabled\n", __func__, pdev->id);
5934 return -ENODEV;
5935 }
5936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005937 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07005938 return -EINVAL;
5939
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305940 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
5941 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
5942 return -EINVAL;
5943 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005944
San Mehat9d2bd732009-09-22 16:44:22 -07005945 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005946 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005947 return -ENXIO;
5948 }
5949
Sujit Reddy Thumma1dfac2c2012-07-30 10:15:39 +05305950 core_memres = platform_get_resource_byname(pdev,
5951 IORESOURCE_MEM, "core_mem");
5952 bam_memres = platform_get_resource_byname(pdev,
5953 IORESOURCE_MEM, "bam_mem");
5954 dml_memres = platform_get_resource_byname(pdev,
5955 IORESOURCE_MEM, "dml_mem");
5956 core_irqres = platform_get_resource_byname(pdev,
5957 IORESOURCE_IRQ, "core_irq");
5958 bam_irqres = platform_get_resource_byname(pdev,
5959 IORESOURCE_IRQ, "bam_irq");
5960 dmares = platform_get_resource_byname(pdev,
5961 IORESOURCE_DMA, "dma_chnl");
5962 dma_crci_res = platform_get_resource_byname(pdev,
5963 IORESOURCE_DMA, "dma_crci");
San Mehat9d2bd732009-09-22 16:44:22 -07005964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005965 if (!core_irqres || !core_memres) {
5966 pr_err("%s: Invalid sdcc core resource\n", __func__);
5967 return -ENXIO;
5968 }
5969
5970 /*
5971 * Both BAM and DML memory resource should be preset.
5972 * BAM IRQ resource should also be present.
5973 */
5974 if ((bam_memres && !dml_memres) ||
5975 (!bam_memres && dml_memres) ||
5976 ((bam_memres && dml_memres) && !bam_irqres)) {
5977 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005978 return -ENXIO;
5979 }
5980
5981 /*
5982 * Setup our host structure
5983 */
San Mehat9d2bd732009-09-22 16:44:22 -07005984 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
5985 if (!mmc) {
5986 ret = -ENOMEM;
5987 goto out;
5988 }
5989
5990 host = mmc_priv(mmc);
Sujit Reddy Thumma7bbeebb2012-09-10 19:10:52 +05305991 host->pdev = pdev;
San Mehat9d2bd732009-09-22 16:44:22 -07005992 host->plat = plat;
5993 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08005994 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05305995
Sahitya Tummalad9df3272011-08-19 16:50:46 +05305996 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305997 set_hw_caps(host, MSMSDCC_SPS_BAM_SUP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005998 else if (dmares)
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05305999 set_hw_caps(host, MSMSDCC_DMA_SUP);
San Mehat9d2bd732009-09-22 16:44:22 -07006000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006001 host->base = ioremap(core_memres->start,
6002 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07006003 if (!host->base) {
6004 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306005 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006006 }
6007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006008 host->core_irqres = core_irqres;
6009 host->bam_irqres = bam_irqres;
6010 host->core_memres = core_memres;
6011 host->dml_memres = dml_memres;
6012 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07006013 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07006014 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07006015 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306016 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07006017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006018#ifdef CONFIG_MMC_EMBEDDED_SDIO
6019 if (plat->embedded_sdio)
6020 mmc_set_embedded_sdio_data(mmc,
6021 &plat->embedded_sdio->cis,
6022 &plat->embedded_sdio->cccr,
6023 plat->embedded_sdio->funcs,
6024 plat->embedded_sdio->num_funcs);
6025#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006026
Sahitya Tummala62612cf2010-12-08 15:03:03 +05306027 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
6028 (unsigned long)host);
6029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006030 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
6031 (unsigned long)host);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306032 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006033 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05306034 ret = msmsdcc_init_dma(host);
6035 if (ret)
6036 goto ioremap_free;
6037 } else {
6038 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07006039 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05306040 }
San Mehat9d2bd732009-09-22 16:44:22 -07006041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006042 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306043 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006044 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306045 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
6046 if (!IS_ERR_OR_NULL(host->bus_clk)) {
6047 /* Vote for max. clk rate for max. performance */
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05306048 ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306049 if (ret)
6050 goto bus_clk_put;
6051 ret = clk_prepare_enable(host->bus_clk);
6052 if (ret)
6053 goto bus_clk_put;
Sujit Reddy Thumma07a5f2f2013-04-25 14:50:32 +05306054 host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
San Mehat9d2bd732009-09-22 16:44:22 -07006055 }
6056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006057 /*
6058 * Setup main peripheral bus clock
6059 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006060 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006061 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05306062 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006063 if (ret)
6064 goto pclk_put;
6065
6066 host->pclk_rate = clk_get_rate(host->pclk);
6067 }
6068
6069 /*
6070 * Setup SDC MMC clock
6071 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07006072 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07006073 if (IS_ERR(host->clk)) {
6074 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006075 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07006076 }
6077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006078 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05306079 if (ret) {
6080 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
6081 goto clk_put;
6082 }
6083
Asutosh Dasf5298c32012-04-03 14:51:47 +05306084 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006085 if (ret)
6086 goto clk_put;
6087
San Mehat9d2bd732009-09-22 16:44:22 -07006088 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306089 if (!host->clk_rate)
6090 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05306091
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306092 set_default_hw_caps(host);
Sujit Reddy Thumma306af642012-10-26 10:02:59 +05306093 host->saved_tuning_phase = INVALID_TUNING_PHASE;
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306094
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05306095 /*
6096 * Set the register write delay according to min. clock frequency
6097 * supported and update later when the host->clk_rate changes.
6098 */
6099 host->reg_write_delay =
6100 (1 + ((3 * USEC_PER_SEC) /
6101 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006102
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306103 atomic_set(&host->clks_on, 1);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306104
6105 ret = msmsdcc_msm_bus_register(host);
6106 if (ret)
6107 goto clk_disable;
6108
6109 if (host->msm_bus_vote.client_handle)
6110 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
6111 msmsdcc_msm_bus_work);
6112
6113 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
6114
Subhash Jadavani15f29db2011-10-13 09:57:13 +05306115 /* Apply Hard reset to SDCC to put it in power on default state */
6116 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006117
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006118#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306119 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006120 if (host->plat->cpu_dma_latency)
6121 host->cpu_dma_latency = host->plat->cpu_dma_latency;
6122 else
6123 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
6124 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306125 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
6126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006127 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07006128 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006129 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306130 goto pm_qos_remove;
San Mehat9d2bd732009-09-22 16:44:22 -07006131 }
6132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006133
6134 /* Clocks has to be running before accessing SPS/DML HW blocks */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306135 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006136 /* Initialize SPS */
6137 ret = msmsdcc_sps_init(host);
6138 if (ret)
6139 goto vreg_deinit;
6140 /* Initialize DML */
6141 ret = msmsdcc_dml_init(host);
6142 if (ret)
6143 goto sps_exit;
6144 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05306145 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07006146
San Mehat9d2bd732009-09-22 16:44:22 -07006147 /*
6148 * Setup MMC host structure
6149 */
6150 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006151 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
6152 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006153 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05306154 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
6155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006156 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
6157 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07006158 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05306159 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Asutosh Dasebd7d092012-07-09 19:08:26 +05306160 mmc->caps |= MMC_CAP_HW_RESET;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306161 /*
6162 * If we send the CMD23 before multi block write/read command
6163 * then we need not to send CMD12 at the end of the transfer.
6164 * If we don't send the CMD12 then only way to detect the PROG_DONE
6165 * status is to use the AUTO_PROG_DONE status provided by SDCC4
6166 * controller. So let's enable the CMD23 for SDCC4 only.
6167 */
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306168 if (!plat->disable_cmd23 && is_auto_prog_done(host))
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05306169 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07006170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171 mmc->caps |= plat->uhs_caps;
Sujit Reddy Thumma824b7522012-05-30 13:04:34 +05306172 mmc->caps2 |= plat->uhs_caps2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006173 /*
6174 * XPC controls the maximum current in the default speed mode of SDXC
6175 * card. XPC=0 means 100mA (max.) but speed class is not supported.
6176 * XPC=1 means 150mA (max.) and speed class is supported.
6177 */
6178 if (plat->xpc_cap)
6179 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
6180 MMC_CAP_SET_XPC_180);
6181
Tatyana Brokhman34a444f2012-10-07 10:12:25 +02006182 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Tatyana Brokhmandffdbad2012-10-04 11:10:13 +02006183 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05306184 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03006185 mmc->caps2 |= MMC_CAP2_SANITIZE;
Yaniv Gardi19e21062012-09-16 10:42:21 +03006186 mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
Tatyana Brokhmanf495d1b2012-10-15 22:43:35 +02006187 mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
Konstantin Dorfmana2c84222013-03-12 15:33:53 +02006188 mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
Subhash Jadavani69245882013-05-27 16:58:41 +05306189 mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
Yaniv Gardi14098552012-06-04 10:56:03 +03006190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006191 if (plat->nonremovable)
6192 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006193 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006194
6195 if (plat->is_sdio_al_client)
6196 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07006197
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306198 mmc->max_segs = msmsdcc_get_nr_sg(host);
6199 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
6200 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07006201
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05306202 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07006203 mmc->max_seg_size = mmc->max_req_size;
6204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006205 writel_relaxed(0, host->base + MMCIMASK0);
6206 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05306207 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07006208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006209 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
6210 mb();
6211 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07006212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006213 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
6214 DRIVER_NAME " (cmd)", host);
6215 if (ret)
6216 goto dml_exit;
6217
6218 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
6219 DRIVER_NAME " (pio)", host);
6220 if (ret)
6221 goto irq_free;
6222
6223 /*
6224 * Enable SDCC IRQ only when host is powered on. Otherwise, this
6225 * IRQ is un-necessarily being monitored by MPM (Modem power
6226 * management block) during idle-power collapse. The MPM will be
6227 * configured to monitor the DATA1 GPIO line with level-low trigger
6228 * and thus depending on the GPIO status, it prevents TCXO shutdown
6229 * during idle-power collapse.
6230 */
6231 disable_irq(core_irqres->start);
6232 host->sdcc_irq_disabled = 1;
6233
Sujit Reddy Thummad7cdadc2012-08-27 12:44:04 +05306234 if (!plat->sdiowakeup_irq) {
6235 /* Check if registered as IORESOURCE_IRQ */
6236 plat->sdiowakeup_irq =
6237 platform_get_irq_byname(pdev, "sdiowakeup_irq");
6238 if (plat->sdiowakeup_irq < 0)
6239 plat->sdiowakeup_irq = 0;
6240 }
6241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006242 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006243 ret = request_irq(plat->sdiowakeup_irq,
6244 msmsdcc_platform_sdiowakeup_irq,
6245 IRQF_SHARED | IRQF_TRIGGER_LOW,
6246 DRIVER_NAME "sdiowakeup", host);
6247 if (ret) {
6248 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
6249 plat->sdiowakeup_irq, ret);
6250 goto pio_irq_free;
6251 } else {
6252 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306253 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006254 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306255 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006256 }
6257 spin_unlock_irqrestore(&host->lock, flags);
6258 }
6259 }
6260
Krishna Konda1963f432013-02-19 20:28:53 -08006261 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006262 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
6263 mmc_hostname(mmc));
6264 }
6265
6266 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
6267 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006268 /*
6269 * Setup card detect change
6270 */
6271
Sujit Reddy Thummaf61d2e72012-06-22 15:56:39 +05306272 if (!plat->status_gpio)
6273 plat->status_gpio = -ENOENT;
6274 if (!plat->wpswitch_gpio)
6275 plat->wpswitch_gpio = -ENOENT;
6276
6277 if (plat->status || gpio_is_valid(plat->status_gpio)) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306278 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006279 host->oldstat = plat->status(mmc_dev(host->mmc));
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306280 } else {
6281 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006282 host->oldstat = msmsdcc_slot_status(host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306283 }
Krishna Konda941604a2012-01-10 17:46:34 -08006284 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006285 }
San Mehat9d2bd732009-09-22 16:44:22 -07006286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006287 if (plat->status_irq) {
6288 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07006289 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006290 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07006291 DRIVER_NAME " (slot)",
6292 host);
6293 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006294 pr_err("Unable to get slot IRQ %d (%d)\n",
6295 plat->status_irq, ret);
6296 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07006297 }
6298 } else if (plat->register_status_notify) {
6299 plat->register_status_notify(msmsdcc_status_notify_cb, host);
6300 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006301 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07006302 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006303
6304 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006305
6306 ret = pm_runtime_set_active(&(pdev)->dev);
6307 if (ret < 0)
6308 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
6309 __func__, ret);
6310 /*
6311 * There is no notion of suspend/resume for SD/MMC/SDIO
6312 * cards. So host can be suspended/resumed with out
6313 * worrying about its children.
6314 */
6315 pm_suspend_ignore_children(&(pdev)->dev, true);
6316
6317 /*
6318 * MMC/SD/SDIO bus suspend/resume operations are defined
6319 * only for the slots that will be used for non-removable
6320 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
6321 * defined. Otherwise, they simply become card removal and
6322 * insertion events during suspend and resume respectively.
6323 * Hence, enable run-time PM only for slots for which bus
6324 * suspend/resume operations are defined.
6325 */
6326#ifdef CONFIG_MMC_UNSAFE_RESUME
6327 /*
6328 * If this capability is set, MMC core will enable/disable host
6329 * for every claim/release operation on a host. We use this
6330 * notification to increment/decrement runtime pm usage count.
6331 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006332 pm_runtime_enable(&(pdev)->dev);
6333#else
6334 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006335 pm_runtime_enable(&(pdev)->dev);
6336 }
6337#endif
Pratibhasagar V713817b2012-09-07 11:28:30 +05306338 host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006339 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
6340 (unsigned long)host);
6341
San Mehat9d2bd732009-09-22 16:44:22 -07006342 mmc_add_host(mmc);
6343
Sujit Reddy Thumma97a35d22012-10-31 22:45:45 +05306344 mmc->clk_scaling.up_threshold = 35;
6345 mmc->clk_scaling.down_threshold = 5;
6346 mmc->clk_scaling.polling_delay_ms = 100;
6347 mmc->caps2 |= MMC_CAP2_CLK_SCALE;
6348
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006349 pr_info("%s: Qualcomm MSM SDCC-core %pr %pr,%d dma %d dmacrcri %d\n",
6350 mmc_hostname(mmc), core_memres, core_irqres,
Krishna Konda25786ec2011-07-25 16:21:36 -07006351 (unsigned int) plat->status_irq, host->dma.channel,
6352 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006353
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306354 pr_info("%s: Controller capabilities: 0x%.8x\n",
6355 mmc_hostname(mmc), host->hw_caps);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006356 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
6357 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
6358 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
6359 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
6360 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
6361 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
6362 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
6363 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
6364 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
6365 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
6366 host->eject);
6367 pr_info("%s: Power save feature enable = %d\n",
6368 mmc_hostname(mmc), msmsdcc_pwrsave);
6369
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306370 if (is_dma_mode(host) && host->dma.channel != -1
Krishna Konda25786ec2011-07-25 16:21:36 -07006371 && host->dma.crci != -1) {
Venkat Gopalakrishnan28ded7f2013-03-29 19:50:14 -07006372 pr_info("%s: DM non-cached buffer at %p, dma_addr: %pa\n",
6373 mmc_hostname(mmc), host->dma.nc, &host->dma.nc_busaddr);
6374 pr_info("%s: DM cmd busaddr: %pa, cmdptr busaddr: %pa\n",
6375 mmc_hostname(mmc), &host->dma.cmd_busaddr,
6376 &host->dma.cmdptr_busaddr);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306377 } else if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006378 pr_info("%s: SPS-BAM data transfer mode available\n",
6379 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006380 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07006381 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07006382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006383#if defined(CONFIG_DEBUG_FS)
6384 msmsdcc_dbg_createhost(host);
6385#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306386
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306387 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
6388 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
6389 sysfs_attr_init(&host->max_bus_bw.attr);
6390 host->max_bus_bw.attr.name = "max_bus_bw";
6391 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
6392 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306393 if (ret)
6394 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306395
6396 if (!plat->status_irq) {
6397 host->polling.show = show_polling;
6398 host->polling.store = store_polling;
6399 sysfs_attr_init(&host->polling.attr);
6400 host->polling.attr.name = "polling";
6401 host->polling.attr.mode = S_IRUGO | S_IWUSR;
6402 ret = device_create_file(&pdev->dev, &host->polling);
6403 if (ret)
6404 goto remove_max_bus_bw_file;
6405 }
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306406 host->idle_timeout.show = show_idle_timeout;
6407 host->idle_timeout.store = store_idle_timeout;
6408 sysfs_attr_init(&host->idle_timeout.attr);
6409 host->idle_timeout.attr.name = "idle_timeout";
6410 host->idle_timeout.attr.mode = S_IRUGO | S_IWUSR;
6411 ret = device_create_file(&pdev->dev, &host->idle_timeout);
6412 if (ret)
6413 goto remove_polling_file;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306414
6415 if (!is_auto_cmd19(host))
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306416 goto add_auto_cmd21_atrr;
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306417
6418 /* Sysfs entry for AUTO CMD19 control */
6419 host->auto_cmd19_attr.show = show_enable_auto_cmd19;
6420 host->auto_cmd19_attr.store = store_enable_auto_cmd19;
6421 sysfs_attr_init(&host->auto_cmd19_attr.attr);
6422 host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
6423 host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
6424 ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
6425 if (ret)
6426 goto remove_idle_timeout_file;
6427
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306428 add_auto_cmd21_atrr:
6429 if (!is_auto_cmd21(host))
6430 goto exit;
6431
6432 /* Sysfs entry for AUTO CMD21 control */
6433 host->auto_cmd21_attr.show = show_enable_auto_cmd21;
6434 host->auto_cmd21_attr.store = store_enable_auto_cmd21;
6435 sysfs_attr_init(&host->auto_cmd21_attr.attr);
6436 host->auto_cmd21_attr.attr.name = "enable_auto_cmd21";
6437 host->auto_cmd21_attr.attr.mode = S_IRUGO | S_IWUSR;
6438 ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
6439 if (ret)
6440 goto remove_auto_cmd19_attr_file;
6441
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306442 exit:
San Mehat9d2bd732009-09-22 16:44:22 -07006443 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006444
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306445 remove_auto_cmd19_attr_file:
6446 if (is_auto_cmd19(host))
6447 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306448 remove_idle_timeout_file:
6449 device_remove_file(&pdev->dev, &host->idle_timeout);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306450 remove_polling_file:
6451 if (!plat->status_irq)
6452 device_remove_file(&pdev->dev, &host->polling);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306453 remove_max_bus_bw_file:
6454 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006455 platform_irq_free:
6456 del_timer_sync(&host->req_tout_timer);
6457 pm_runtime_disable(&(pdev)->dev);
6458 pm_runtime_set_suspended(&(pdev)->dev);
6459
6460 if (plat->status_irq)
6461 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306462 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006463 sdiowakeup_irq_free:
Krishna Konda1963f432013-02-19 20:28:53 -08006464 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6465 wake_lock_destroy(&host->sdio_wlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006466 wake_lock_destroy(&host->sdio_suspend_wlock);
6467 if (plat->sdiowakeup_irq)
6468 free_irq(plat->sdiowakeup_irq, host);
6469 pio_irq_free:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006470 free_irq(core_irqres->start, host);
6471 irq_free:
6472 free_irq(core_irqres->start, host);
6473 dml_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306474 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006475 msmsdcc_dml_exit(host);
6476 sps_exit:
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306477 if (is_sps_mode(host))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006478 msmsdcc_sps_exit(host);
6479 vreg_deinit:
6480 msmsdcc_vreg_init(host, false);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306481 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006482 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306483 pm_qos_remove_request(&host->pm_qos_req_dma);
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306484 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6485 msmsdcc_msm_bus_unregister(host);
6486 clk_disable:
6487 clk_disable_unprepare(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07006488 clk_put:
6489 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006490 pclk_disable:
6491 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05306492 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07006493 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006494 if (!IS_ERR(host->pclk))
6495 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306496 if (!IS_ERR_OR_NULL(host->bus_clk))
6497 clk_disable_unprepare(host->bus_clk);
6498 bus_clk_put:
6499 if (!IS_ERR_OR_NULL(host->bus_clk))
6500 clk_put(host->bus_clk);
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306501 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006502 if (host->dmares)
6503 dma_free_coherent(NULL,
6504 sizeof(struct msmsdcc_nc_dmadata),
6505 host->dma.nc, host->dma.nc_busaddr);
6506 }
6507 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05306508 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07006509 host_free:
6510 mmc_free_host(mmc);
6511 out:
6512 return ret;
6513}
6514
Pratibhasagar V713817b2012-09-07 11:28:30 +05306515#ifdef CONFIG_DEBUG_FS
6516static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
6517{
6518 debugfs_remove_recursive(host->debugfs_host_dir);
6519 host->debugfs_host_dir = NULL;
6520}
6521#else
6522static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
6523#endif
6524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006525static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07006526{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006527 struct mmc_host *mmc = mmc_get_drvdata(pdev);
6528 struct mmc_platform_data *plat;
6529 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006531 if (!mmc)
6532 return -ENXIO;
6533
6534 if (pm_runtime_suspended(&(pdev)->dev))
6535 pm_runtime_resume(&(pdev)->dev);
6536
6537 host = mmc_priv(mmc);
6538
6539 DBG(host, "Removing SDCC device = %d\n", pdev->id);
6540 plat = host->plat;
6541
Subhash Jadavanie5c2e712012-08-28 16:31:48 +05306542 if (is_auto_cmd19(host))
6543 device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
Subhash Jadavani2bb781e2012-08-28 18:33:15 +05306544 if (is_auto_cmd21(host))
6545 device_remove_file(&pdev->dev, &host->auto_cmd21_attr);
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306546 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006547 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05306548 device_remove_file(&pdev->dev, &host->polling);
Pratibhasagar V13d1d032012-07-09 20:12:38 +05306549 device_remove_file(&pdev->dev, &host->idle_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006550
Pratibhasagar V713817b2012-09-07 11:28:30 +05306551 msmsdcc_remove_debugfs(host);
6552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006553 del_timer_sync(&host->req_tout_timer);
6554 tasklet_kill(&host->dma_tlet);
6555 tasklet_kill(&host->sps.tlet);
6556 mmc_remove_host(mmc);
6557
6558 if (plat->status_irq)
6559 free_irq(plat->status_irq, host);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306560 msmsdcc_disable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006561
6562 wake_lock_destroy(&host->sdio_suspend_wlock);
6563 if (plat->sdiowakeup_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006564 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
6565 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07006566 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006567
Krishna Konda1963f432013-02-19 20:28:53 -08006568 if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
6569 wake_lock_destroy(&host->sdio_wlock);
6570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006571 free_irq(host->core_irqres->start, host);
6572 free_irq(host->core_irqres->start, host);
6573
6574 clk_put(host->clk);
6575 if (!IS_ERR(host->pclk))
6576 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05306577 if (!IS_ERR_OR_NULL(host->bus_clk))
6578 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006579
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07006580 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05306581 pm_qos_remove_request(&host->pm_qos_req_dma);
6582
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306583 if (host->msm_bus_vote.client_handle) {
6584 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
6585 msmsdcc_msm_bus_unregister(host);
6586 }
6587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006588 msmsdcc_vreg_init(host, false);
6589
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306590 if (is_dma_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006591 if (host->dmares)
6592 dma_free_coherent(NULL,
6593 sizeof(struct msmsdcc_nc_dmadata),
6594 host->dma.nc, host->dma.nc_busaddr);
6595 }
6596
Sujit Reddy Thumma01bc8712012-06-21 12:07:47 +05306597 if (is_sps_mode(host)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006598 msmsdcc_dml_exit(host);
6599 msmsdcc_sps_exit(host);
6600 }
6601
6602 iounmap(host->base);
6603 mmc_free_host(mmc);
6604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006605 pm_runtime_disable(&(pdev)->dev);
6606 pm_runtime_set_suspended(&(pdev)->dev);
6607
6608 return 0;
6609}
6610
6611#ifdef CONFIG_MSM_SDIO_AL
6612int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6613{
6614 struct msmsdcc_host *host = mmc_priv(mmc);
6615 unsigned long flags;
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306616 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006617
Asutosh Dasf5298c32012-04-03 14:51:47 +05306618 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006619 spin_lock_irqsave(&host->lock, flags);
6620 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
6621 enable ? "En" : "Dis");
6622
6623 if (enable) {
6624 if (!host->sdcc_irq_disabled) {
6625 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05306626 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006627 host->sdcc_irq_disabled = 1;
6628 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306629 rc = msmsdcc_setup_clocks(host, false);
6630 if (rc)
6631 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006632
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306633 if (host->plat->sdio_lpm_gpio_setup &&
6634 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006635 spin_unlock_irqrestore(&host->lock, flags);
6636 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
6637 spin_lock_irqsave(&host->lock, flags);
6638 host->sdio_gpio_lpm = 1;
6639 }
6640
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306641 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006642 msmsdcc_enable_irq_wake(host);
6643 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306644 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006645 }
6646 } else {
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306647 rc = msmsdcc_setup_clocks(host, true);
6648 if (rc)
6649 goto out;
6650
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306651 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006652 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306653 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006654 msmsdcc_disable_irq_wake(host);
6655 }
6656
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05306657 if (host->plat->sdio_lpm_gpio_setup &&
6658 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006659 spin_unlock_irqrestore(&host->lock, flags);
6660 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
6661 spin_lock_irqsave(&host->lock, flags);
6662 host->sdio_gpio_lpm = 0;
6663 }
6664
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306665 if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006666 writel_relaxed(host->mci_irqenable,
6667 host->base + MMCIMASK0);
6668 mb();
6669 enable_irq(host->core_irqres->start);
6670 host->sdcc_irq_disabled = 0;
6671 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006672 }
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306673out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006674 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05306675 mutex_unlock(&host->clk_mutex);
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306676 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006677}
6678#else
6679int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
6680{
6681 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07006682}
6683#endif
6684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006685#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306686#ifdef CONFIG_MMC_CLKGATE
6687static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6688{
6689 struct mmc_host *mmc = host->mmc;
6690 unsigned long flags;
6691
6692 mmc_host_clk_hold(mmc);
6693 spin_lock_irqsave(&mmc->clk_lock, flags);
6694 mmc->clk_old = mmc->ios.clock;
6695 mmc->ios.clock = 0;
6696 mmc->clk_gated = true;
6697 spin_unlock_irqrestore(&mmc->clk_lock, flags);
6698 mmc_set_ios(mmc);
6699 mmc_host_clk_release(mmc);
6700}
6701
6702static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6703{
6704 struct mmc_host *mmc = host->mmc;
6705
6706 mmc_host_clk_hold(mmc);
6707 mmc->ios.clock = host->clk_rate;
6708 mmc_set_ios(mmc);
6709 mmc_host_clk_release(mmc);
6710}
6711#else
6712static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
6713{
6714 struct mmc_host *mmc = host->mmc;
6715
6716 mmc->ios.clock = 0;
6717 mmc_set_ios(mmc);
6718}
6719
6720static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
6721{
6722 struct mmc_host *mmc = host->mmc;
6723
6724 mmc->ios.clock = host->clk_rate;
6725 mmc_set_ios(mmc);
6726}
6727#endif
6728
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306729#if CONFIG_DEBUG_FS
6730static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306731 const char *func, int err)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306732{
6733 ktime_t diff;
6734
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306735 if (host->print_pm_stats && !err) {
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306736 diff = ktime_sub(ktime_get(), start);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306737 pr_info("%s: %s: Completed in %llu usec\n",
6738 mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306739 }
6740}
6741#else
6742static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306743 const char *func, int err) {}
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306744#endif
6745
San Mehat9d2bd732009-09-22 16:44:22 -07006746static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006747msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006748{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006749 struct mmc_host *mmc = dev_get_drvdata(dev);
6750 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006751 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306752 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306753 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006754
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306755 if (host->plat->is_sdio_al_client) {
6756 rc = 0;
6757 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006758 }
San Mehat9d2bd732009-09-22 16:44:22 -07006759
Sahitya Tummala7661a452011-07-18 13:28:35 +05306760 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006761 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006762 host->sdcc_suspending = 1;
6763 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07006764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006765 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006766 * MMC core thinks that host is disabled by now since
6767 * runtime suspend is scheduled after msmsdcc_disable()
6768 * is called. Thus, MMC core will try to enable the host
6769 * while suspending it. This results in a synchronous
6770 * runtime resume request while in runtime suspending
6771 * context and hence inorder to complete this resume
6772 * requet, it will wait for suspend to be complete,
6773 * but runtime suspend also can not proceed further
6774 * until the host is resumed. Thus, it leads to a hang.
6775 * Hence, increase the pm usage count before suspending
6776 * the host so that any resume requests after this will
6777 * simple become pm usage counter increment operations.
6778 */
6779 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306780 /* If there is pending detect work abort runtime suspend */
6781 if (unlikely(work_busy(&mmc->detect.work)))
6782 rc = -EAGAIN;
6783 else
6784 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006785 pm_runtime_put_noidle(dev);
6786
6787 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306788 spin_lock_irqsave(&host->lock, flags);
6789 host->sdcc_suspended = true;
6790 spin_unlock_irqrestore(&host->lock, flags);
6791 if (mmc->card && mmc_card_sdio(mmc->card) &&
6792 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006793 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306794 * If SDIO function driver doesn't want
6795 * to power off the card, atleast turn off
6796 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006797 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306798 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006799 }
6800 }
6801 host->sdcc_suspending = 0;
6802 mmc->suspend_task = NULL;
6803 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
6804 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006805 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05306806 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05306807out:
Sahitya Tummalaa368d0b2013-05-29 15:22:56 +05306808 /*
6809 * Remove the vote immediately only if clocks are off in which
6810 * case we might have queued work to remove vote but it may not
6811 * be completed before runtime suspend or system suspend.
6812 */
6813 if (!atomic_read(&host->clks_on))
6814 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306815 msmsdcc_print_pm_stats(host, start, __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07006816 return rc;
6817}
6818
6819static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006820msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07006821{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006822 struct mmc_host *mmc = dev_get_drvdata(dev);
6823 struct msmsdcc_host *host = mmc_priv(mmc);
6824 unsigned long flags;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306825 ktime_t start = ktime_get();
San Mehat9d2bd732009-09-22 16:44:22 -07006826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006827 if (host->plat->is_sdio_al_client)
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306828 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07006829
Sahitya Tummala7661a452011-07-18 13:28:35 +05306830 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07006831 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306832 if (mmc->card && mmc_card_sdio(mmc->card) &&
6833 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05306834 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05306835 }
San Mehat9d2bd732009-09-22 16:44:22 -07006836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006837 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07006838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006839 /*
6840 * FIXME: Clearing of flags must be handled in clients
6841 * resume handler.
6842 */
6843 spin_lock_irqsave(&host->lock, flags);
6844 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306845 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006846 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07006847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006848 /*
6849 * After resuming the host wait for sometime so that
6850 * the SDIO work will be processed.
6851 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306852 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05306853 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006854 host->plat->sdiowakeup_irq) &&
6855 wake_lock_active(&host->sdio_wlock))
6856 wake_lock_timeout(&host->sdio_wlock, 1);
6857 }
6858
6859 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07006860 }
Subhash Jadavani386ad802012-08-16 18:46:57 +05306861 host->pending_resume = false;
Sahitya Tummala7661a452011-07-18 13:28:35 +05306862 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306863out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306864 msmsdcc_print_pm_stats(host, start, __func__, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07006865 return 0;
6866}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006867
6868static int msmsdcc_runtime_idle(struct device *dev)
6869{
6870 struct mmc_host *mmc = dev_get_drvdata(dev);
6871 struct msmsdcc_host *host = mmc_priv(mmc);
6872
6873 if (host->plat->is_sdio_al_client)
6874 return 0;
6875
6876 /* Idle timeout is not configurable for now */
Pratibhasagar V713817b2012-09-07 11:28:30 +05306877 pm_schedule_suspend(dev, host->idle_tout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006878
6879 return -EAGAIN;
6880}
6881
6882static int msmsdcc_pm_suspend(struct device *dev)
6883{
6884 struct mmc_host *mmc = dev_get_drvdata(dev);
6885 struct msmsdcc_host *host = mmc_priv(mmc);
6886 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306887 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006888
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306889 if (host->plat->is_sdio_al_client) {
6890 rc = 0;
6891 goto out;
6892 }
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306893 if (host->plat->status_irq) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006894 disable_irq(host->plat->status_irq);
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306895 msmsdcc_disable_status_gpio(host);
6896 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006897
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306898 /*
6899 * If system comes out of suspend, msmsdcc_pm_resume() sets the
6900 * host->pending_resume flag if the SDCC wasn't runtime suspended.
6901 * Now if the system again goes to suspend without any SDCC activity
6902 * then host->pending_resume flag will remain set which may cause
6903 * the SDCC resume to happen first and then suspend.
6904 * To avoid this unnecessary resume/suspend, make sure that
6905 * pending_resume flag is cleared before calling the
6906 * msmsdcc_runtime_suspend().
6907 */
6908 if (!pm_runtime_suspended(dev) && !host->pending_resume)
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006909 rc = msmsdcc_runtime_suspend(dev);
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306910 out:
Subhash Jadavani444f1f02013-01-08 17:54:12 +05306911 /* This flag must not be set if system is entering into suspend */
6912 host->pending_resume = false;
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306913 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006914 return rc;
6915}
6916
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306917static int msmsdcc_suspend_noirq(struct device *dev)
6918{
6919 struct mmc_host *mmc = dev_get_drvdata(dev);
6920 struct msmsdcc_host *host = mmc_priv(mmc);
6921 int rc = 0;
6922
6923 /*
6924 * After platform suspend there may be active request
6925 * which might have enabled clocks. For example, in SDIO
6926 * case, ksdioirq thread might have scheduled after sdcc
6927 * suspend but before system freeze. In that case abort
6928 * suspend and retry instead of keeping the clocks on
6929 * during suspend and not allowing TCXO.
6930 */
6931
Pratibhasagar V89cfcd72012-06-14 18:13:26 +05306932 if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05306933 pr_warn("%s: clocks are on after suspend, aborting system "
6934 "suspend\n", mmc_hostname(mmc));
6935 rc = -EAGAIN;
6936 }
6937
6938 return rc;
6939}
6940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006941static int msmsdcc_pm_resume(struct device *dev)
6942{
6943 struct mmc_host *mmc = dev_get_drvdata(dev);
6944 struct msmsdcc_host *host = mmc_priv(mmc);
6945 int rc = 0;
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306946 ktime_t start = ktime_get();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006947
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306948 if (host->plat->is_sdio_al_client) {
6949 rc = 0;
6950 goto out;
6951 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006952 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05306953 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavani386ad802012-08-16 18:46:57 +05306954 /*
6955 * As runtime PM is enabled before calling the device's platform resume
6956 * callback, we use the pm_runtime_suspended API to know if SDCC is
6957 * really runtime suspended or not and set the pending_resume flag only
6958 * if its not runtime suspended.
6959 */
6960 else if (!pm_runtime_suspended(dev))
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006961 host->pending_resume = true;
6962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006963 if (host->plat->status_irq) {
Subhash Jadavani4981cefc2012-10-10 09:55:04 +05306964 msmsdcc_enable_status_gpio(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006965 msmsdcc_check_status((unsigned long)host);
6966 enable_irq(host->plat->status_irq);
6967 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05306968out:
Subhash Jadavania5ae4d02012-11-28 18:37:06 +05306969 msmsdcc_print_pm_stats(host, start, __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006970 return rc;
6971}
6972
Daniel Walker08ecfde2010-06-23 12:32:20 -07006973#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07006974static int msmsdcc_runtime_suspend(struct device *dev)
6975{
6976 return 0;
6977}
6978static int msmsdcc_runtime_idle(struct device *dev)
6979{
6980 return 0;
6981}
6982static int msmsdcc_pm_suspend(struct device *dev)
6983{
6984 return 0;
6985}
6986static int msmsdcc_pm_resume(struct device *dev)
6987{
6988 return 0;
6989}
6990static int msmsdcc_suspend_noirq(struct device *dev)
6991{
6992 return 0;
6993}
6994static int msmsdcc_runtime_resume(struct device *dev)
6995{
6996 return 0;
6997}
Daniel Walker08ecfde2010-06-23 12:32:20 -07006998#endif
San Mehat9d2bd732009-09-22 16:44:22 -07006999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007000static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
7001 .runtime_suspend = msmsdcc_runtime_suspend,
7002 .runtime_resume = msmsdcc_runtime_resume,
7003 .runtime_idle = msmsdcc_runtime_idle,
7004 .suspend = msmsdcc_pm_suspend,
7005 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05307006 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007007};
7008
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05307009static const struct of_device_id msmsdcc_dt_match[] = {
7010 {.compatible = "qcom,msm-sdcc"},
7011
7012};
7013MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
7014
San Mehat9d2bd732009-09-22 16:44:22 -07007015static struct platform_driver msmsdcc_driver = {
7016 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007017 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07007018 .driver = {
7019 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007020 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05307021 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07007022 },
7023};
7024
7025static int __init msmsdcc_init(void)
7026{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007027#if defined(CONFIG_DEBUG_FS)
7028 int ret = 0;
7029 ret = msmsdcc_dbg_init();
7030 if (ret) {
7031 pr_err("Failed to create debug fs dir \n");
7032 return ret;
7033 }
7034#endif
San Mehat9d2bd732009-09-22 16:44:22 -07007035 return platform_driver_register(&msmsdcc_driver);
7036}
San Mehat9d2bd732009-09-22 16:44:22 -07007037
San Mehat9d2bd732009-09-22 16:44:22 -07007038static void __exit msmsdcc_exit(void)
7039{
7040 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007041
7042#if defined(CONFIG_DEBUG_FS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007043 debugfs_remove(debugfs_dir);
7044#endif
San Mehat9d2bd732009-09-22 16:44:22 -07007045}
7046
7047module_init(msmsdcc_init);
7048module_exit(msmsdcc_exit);
7049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007050MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07007051MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007052
7053#if defined(CONFIG_DEBUG_FS)
Pratibhasagar V713817b2012-09-07 11:28:30 +05307054static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007055{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307056 struct msmsdcc_host *host = data;
7057
7058 *val = host->idle_tout / 1000L;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007059 return 0;
7060}
7061
Pratibhasagar V713817b2012-09-07 11:28:30 +05307062static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007063{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307064 struct msmsdcc_host *host = data;
7065 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007066
Pratibhasagar V713817b2012-09-07 11:28:30 +05307067 spin_lock_irqsave(&host->lock, flags);
7068 host->idle_tout = (u32)val * 1000;
7069 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007070
Pratibhasagar V713817b2012-09-07 11:28:30 +05307071 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007072}
7073
Pratibhasagar V713817b2012-09-07 11:28:30 +05307074DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
7075 msmsdcc_dbg_idle_tout_get,
7076 msmsdcc_dbg_idle_tout_set,
7077 "%llu\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007078
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307079static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
7080{
7081 struct msmsdcc_host *host = data;
7082
7083 *val = (u64) host->enforce_pio_mode;
7084 return 0;
7085}
7086
7087static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
7088{
7089 struct msmsdcc_host *host = data;
7090 unsigned long flags;
7091
7092 spin_lock_irqsave(&host->lock, flags);
7093 host->enforce_pio_mode = !!val;
7094 spin_unlock_irqrestore(&host->lock, flags);
7095
7096 return 0;
7097}
7098
7099DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
7100 msmsdcc_dbg_pio_mode_get,
7101 msmsdcc_dbg_pio_mode_set,
7102 "%llu\n");
7103
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307104static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
7105{
7106 struct msmsdcc_host *host = data;
7107
7108 *val = !!host->print_pm_stats;
7109 return 0;
7110}
7111
7112static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
7113{
7114 struct msmsdcc_host *host = data;
7115 unsigned long flags;
7116
7117 spin_lock_irqsave(&host->lock, flags);
7118 host->print_pm_stats = !!val;
7119 spin_unlock_irqrestore(&host->lock, flags);
7120
7121 return 0;
7122}
7123
7124DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
7125 msmsdcc_dbg_pm_stats_get,
7126 msmsdcc_dbg_pm_stats_set,
7127 "%llu\n");
7128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007129static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
7130{
Pratibhasagar V713817b2012-09-07 11:28:30 +05307131 int err = 0;
7132
7133 if (!debugfs_dir)
7134 return;
7135
7136 host->debugfs_host_dir = debugfs_create_dir(
7137 mmc_hostname(host->mmc), debugfs_dir);
7138 if (IS_ERR(host->debugfs_host_dir)) {
7139 err = PTR_ERR(host->debugfs_host_dir);
7140 host->debugfs_host_dir = NULL;
7141 pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
7142 mmc_hostname(host->mmc), err);
7143 return;
7144 }
7145
7146 host->debugfs_idle_tout = debugfs_create_file("idle_tout",
7147 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7148 &msmsdcc_dbg_idle_tout_ops);
7149
7150 if (IS_ERR(host->debugfs_idle_tout)) {
7151 err = PTR_ERR(host->debugfs_idle_tout);
7152 host->debugfs_idle_tout = NULL;
7153 pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
7154 mmc_hostname(host->mmc), err);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007155 }
Pratibhasagar V889d61c2012-09-09 19:51:14 +05307156
7157 host->debugfs_pio_mode = debugfs_create_file("pio_mode",
7158 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7159 &msmsdcc_dbg_pio_mode_ops);
7160
7161 if (IS_ERR(host->debugfs_pio_mode)) {
7162 err = PTR_ERR(host->debugfs_pio_mode);
7163 host->debugfs_pio_mode = NULL;
7164 pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
7165 mmc_hostname(host->mmc), err);
7166 }
Pratibhasagar Vc5e5f792012-09-09 20:09:02 +05307167
7168 host->debugfs_pm_stats = debugfs_create_file("pm_stats",
7169 S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
7170 &msmsdcc_dbg_pm_stats_ops);
7171 if (IS_ERR(host->debugfs_pm_stats)) {
7172 err = PTR_ERR(host->debugfs_pm_stats);
7173 host->debugfs_pm_stats = NULL;
7174 pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
7175 mmc_hostname(host->mmc), err);
7176 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007177}
7178
7179static int __init msmsdcc_dbg_init(void)
7180{
7181 int err;
7182
Pratibhasagar V713817b2012-09-07 11:28:30 +05307183 debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007184 if (IS_ERR(debugfs_dir)) {
7185 err = PTR_ERR(debugfs_dir);
7186 debugfs_dir = NULL;
7187 return err;
7188 }
7189
7190 return 0;
7191}
7192#endif