blob: 2e6e42297976643e612bf97788cacf90d871529c [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.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
Subhash Jadavani933e6a62011-12-26 18:05:04 +053046#include <linux/pm_qos_params.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053057#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053058#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070059
San Mehat9d2bd732009-09-22 16:44:22 -070060#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070062
63#define DRIVER_NAME "msm-sdcc"
64
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065#define DBG(host, fmt, args...) \
66 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
67
68#define IRQ_DEBUG 0
69#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
70#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
71#define SPS_CONS_PERIPHERAL 0
72#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053073/* Use SPS only if transfer size is more than this macro */
74#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053076#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
77
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078#if defined(CONFIG_DEBUG_FS)
79static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
80static struct dentry *debugfs_dir;
81static struct dentry *debugfs_file;
82static int msmsdcc_dbg_init(void);
83#endif
84
Asutosh Dasaccacd42012-03-08 14:33:17 +053085static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
86 *data);
87
Subhash Jadavani8766e352011-11-30 11:30:32 +053088static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070089static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091static struct mmc_command dummy52cmd;
92static struct mmc_request dummy52mrq = {
93 .cmd = &dummy52cmd,
94 .data = NULL,
95 .stop = NULL,
96};
97static struct mmc_command dummy52cmd = {
98 .opcode = SD_IO_RW_DIRECT,
99 .flags = MMC_RSP_PRESENT,
100 .data = NULL,
101 .mrq = &dummy52mrq,
102};
103/*
104 * An array holding the Tuning pattern to compare with when
105 * executing a tuning cycle.
106 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530107static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
109 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
110 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
111 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
112};
San Mehat865c8062009-11-13 13:42:06 -0800113
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530114static const u32 tuning_block_128[] = {
115 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
116 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
117 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
118 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
119 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
120 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
121 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
122 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
123};
124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125#if IRQ_DEBUG == 1
126static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
127 "dattimeout", "txunderrun", "rxoverrun",
128 "cmdrespend", "cmdsent", "dataend", NULL,
129 "datablkend", "cmdactive", "txactive",
130 "rxactive", "txhalfempty", "rxhalffull",
131 "txfifofull", "rxfifofull", "txfifoempty",
132 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
133 "sdiointr", "progdone", "atacmdcompl",
134 "sdiointrope", "ccstimeout", NULL, NULL,
135 NULL, NULL, NULL };
136
137static void
138msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800139{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
143 for (i = 0; i < 32; i++) {
144 if (status & (1 << i))
145 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800148}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149#endif
San Mehat865c8062009-11-13 13:42:06 -0800150
San Mehat9d2bd732009-09-22 16:44:22 -0700151static void
152msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
153 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530154static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530155static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530156static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800157static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800158static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700159static int msmsdcc_runtime_resume(struct device *dev);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530160
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530161static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
162{
163 unsigned short ret = NR_SG;
164
165 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530166 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530167 } else { /* DMA or PIO mode */
168 if (NR_SG > MAX_NR_SG_DMA_PIO)
169 ret = MAX_NR_SG_DMA_PIO;
170 }
171
172 return ret;
173}
174
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530175/* Prevent idle power collapse(pc) while operating in peripheral mode */
176static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
177{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700178 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530179 return;
180
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530181 if (vote)
182 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700183 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530184 else
185 pm_qos_update_request(&host->pm_qos_req_dma,
186 PM_QOS_DEFAULT_VALUE);
187}
188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
190static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
191 struct msmsdcc_sps_ep_conn_data *ep);
192static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep);
194#else
195static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep,
197 bool is_producer) { return 0; }
198static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
199 struct msmsdcc_sps_ep_conn_data *ep) { }
200static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
201 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530202{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 return 0;
204}
205static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep)
207{
208 return 0;
209}
210static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
211static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
212#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530215 * Apply soft reset to all SDCC BAM pipes
216 *
217 * This function applies soft reset to SDCC BAM pipe.
218 *
219 * This function should be called to recover from error
220 * conditions encountered during CMD/DATA tranfsers with card.
221 *
222 * @host - Pointer to driver's host structure
223 *
224 */
225static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
226{
227 int rc;
228
229 /* Reset all SDCC BAM pipes */
230 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
231 if (rc)
232 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
233 mmc_hostname(host->mmc), rc);
234 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
235 if (rc)
236 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
237 mmc_hostname(host->mmc), rc);
238
239 /* Restore all BAM pipes connections */
240 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
241 if (rc)
242 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
243 mmc_hostname(host->mmc), rc);
244 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
245 if (rc)
246 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
247 mmc_hostname(host->mmc), rc);
248}
249
250/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 * Apply soft reset
252 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530253 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 *
255 * This function should be called to recover from error
256 * conditions encountered with CMD/DATA tranfsers with card.
257 *
258 * Soft reset should only be used with SDCC controller v4.
259 *
260 * @host - Pointer to driver's host structure
261 *
262 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530263static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 /*
266 * Reset SDCC controller's DPSM (data path state machine
267 * and CPSM (command path state machine).
268 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530270 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530272 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530273}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530274
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530275static void msmsdcc_hard_reset(struct msmsdcc_host *host)
276{
277 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530278
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530279 /* Reset the controller */
280 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
281 if (ret)
282 pr_err("%s: Clock assert failed at %u Hz"
283 " with err %d\n", mmc_hostname(host->mmc),
284 host->clk_rate, ret);
285
286 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
287 if (ret)
288 pr_err("%s: Clock deassert failed at %u Hz"
289 " with err %d\n", mmc_hostname(host->mmc),
290 host->clk_rate, ret);
291
Subhash Jadavanidd432952012-03-28 11:25:56 +0530292 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530293 /* Give some delay for clock reset to propogate to controller */
294 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530295}
296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
298{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530299 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530300 if (host->is_sps_mode) {
301 /* Reset DML first */
302 msmsdcc_dml_reset(host);
303 /*
304 * delay the SPS pipe reset in thread context as
305 * sps_connect/sps_disconnect APIs can be called
306 * only from non-atomic context.
307 */
308 host->sps.pipe_reset_pending = true;
309 }
310 mb();
311 msmsdcc_soft_reset(host);
312
313 pr_debug("%s: Applied soft reset to Controller\n",
314 mmc_hostname(host->mmc));
315
316 if (host->is_sps_mode)
317 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 } else {
319 /* Give Clock reset (hard reset) to controller */
320 u32 mci_clk = 0;
321 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322
323 /* Save the controller state */
324 mci_clk = readl_relaxed(host->base + MMCICLOCK);
325 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530326 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530329 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 pr_debug("%s: Controller has been reinitialized\n",
331 mmc_hostname(host->mmc));
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 /* Restore the contoller state */
334 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530335 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530337 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530339 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530341
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700342 if (host->dummy_52_needed)
343 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344}
345
346static int
San Mehat9d2bd732009-09-22 16:44:22 -0700347msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
348{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 int retval = 0;
350
San Mehat9d2bd732009-09-22 16:44:22 -0700351 BUG_ON(host->curr.data);
352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 del_timer(&host->req_tout_timer);
354
San Mehat9d2bd732009-09-22 16:44:22 -0700355 if (mrq->data)
356 mrq->data->bytes_xfered = host->curr.data_xfered;
357 if (mrq->cmd->error == -ETIMEDOUT)
358 mdelay(5);
359
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530360 /* Clear current request information as current request has ended */
361 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
362
San Mehat9d2bd732009-09-22 16:44:22 -0700363 /*
364 * Need to drop the host lock here; mmc_request_done may call
365 * back into the driver...
366 */
367 spin_unlock(&host->lock);
368 mmc_request_done(host->mmc, mrq);
369 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370
371 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700372}
373
374static void
375msmsdcc_stop_data(struct msmsdcc_host *host)
376{
San Mehat9d2bd732009-09-22 16:44:22 -0700377 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530378 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530379 host->curr.wait_for_auto_prog_done = false;
380 host->curr.got_auto_prog_done = false;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700381 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
382 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530383 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700384}
385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700387{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 return host->core_memres->start + MMCIFIFO;
389}
390
391static inline unsigned int msmsdcc_get_min_sup_clk_rate(
392 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530393
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395{
396 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530397 if (!host->sdcc_version)
398 udelay(host->reg_write_delay);
399 else if (readl_relaxed(host->base + MCI_STATUS2) &
400 MCI_MCLK_REG_WR_ACTIVE) {
401 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530402
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530403 start = ktime_get();
404 while (readl_relaxed(host->base + MCI_STATUS2) &
405 MCI_MCLK_REG_WR_ACTIVE) {
406 diff = ktime_sub(ktime_get(), start);
407 /* poll for max. 1 ms */
408 if (ktime_to_us(diff) > 1000) {
409 pr_warning("%s: previous reg. write is"
410 " still active\n",
411 mmc_hostname(host->mmc));
412 break;
413 }
414 }
415 }
San Mehat9d2bd732009-09-22 16:44:22 -0700416}
417
Subhash Jadavanidd432952012-03-28 11:25:56 +0530418static inline void msmsdcc_delay(struct msmsdcc_host *host)
419{
420 udelay(host->reg_write_delay);
421
422}
423
San Mehat56a8b5b2009-11-21 12:29:46 -0800424static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
426{
427 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530429 /*
430 * As after sending the command, we don't write any of the
431 * controller registers and just wait for the
432 * CMD_RESPOND_END/CMD_SENT/Command failure notication
433 * from Controller.
434 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800436}
437
438static void
439msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
440{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
444 writel_relaxed((unsigned int)host->curr.xfer_size,
445 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530447 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800448
San Mehat6ac9ea62009-12-02 17:24:58 -0800449 if (host->cmd_cmd) {
450 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800452 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800453}
454
San Mehat9d2bd732009-09-22 16:44:22 -0700455static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530456msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700457{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700459 unsigned long flags;
460 struct mmc_request *mrq;
461
462 spin_lock_irqsave(&host->lock, flags);
463 mrq = host->curr.mrq;
464 BUG_ON(!mrq);
465
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530466 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700467 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700468 goto out;
469 }
470
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530471 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700472 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700474 } else {
475 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530476 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700477 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530478 mmc_hostname(host->mmc), host->dma.result);
479 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700480 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530481 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530482 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 host->dma.err.flush[0], host->dma.err.flush[1],
484 host->dma.err.flush[2], host->dma.err.flush[3],
485 host->dma.err.flush[4],
486 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530487 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700488 if (!mrq->data->error)
489 mrq->data->error = -EIO;
490 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530491 if (!mrq->data->host_cookie)
492 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
493 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 if (host->curr.user_pages) {
496 struct scatterlist *sg = host->dma.sg;
497 int i;
498
499 for (i = 0; i < host->dma.num_ents; i++, sg++)
500 flush_dcache_page(sg_page(sg));
501 }
502
San Mehat9d2bd732009-09-22 16:44:22 -0700503 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800504 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700505
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530506 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
507 (host->curr.wait_for_auto_prog_done &&
508 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700509 /*
510 * If we've already gotten our DATAEND / DATABLKEND
511 * for this request, then complete it through here.
512 */
San Mehat9d2bd732009-09-22 16:44:22 -0700513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700515 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516 host->curr.xfer_remain -= host->curr.xfer_size;
517 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700518 if (host->dummy_52_needed) {
519 mrq->data->bytes_xfered = host->curr.data_xfered;
520 host->dummy_52_sent = 1;
521 msmsdcc_start_command(host, &dummy52cmd,
522 MCI_CPSM_PROGENA);
523 goto out;
524 }
525 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530526 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530527 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700528 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530530 /*
531 * Clear current request information as current
532 * request has ended
533 */
534 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700535 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536
San Mehat9d2bd732009-09-22 16:44:22 -0700537 mmc_request_done(host->mmc, mrq);
538 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530539 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
540 || !mrq->sbc)) {
541 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530542 }
San Mehat9d2bd732009-09-22 16:44:22 -0700543 }
544
545out:
546 spin_unlock_irqrestore(&host->lock, flags);
547 return;
548}
549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
551/**
552 * Callback notification from SPS driver
553 *
554 * This callback function gets triggered called from
555 * SPS driver when requested SPS data transfer is
556 * completed.
557 *
558 * SPS driver invokes this callback in BAM irq context so
559 * SDCC driver schedule a tasklet for further processing
560 * this callback notification at later point of time in
561 * tasklet context and immediately returns control back
562 * to SPS driver.
563 *
564 * @nofity - Pointer to sps event notify sturcture
565 *
566 */
567static void
568msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
569{
570 struct msmsdcc_host *host =
571 (struct msmsdcc_host *)
572 ((struct sps_event_notify *)notify)->user;
573
574 host->sps.notify = *notify;
575 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
576 mmc_hostname(host->mmc), __func__, notify->event_id,
577 notify->data.transfer.iovec.addr,
578 notify->data.transfer.iovec.size,
579 notify->data.transfer.iovec.flags);
580 /* Schedule a tasklet for completing data transfer */
581 tasklet_schedule(&host->sps.tlet);
582}
583
584/**
585 * Tasklet handler for processing SPS callback event
586 *
587 * This function processing SPS event notification and
588 * checks if the SPS transfer is completed or not and
589 * then accordingly notifies status to MMC core layer.
590 *
591 * This function is called in tasklet context.
592 *
593 * @data - Pointer to sdcc driver data
594 *
595 */
596static void msmsdcc_sps_complete_tlet(unsigned long data)
597{
598 unsigned long flags;
599 int i, rc;
600 u32 data_xfered = 0;
601 struct mmc_request *mrq;
602 struct sps_iovec iovec;
603 struct sps_pipe *sps_pipe_handle;
604 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
605 struct sps_event_notify *notify = &host->sps.notify;
606
607 spin_lock_irqsave(&host->lock, flags);
608 if (host->sps.dir == DMA_FROM_DEVICE)
609 sps_pipe_handle = host->sps.prod.pipe_handle;
610 else
611 sps_pipe_handle = host->sps.cons.pipe_handle;
612 mrq = host->curr.mrq;
613
614 if (!mrq) {
615 spin_unlock_irqrestore(&host->lock, flags);
616 return;
617 }
618
619 pr_debug("%s: %s: sps event_id=%d\n",
620 mmc_hostname(host->mmc), __func__,
621 notify->event_id);
622
623 if (msmsdcc_is_dml_busy(host)) {
624 /* oops !!! this should never happen. */
625 pr_err("%s: %s: Received SPS EOT event"
626 " but DML HW is still busy !!!\n",
627 mmc_hostname(host->mmc), __func__);
628 }
629 /*
630 * Got End of transfer event!!! Check if all of the data
631 * has been transferred?
632 */
633 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
634 rc = sps_get_iovec(sps_pipe_handle, &iovec);
635 if (rc) {
636 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
637 mmc_hostname(host->mmc), __func__, rc, i);
638 break;
639 }
640 data_xfered += iovec.size;
641 }
642
643 if (data_xfered == host->curr.xfer_size) {
644 host->curr.data_xfered = host->curr.xfer_size;
645 host->curr.xfer_remain -= host->curr.xfer_size;
646 pr_debug("%s: Data xfer success. data_xfered=0x%x",
647 mmc_hostname(host->mmc),
648 host->curr.xfer_size);
649 } else {
650 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
651 " xfer_size=%d", mmc_hostname(host->mmc),
652 data_xfered, host->curr.xfer_size);
653 msmsdcc_reset_and_restore(host);
654 if (!mrq->data->error)
655 mrq->data->error = -EIO;
656 }
657
658 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530659 if (!mrq->data->host_cookie)
660 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
661 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662 host->sps.sg = NULL;
663 host->sps.busy = 0;
664
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530665 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
666 (host->curr.wait_for_auto_prog_done &&
667 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668 /*
669 * If we've already gotten our DATAEND / DATABLKEND
670 * for this request, then complete it through here.
671 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672
673 if (!mrq->data->error) {
674 host->curr.data_xfered = host->curr.xfer_size;
675 host->curr.xfer_remain -= host->curr.xfer_size;
676 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700677 if (host->dummy_52_needed) {
678 mrq->data->bytes_xfered = host->curr.data_xfered;
679 host->dummy_52_sent = 1;
680 msmsdcc_start_command(host, &dummy52cmd,
681 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700682 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700683 return;
684 }
685 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530686 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530687 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 mrq->data->bytes_xfered = host->curr.data_xfered;
689 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530690 /*
691 * Clear current request information as current
692 * request has ended
693 */
694 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 spin_unlock_irqrestore(&host->lock, flags);
696
697 mmc_request_done(host->mmc, mrq);
698 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530699 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
700 || !mrq->sbc)) {
701 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 }
703 }
704 spin_unlock_irqrestore(&host->lock, flags);
705}
706
707/**
708 * Exit from current SPS data transfer
709 *
710 * This function exits from current SPS data transfer.
711 *
712 * This function should be called when error condition
713 * is encountered during data transfer.
714 *
715 * @host - Pointer to sdcc host structure
716 *
717 */
718static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
719{
720 struct mmc_request *mrq;
721
722 mrq = host->curr.mrq;
723 BUG_ON(!mrq);
724
725 msmsdcc_reset_and_restore(host);
726 if (!mrq->data->error)
727 mrq->data->error = -EIO;
728
729 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530730 if (!mrq->data->host_cookie)
731 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
732 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733
734 host->sps.sg = NULL;
735 host->sps.busy = 0;
736 if (host->curr.data)
737 msmsdcc_stop_data(host);
738
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530739 if (!mrq->data->stop || mrq->cmd->error ||
740 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530742 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
743 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 msmsdcc_start_command(host, mrq->data->stop, 0);
745
746}
747#else
748static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
749static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
750static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
751#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
752
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530753static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530755static void
756msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
757 unsigned int result,
758 struct msm_dmov_errdata *err)
759{
760 struct msmsdcc_dma_data *dma_data =
761 container_of(cmd, struct msmsdcc_dma_data, hdr);
762 struct msmsdcc_host *host = dma_data->host;
763
764 dma_data->result = result;
765 if (err)
766 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
767
768 tasklet_schedule(&host->dma_tlet);
769}
770
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530771static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
772 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700773{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530774 bool ret = true;
775 u32 xfer_size = data->blksz * data->blocks;
776
777 if (host->is_sps_mode) {
778 /*
779 * BAM Mode: Fall back on PIO if size is less
780 * than or equal to SPS_MIN_XFER_SIZE bytes.
781 */
782 if (xfer_size <= SPS_MIN_XFER_SIZE)
783 ret = false;
784 } else if (host->is_dma_mode) {
785 /*
786 * ADM Mode: Fall back on PIO if size is less than FIFO size
787 * or not integer multiple of FIFO size
788 */
789 if (xfer_size % MCI_FIFOSIZE)
790 ret = false;
791 } else {
792 /* PIO Mode */
793 ret = false;
794 }
795
796 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700797}
798
799static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
800{
801 struct msmsdcc_nc_dmadata *nc;
802 dmov_box *box;
803 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700804 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530805 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700806 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530807 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700808
Krishna Konda25786ec2011-07-25 16:21:36 -0700809 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700811
Krishna Konda25786ec2011-07-25 16:21:36 -0700812 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
813
San Mehat9d2bd732009-09-22 16:44:22 -0700814 host->dma.sg = data->sg;
815 host->dma.num_ents = data->sg_len;
816
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530817 /* Prevent memory corruption */
818 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800819
San Mehat9d2bd732009-09-22 16:44:22 -0700820 nc = host->dma.nc;
821
San Mehat9d2bd732009-09-22 16:44:22 -0700822 if (data->flags & MMC_DATA_READ)
823 host->dma.dir = DMA_FROM_DEVICE;
824 else
825 host->dma.dir = DMA_TO_DEVICE;
826
Asutosh Dasaccacd42012-03-08 14:33:17 +0530827 if (!data->host_cookie) {
828 n = msmsdcc_prep_xfer(host, data);
829 if (unlikely(n < 0)) {
830 host->dma.sg = NULL;
831 host->dma.num_ents = 0;
832 return -ENOMEM;
833 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800834 }
San Mehat9d2bd732009-09-22 16:44:22 -0700835
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530836 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
837 host->curr.user_pages = 0;
838 box = &nc->cmd[0];
839 for (i = 0; i < host->dma.num_ents; i++) {
840 len = sg_dma_len(sg);
841 offset = 0;
842
843 do {
844 /* Check if we can do DMA */
845 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
846 err = -ENOTSUPP;
847 goto unmap;
848 }
849
850 box->cmd = CMD_MODE_BOX;
851
852 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
853 len = MMC_MAX_DMA_BOX_LENGTH;
854 len -= len % data->blksz;
855 }
856 rows = (len % MCI_FIFOSIZE) ?
857 (len / MCI_FIFOSIZE) + 1 :
858 (len / MCI_FIFOSIZE);
859
860 if (data->flags & MMC_DATA_READ) {
861 box->src_row_addr = msmsdcc_fifo_addr(host);
862 box->dst_row_addr = sg_dma_address(sg) + offset;
863 box->src_dst_len = (MCI_FIFOSIZE << 16) |
864 (MCI_FIFOSIZE);
865 box->row_offset = MCI_FIFOSIZE;
866 box->num_rows = rows * ((1 << 16) + 1);
867 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
868 } else {
869 box->src_row_addr = sg_dma_address(sg) + offset;
870 box->dst_row_addr = msmsdcc_fifo_addr(host);
871 box->src_dst_len = (MCI_FIFOSIZE << 16) |
872 (MCI_FIFOSIZE);
873 box->row_offset = (MCI_FIFOSIZE << 16);
874 box->num_rows = rows * ((1 << 16) + 1);
875 box->cmd |= CMD_DST_CRCI(host->dma.crci);
876 }
877
878 offset += len;
879 len = sg_dma_len(sg) - offset;
880 box++;
881 box_cmd_cnt++;
882 } while (len);
883 sg++;
884 }
885 /* Mark last command */
886 box--;
887 box->cmd |= CMD_LC;
888
889 /* location of command block must be 64 bit aligned */
890 BUG_ON(host->dma.cmd_busaddr & 0x07);
891
892 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
893 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
894 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
895 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
896
897 /* Flush all data to memory before starting dma */
898 mb();
899
900unmap:
901 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530902 if (!data->host_cookie)
903 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
904 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530905 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
906 mmc_hostname(host->mmc), err);
907 }
908
909 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700910}
911
Asutosh Dasaccacd42012-03-08 14:33:17 +0530912static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
913 struct mmc_data *data)
914{
915 int rc = 0;
916 unsigned int dir;
917
918 /* Prevent memory corruption */
919 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
920
921 if (data->flags & MMC_DATA_READ)
922 dir = DMA_FROM_DEVICE;
923 else
924 dir = DMA_TO_DEVICE;
925
926 /* Make sg buffers DMA ready */
927 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
928 dir);
929
930 if (unlikely(rc != data->sg_len)) {
931 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
932 mmc_hostname(host->mmc), rc);
933 rc = -ENOMEM;
934 goto dma_map_err;
935 }
936
937 pr_debug("%s: %s: %s: sg_len=%d\n",
938 mmc_hostname(host->mmc), __func__,
939 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
940 data->sg_len);
941
942 goto out;
943
944dma_map_err:
945 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
946 data->flags);
947out:
948 return rc;
949}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
951/**
952 * Submits data transfer request to SPS driver
953 *
954 * This function make sg (scatter gather) data buffers
955 * DMA ready and then submits them to SPS driver for
956 * transfer.
957 *
958 * @host - Pointer to sdcc host structure
959 * @data - Pointer to mmc_data structure
960 *
961 * @return 0 if success else negative value
962 */
963static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +0530964 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800965{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 int rc = 0;
967 u32 flags;
968 int i;
969 u32 addr, len, data_cnt;
970 struct scatterlist *sg = data->sg;
971 struct sps_pipe *sps_pipe_handle;
972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 host->sps.sg = data->sg;
974 host->sps.num_ents = data->sg_len;
975 host->sps.xfer_req_cnt = 0;
976 if (data->flags & MMC_DATA_READ) {
977 host->sps.dir = DMA_FROM_DEVICE;
978 sps_pipe_handle = host->sps.prod.pipe_handle;
979 } else {
980 host->sps.dir = DMA_TO_DEVICE;
981 sps_pipe_handle = host->sps.cons.pipe_handle;
982 }
983
Asutosh Dasaccacd42012-03-08 14:33:17 +0530984 if (!data->host_cookie) {
985 rc = msmsdcc_prep_xfer(host, data);
986 if (unlikely(rc < 0)) {
987 host->dma.sg = NULL;
988 host->dma.num_ents = 0;
989 goto out;
990 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 }
992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 for (i = 0; i < data->sg_len; i++) {
994 /*
995 * Check if this is the last buffer to transfer?
996 * If yes then set the INT and EOT flags.
997 */
998 len = sg_dma_len(sg);
999 addr = sg_dma_address(sg);
1000 flags = 0;
1001 while (len > 0) {
1002 if (len > SPS_MAX_DESC_SIZE) {
1003 data_cnt = SPS_MAX_DESC_SIZE;
1004 } else {
1005 data_cnt = len;
1006 if (i == data->sg_len - 1)
1007 flags = SPS_IOVEC_FLAG_INT |
1008 SPS_IOVEC_FLAG_EOT;
1009 }
1010 rc = sps_transfer_one(sps_pipe_handle, addr,
1011 data_cnt, host, flags);
1012 if (rc) {
1013 pr_err("%s: sps_transfer_one() error! rc=%d,"
1014 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1015 mmc_hostname(host->mmc), rc,
1016 (u32)sps_pipe_handle, (u32)sg, i);
1017 goto dma_map_err;
1018 }
1019 addr += data_cnt;
1020 len -= data_cnt;
1021 host->sps.xfer_req_cnt++;
1022 }
1023 sg++;
1024 }
1025 goto out;
1026
1027dma_map_err:
1028 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301029 if (!data->host_cookie)
1030 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1031 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032out:
1033 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001034}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035#else
1036static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1037 struct mmc_data *data) { return 0; }
1038#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001039
1040static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001041msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1042 struct mmc_command *cmd, u32 *c)
1043{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301044 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 cmd->opcode, cmd->arg, cmd->flags);
1046
San Mehat56a8b5b2009-11-21 12:29:46 -08001047 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1048
1049 if (cmd->flags & MMC_RSP_PRESENT) {
1050 if (cmd->flags & MMC_RSP_136)
1051 *c |= MCI_CPSM_LONGRSP;
1052 *c |= MCI_CPSM_RESPONSE;
1053 }
1054
1055 if (/*interrupt*/0)
1056 *c |= MCI_CPSM_INTERRUPT;
1057
Asutosh Das05049132012-05-09 12:38:15 +05301058 /* DAT_CMD bit should be set for all ADTC */
1059 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001060 *c |= MCI_CSPM_DATCMD;
1061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301063 if (host->tuning_needed &&
1064 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1065
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301066 /*
1067 * For open ended block read operation (without CMD23),
1068 * AUTO_CMD19 bit should be set while sending the READ command.
1069 * For close ended block read operation (with CMD23),
1070 * AUTO_CMD19 bit should be set while sending CMD23.
1071 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301072 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1073 host->curr.mrq->cmd->opcode ==
1074 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301075 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301076 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1077 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301078 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1079 *c |= MCI_CSPM_AUTO_CMD19;
1080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 }
1082
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301083 /* Clear CDR_EN bit for write operations */
1084 if (host->tuning_needed && cmd->mrq->data &&
1085 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1086 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1087 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1088
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301089 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301090 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301092 }
1093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 if (cmd == cmd->mrq->stop)
1095 *c |= MCI_CSPM_MCIABORT;
1096
San Mehat56a8b5b2009-11-21 12:29:46 -08001097 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 pr_err("%s: Overlapping command requests\n",
1099 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001100 }
1101 host->curr.cmd = cmd;
1102}
1103
1104static void
1105msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1106 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001107{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301108 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001109 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001111 unsigned int pio_irqmask = 0;
1112
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301113 BUG_ON(!data->sg);
1114 BUG_ON(!data->sg_len);
1115
San Mehat9d2bd732009-09-22 16:44:22 -07001116 host->curr.data = data;
1117 host->curr.xfer_size = data->blksz * data->blocks;
1118 host->curr.xfer_remain = host->curr.xfer_size;
1119 host->curr.data_xfered = 0;
1120 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301121 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001122
San Mehat9d2bd732009-09-22 16:44:22 -07001123 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1124
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301125 if (host->curr.wait_for_auto_prog_done)
1126 datactrl |= MCI_AUTO_PROG_DONE;
1127
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301128 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1130 datactrl |= MCI_DPSM_DMAENABLE;
1131 } else if (host->is_sps_mode) {
1132 if (!msmsdcc_is_dml_busy(host)) {
1133 if (!msmsdcc_sps_start_xfer(host, data)) {
1134 /* Now kick start DML transfer */
1135 mb();
1136 msmsdcc_dml_start_xfer(host, data);
1137 datactrl |= MCI_DPSM_DMAENABLE;
1138 host->sps.busy = 1;
1139 }
1140 } else {
1141 /*
1142 * Can't proceed with new transfer as
1143 * previous trasnfer is already in progress.
1144 * There is no point of going into PIO mode
1145 * as well. Is this a time to do kernel panic?
1146 */
1147 pr_err("%s: %s: DML HW is busy!!!"
1148 " Can't perform new SPS transfers"
1149 " now\n", mmc_hostname(host->mmc),
1150 __func__);
1151 }
1152 }
1153 }
1154
1155 /* Is data transfer in PIO mode required? */
1156 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001157 if (data->flags & MMC_DATA_READ) {
1158 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1159 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1160 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001161 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1163 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001164
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001165 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001166 }
1167
1168 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301169 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301170 else if (host->curr.use_wr_data_pend)
1171 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001172
San Mehat56a8b5b2009-11-21 12:29:46 -08001173 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001175 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1178 /* Use ADM (Application Data Mover) HW for Data transfer */
1179 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001180 host->cmd_timeout = timeout;
1181 host->cmd_pio_irqmask = pio_irqmask;
1182 host->cmd_datactrl = datactrl;
1183 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1186 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001187 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001188
1189 if (cmd) {
1190 msmsdcc_start_command_deferred(host, cmd, &c);
1191 host->cmd_c = c;
1192 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1194 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1195 host->base + MMCIMASK0);
1196 mb();
1197 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001198 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1205 (~(MCI_IRQ_PIO))) | pio_irqmask,
1206 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001208
1209 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301210 /* Delay between data/command */
1211 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001212 /* Daisy-chain the command if requested */
1213 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301214 } else {
1215 /*
1216 * We don't need delay after writing to DATA_CTRL
1217 * register if we are not writing to CMD register
1218 * immediately after this. As we already have delay
1219 * before sending the command, we just need mb() here.
1220 */
1221 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001222 }
San Mehat9d2bd732009-09-22 16:44:22 -07001223 }
1224}
1225
1226static void
1227msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1228{
San Mehat56a8b5b2009-11-21 12:29:46 -08001229 msmsdcc_start_command_deferred(host, cmd, &c);
1230 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001231}
1232
1233static void
1234msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1235 unsigned int status)
1236{
1237 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301239 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1240 || data->mrq->cmd->opcode ==
1241 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 pr_err("%s: Data CRC error\n",
1243 mmc_hostname(host->mmc));
1244 pr_err("%s: opcode 0x%.8x\n", __func__,
1245 data->mrq->cmd->opcode);
1246 pr_err("%s: blksz %d, blocks %d\n", __func__,
1247 data->blksz, data->blocks);
1248 data->error = -EILSEQ;
1249 }
San Mehat9d2bd732009-09-22 16:44:22 -07001250 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 /* CRC is optional for the bus test commands, not all
1252 * cards respond back with CRC. However controller
1253 * waits for the CRC and times out. Hence ignore the
1254 * data timeouts during the Bustest.
1255 */
1256 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1257 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301258 pr_err("%s: CMD%d: Data timeout\n",
1259 mmc_hostname(host->mmc),
1260 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301262 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 }
San Mehat9d2bd732009-09-22 16:44:22 -07001264 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001265 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001266 data->error = -EIO;
1267 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001268 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001269 data->error = -EIO;
1270 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001271 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001273 data->error = -EIO;
1274 }
San Mehat9d2bd732009-09-22 16:44:22 -07001275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001277 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 host->dummy_52_needed = 0;
1279}
San Mehat9d2bd732009-09-22 16:44:22 -07001280
1281static int
1282msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1283{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001285 uint32_t *ptr = (uint32_t *) buffer;
1286 int count = 0;
1287
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301288 if (remain % 4)
1289 remain = ((remain >> 2) + 1) << 2;
1290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1292
1293 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001294 ptr++;
1295 count += sizeof(uint32_t);
1296
1297 remain -= sizeof(uint32_t);
1298 if (remain == 0)
1299 break;
1300 }
1301 return count;
1302}
1303
1304static int
1305msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001307{
1308 void __iomem *base = host->base;
1309 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 while (readl_relaxed(base + MMCISTATUS) &
1313 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1314 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001315
San Mehat9d2bd732009-09-22 16:44:22 -07001316 count = min(remain, maxcnt);
1317
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301318 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1319 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001320 ptr += count;
1321 remain -= count;
1322
1323 if (remain == 0)
1324 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 }
1326 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001327
1328 return ptr - buffer;
1329}
1330
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001331/*
1332 * Copy up to a word (4 bytes) between a scatterlist
1333 * and a temporary bounce buffer when the word lies across
1334 * two pages. The temporary buffer can then be read to/
1335 * written from the FIFO once.
1336 */
1337static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1338{
1339 struct msmsdcc_pio_data *pio = &host->pio;
1340 unsigned int bytes_avail;
1341
1342 if (host->curr.data->flags & MMC_DATA_READ)
1343 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1344 pio->bounce_buf_len);
1345 else
1346 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1347 pio->bounce_buf_len);
1348
1349 while (pio->bounce_buf_len != 4) {
1350 if (!sg_miter_next(&pio->sg_miter))
1351 break;
1352 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1353 4 - pio->bounce_buf_len);
1354 if (host->curr.data->flags & MMC_DATA_READ)
1355 memcpy(pio->sg_miter.addr,
1356 &pio->bounce_buf[pio->bounce_buf_len],
1357 bytes_avail);
1358 else
1359 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1360 pio->sg_miter.addr, bytes_avail);
1361
1362 pio->sg_miter.consumed = bytes_avail;
1363 pio->bounce_buf_len += bytes_avail;
1364 }
1365}
1366
1367/*
1368 * Use sg_miter_next to return as many 4-byte aligned
1369 * chunks as possible, using a temporary 4 byte buffer
1370 * for alignment if necessary
1371 */
1372static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1373{
1374 struct msmsdcc_pio_data *pio = &host->pio;
1375 unsigned int length, rlength;
1376 char *buffer;
1377
1378 if (!sg_miter_next(&pio->sg_miter))
1379 return 0;
1380
1381 buffer = pio->sg_miter.addr;
1382 length = pio->sg_miter.length;
1383
1384 if (length < host->curr.xfer_remain) {
1385 rlength = round_down(length, 4);
1386 if (rlength) {
1387 /*
1388 * We have a 4-byte aligned chunk.
1389 * The rounding will be reflected by
1390 * a call to msmsdcc_sg_consumed
1391 */
1392 length = rlength;
1393 goto sg_next_end;
1394 }
1395 /*
1396 * We have a length less than 4 bytes. Check to
1397 * see if more buffer is available, and combine
1398 * to make 4 bytes if possible.
1399 */
1400 pio->bounce_buf_len = length;
1401 memset(pio->bounce_buf, 0, 4);
1402
1403 /*
1404 * On a read, get 4 bytes from FIFO, and distribute
1405 * (4-bouce_buf_len) bytes into consecutive
1406 * sgl buffers when msmsdcc_sg_consumed is called
1407 */
1408 if (host->curr.data->flags & MMC_DATA_READ) {
1409 buffer = pio->bounce_buf;
1410 length = 4;
1411 goto sg_next_end;
1412 } else {
1413 _msmsdcc_sg_consume_word(host);
1414 buffer = pio->bounce_buf;
1415 length = pio->bounce_buf_len;
1416 }
1417 }
1418
1419sg_next_end:
1420 *buf = buffer;
1421 *len = length;
1422 return 1;
1423}
1424
1425/*
1426 * Update sg_miter.consumed based on how many bytes were
1427 * consumed. If the bounce buffer was used to read from FIFO,
1428 * redistribute into sgls.
1429 */
1430static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1431 unsigned int length)
1432{
1433 struct msmsdcc_pio_data *pio = &host->pio;
1434
1435 if (host->curr.data->flags & MMC_DATA_READ) {
1436 if (length > pio->sg_miter.consumed)
1437 /*
1438 * consumed 4 bytes, but sgl
1439 * describes < 4 bytes
1440 */
1441 _msmsdcc_sg_consume_word(host);
1442 else
1443 pio->sg_miter.consumed = length;
1444 } else
1445 if (length < pio->sg_miter.consumed)
1446 pio->sg_miter.consumed = length;
1447}
1448
1449static void msmsdcc_sg_start(struct msmsdcc_host *host)
1450{
1451 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1452
1453 host->pio.bounce_buf_len = 0;
1454
1455 if (host->curr.data->flags & MMC_DATA_READ)
1456 sg_miter_flags |= SG_MITER_TO_SG;
1457 else
1458 sg_miter_flags |= SG_MITER_FROM_SG;
1459
1460 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1461 host->curr.data->sg_len, sg_miter_flags);
1462}
1463
1464static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1465{
1466 sg_miter_stop(&host->pio.sg_miter);
1467}
1468
San Mehat1cd22962010-02-03 12:59:29 -08001469static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001470msmsdcc_pio_irq(int irq, void *dev_id)
1471{
1472 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001474 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001475 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001476 unsigned int remain;
1477 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001478
Murali Palnati36448a42011-09-02 15:06:18 +05301479 spin_lock(&host->lock);
1480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301484 (MCI_IRQ_PIO)) == 0) {
1485 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488#if IRQ_DEBUG
1489 msmsdcc_print_status(host, "irq1-r", status);
1490#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001491 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001493 do {
1494 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1497 | MCI_RXDATAAVLBL)))
1498 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001499
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001500 if (!msmsdcc_sg_next(host, &buffer, &remain))
1501 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502
San Mehat9d2bd732009-09-22 16:44:22 -07001503 len = 0;
1504 if (status & MCI_RXACTIVE)
1505 len = msmsdcc_pio_read(host, buffer, remain);
1506 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001508
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301509 /* len might have aligned to 32bits above */
1510 if (len > remain)
1511 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001512
San Mehat9d2bd732009-09-22 16:44:22 -07001513 host->curr.xfer_remain -= len;
1514 host->curr.data_xfered += len;
1515 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001516 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 if (remain) /* Done with this page? */
1519 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001522 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001523
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001524 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001525 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1528 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1529 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1530 host->base + MMCIMASK0);
1531 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301532 /*
1533 * back to back write to MASK0 register don't need
1534 * synchronization delay.
1535 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1537 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1538 }
1539 mb();
1540 } else if (!host->curr.xfer_remain) {
1541 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1542 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1543 mb();
1544 }
San Mehat9d2bd732009-09-22 16:44:22 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001547
1548 return IRQ_HANDLED;
1549}
1550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551static void
1552msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1553
1554static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1555 struct mmc_data *data)
1556{
1557 u32 loop_cnt = 0;
1558
1559 /*
1560 * For read commands with data less than fifo size, it is possible to
1561 * get DATAEND first and RXDATA_AVAIL might be set later because of
1562 * synchronization delay through the asynchronous RX FIFO. Thus, for
1563 * such cases, even after DATAEND interrupt is received software
1564 * should poll for RXDATA_AVAIL until the requested data is read out
1565 * of FIFO. This change is needed to get around this abnormal but
1566 * sometimes expected behavior of SDCC3 controller.
1567 *
1568 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1569 * after the data is loaded into RX FIFO. This would amount to less
1570 * than a microsecond and thus looping for 1000 times is good enough
1571 * for that delay.
1572 */
1573 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1574 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1575 spin_unlock(&host->lock);
1576 msmsdcc_pio_irq(1, host);
1577 spin_lock(&host->lock);
1578 }
1579 }
1580 if (loop_cnt == 1000) {
1581 pr_info("%s: Timed out while polling for Rx Data\n",
1582 mmc_hostname(host->mmc));
1583 data->error = -ETIMEDOUT;
1584 msmsdcc_reset_and_restore(host);
1585 }
1586}
1587
San Mehat9d2bd732009-09-22 16:44:22 -07001588static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1589{
1590 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001591
1592 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301593 if (mmc_resp_type(cmd))
1594 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1595 /*
1596 * Read rest of the response registers only if
1597 * long response is expected for this command
1598 */
1599 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1600 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1601 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1602 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1603 }
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301606 pr_debug("%s: CMD%d: Command timeout\n",
1607 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001608 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301610 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301611 pr_err("%s: CMD%d: Command CRC error\n",
1612 mmc_hostname(host->mmc), cmd->opcode);
1613 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001614 cmd->error = -EILSEQ;
1615 }
1616
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301617 if (!cmd->error) {
1618 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1619 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1620 mod_timer(&host->req_tout_timer, (jiffies +
1621 msecs_to_jiffies(host->curr.req_tout_ms)));
1622 }
1623 }
1624
San Mehat9d2bd732009-09-22 16:44:22 -07001625 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 if (host->curr.data && host->dma.sg &&
1627 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001628 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 else if (host->curr.data && host->sps.sg &&
1630 host->is_sps_mode){
1631 /* Stop current SPS transfer */
1632 msmsdcc_sps_exit_curr_xfer(host);
1633 }
San Mehat9d2bd732009-09-22 16:44:22 -07001634 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301635 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001636 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301637 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301638 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301639 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301640 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301642 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301644 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301645 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301646 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301647 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001648 if (host->dummy_52_needed)
1649 host->dummy_52_needed = 0;
1650 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301652 msmsdcc_request_end(host, cmd->mrq);
1653 }
1654 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301655 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301656 if (cmd == host->curr.mrq->sbc)
1657 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1658 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1659 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301660 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001661 }
1662}
1663
San Mehat9d2bd732009-09-22 16:44:22 -07001664static irqreturn_t
1665msmsdcc_irq(int irq, void *dev_id)
1666{
1667 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001668 u32 status;
1669 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001671
1672 spin_lock(&host->lock);
1673
1674 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 struct mmc_command *cmd;
1676 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 if (timer) {
1679 timer = 0;
1680 msmsdcc_delay(host);
1681 }
San Mehat865c8062009-11-13 13:42:06 -08001682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 if (!host->clks_on) {
1684 pr_debug("%s: %s: SDIO async irq received\n",
1685 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301686
1687 /*
1688 * Only async interrupt can come when clocks are off,
1689 * disable further interrupts and enable them when
1690 * clocks are on.
1691 */
1692 if (!host->sdcc_irq_disabled) {
1693 disable_irq_nosync(irq);
1694 host->sdcc_irq_disabled = 1;
1695 }
1696
1697 /*
1698 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1699 * will take care of signaling sdio irq during
1700 * mmc_sdio_resume().
1701 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301702 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301703 /*
1704 * This is a wakeup interrupt so hold wakelock
1705 * until SDCC resume is handled.
1706 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301708 } else {
1709 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301710 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301711 spin_lock(&host->lock);
1712 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301713 ret = 1;
1714 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715 }
1716
1717 status = readl_relaxed(host->base + MMCISTATUS);
1718
1719 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1720 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001721 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723#if IRQ_DEBUG
1724 msmsdcc_print_status(host, "irq0-r", status);
1725#endif
1726 status &= readl_relaxed(host->base + MMCIMASK0);
1727 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301728 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301729 if (host->clk_rate <=
1730 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301731 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732#if IRQ_DEBUG
1733 msmsdcc_print_status(host, "irq0-p", status);
1734#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 if (status & MCI_SDIOINTROPE) {
1737 if (host->sdcc_suspending)
1738 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301739 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301741 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001742 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001743 data = host->curr.data;
1744
1745 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1747 MCI_CMDTIMEOUT)) {
1748 if (status & MCI_CMDTIMEOUT)
1749 pr_debug("%s: dummy CMD52 timeout\n",
1750 mmc_hostname(host->mmc));
1751 if (status & MCI_CMDCRCFAIL)
1752 pr_debug("%s: dummy CMD52 CRC failed\n",
1753 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001754 host->dummy_52_sent = 0;
1755 host->dummy_52_needed = 0;
1756 if (data) {
1757 msmsdcc_stop_data(host);
1758 msmsdcc_request_end(host, data->mrq);
1759 }
1760 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 spin_unlock(&host->lock);
1762 return IRQ_HANDLED;
1763 }
1764 break;
1765 }
1766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 /*
1768 * Check for proper command response
1769 */
1770 cmd = host->curr.cmd;
1771 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1772 MCI_CMDTIMEOUT | MCI_PROGDONE |
1773 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1774 msmsdcc_do_cmdirq(host, status);
1775 }
1776
Sathish Ambley081d7842011-11-29 11:19:41 -08001777 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 /* Check for data errors */
1779 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1780 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1781 msmsdcc_data_err(host, data, status);
1782 host->curr.data_xfered = 0;
1783 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001784 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 else if (host->sps.sg && host->is_sps_mode) {
1786 /* Stop current SPS transfer */
1787 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301788 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 msmsdcc_reset_and_restore(host);
1790 if (host->curr.data)
1791 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301792 if (!data->stop || (host->curr.mrq->sbc
1793 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 timer |=
1795 msmsdcc_request_end(host,
1796 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301797 else if ((host->curr.mrq->sbc
1798 && data->error) ||
1799 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 msmsdcc_start_command(host,
1801 data->stop,
1802 0);
1803 timer = 1;
1804 }
1805 }
1806 }
1807
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301808 /* Check for prog done */
1809 if (host->curr.wait_for_auto_prog_done &&
1810 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301811 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 /* Check for data done */
1814 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1815 host->curr.got_dataend = 1;
1816
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301817 if (host->curr.got_dataend &&
1818 (!host->curr.wait_for_auto_prog_done ||
1819 (host->curr.wait_for_auto_prog_done &&
1820 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 /*
1822 * If DMA is still in progress, we complete
1823 * via the completion handler
1824 */
1825 if (!host->dma.busy && !host->sps.busy) {
1826 /*
1827 * There appears to be an issue in the
1828 * controller where if you request a
1829 * small block transfer (< fifo size),
1830 * you may get your DATAEND/DATABLKEND
1831 * irq without the PIO data irq.
1832 *
1833 * Check to see if theres still data
1834 * to be read, and simulate a PIO irq.
1835 */
1836 if (data->flags & MMC_DATA_READ)
1837 msmsdcc_wait_for_rxdata(host,
1838 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 if (!data->error) {
1840 host->curr.data_xfered =
1841 host->curr.xfer_size;
1842 host->curr.xfer_remain -=
1843 host->curr.xfer_size;
1844 }
1845
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001846 if (!host->dummy_52_needed) {
1847 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301848 if (!data->stop ||
1849 (host->curr.mrq->sbc
1850 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001851 msmsdcc_request_end(
1852 host,
1853 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301854 else if ((host->curr.mrq->sbc
1855 && data->error) ||
1856 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001857 msmsdcc_start_command(
1858 host,
1859 data->stop, 0);
1860 timer = 1;
1861 }
1862 } else {
1863 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001865 &dummy52cmd,
1866 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 }
1868 }
1869 }
1870 }
1871
San Mehat9d2bd732009-09-22 16:44:22 -07001872 ret = 1;
1873 } while (status);
1874
1875 spin_unlock(&host->lock);
1876
San Mehat9d2bd732009-09-22 16:44:22 -07001877 return IRQ_RETVAL(ret);
1878}
1879
1880static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301881msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1882 bool is_first_request)
1883{
1884 struct msmsdcc_host *host = mmc_priv(mmc);
1885 struct mmc_data *data = mrq->data;
1886 int rc = 0;
1887
1888 if (unlikely(!data)) {
1889 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1890 __func__);
1891 return;
1892 }
1893 if (unlikely(data->host_cookie)) {
1894 /* Very wrong */
1895 data->host_cookie = 0;
1896 pr_err("%s: %s Request reposted for prepare\n",
1897 mmc_hostname(mmc), __func__);
1898 return;
1899 }
1900
1901 if (!msmsdcc_is_dma_possible(host, data))
1902 return;
1903
1904 rc = msmsdcc_prep_xfer(host, data);
1905 if (unlikely(rc < 0)) {
1906 data->host_cookie = 0;
1907 return;
1908 }
1909
1910 data->host_cookie = 1;
1911}
1912
1913static void
1914msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1915{
1916 struct msmsdcc_host *host = mmc_priv(mmc);
1917 unsigned int dir;
1918 struct mmc_data *data = mrq->data;
1919
1920 if (unlikely(!data)) {
1921 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1922 __func__);
1923 return;
1924 }
1925 if (data->flags & MMC_DATA_READ)
1926 dir = DMA_FROM_DEVICE;
1927 else
1928 dir = DMA_TO_DEVICE;
1929
1930 if (data->host_cookie)
1931 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1932 data->sg_len, dir);
1933
1934 data->host_cookie = 0;
1935}
1936
1937static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001938msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1939{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301940 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301942 if ((mrq->data->flags & MMC_DATA_READ) ||
1943 host->curr.use_wr_data_pend)
1944 msmsdcc_start_data(host, mrq->data,
1945 mrq->sbc ? mrq->sbc : mrq->cmd,
1946 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301947 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301948 msmsdcc_start_command(host,
1949 mrq->sbc ? mrq->sbc : mrq->cmd,
1950 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 } else {
1952 msmsdcc_start_command(host, mrq->cmd, 0);
1953 }
1954}
1955
1956static void
San Mehat9d2bd732009-09-22 16:44:22 -07001957msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1958{
1959 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301960 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 /*
1963 * Get the SDIO AL client out of LPM.
1964 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001965 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 if (host->plat->is_sdio_al_client)
1967 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001968
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301969 /* check if sps pipe reset is pending? */
1970 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1971 msmsdcc_sps_pipes_reset_and_restore(host);
1972 host->sps.pipe_reset_pending = false;
1973 }
1974
San Mehat9d2bd732009-09-22 16:44:22 -07001975 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001976
1977 if (host->eject) {
1978 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1979 mrq->cmd->error = 0;
1980 mrq->data->bytes_xfered = mrq->data->blksz *
1981 mrq->data->blocks;
1982 } else
1983 mrq->cmd->error = -ENOMEDIUM;
1984
1985 spin_unlock_irqrestore(&host->lock, flags);
1986 mmc_request_done(mmc, mrq);
1987 return;
1988 }
1989
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301990 /*
subhashjf181c292012-05-02 13:07:40 +05301991 * Don't start the request if SDCC is not in proper state to handle it
1992 */
1993 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1994 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1995 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1996 __func__, mrq->cmd->opcode);
1997 msmsdcc_dump_sdcc_state(host);
1998 mrq->cmd->error = -EIO;
1999 if (mrq->data) {
2000 mrq->data->error = -EIO;
2001 mrq->data->bytes_xfered = 0;
2002 }
2003 spin_unlock_irqrestore(&host->lock, flags);
2004 mmc_request_done(mmc, mrq);
2005 return;
2006 }
2007
2008 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2009 " other request (CMD%d) is in progress\n",
2010 mmc_hostname(host->mmc), __func__,
2011 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2012
2013 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302014 * Set timeout value to 10 secs (or more in case of buggy cards)
2015 */
2016 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302017 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302018 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302019 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302020 /*
2021 * Kick the software request timeout timer here with the timeout
2022 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302023 */
2024 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302025 (jiffies +
2026 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002027
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302028 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302029 if (mrq->sbc) {
2030 mrq->sbc->mrq = mrq;
2031 mrq->sbc->data = mrq->data;
2032 }
2033
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302034 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302035 if (host->sdcc_version) {
2036 if (!mrq->stop)
2037 host->curr.wait_for_auto_prog_done = true;
2038 } else {
2039 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2040 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 host->dummy_52_needed = 1;
2042 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302043
Subhash Jadavanif5277752011-10-12 16:47:52 +05302044 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2045 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2046 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002047 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302048
Subhash Jadavanif5277752011-10-12 16:47:52 +05302049 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302050
San Mehat9d2bd732009-09-22 16:44:22 -07002051 spin_unlock_irqrestore(&host->lock, flags);
2052}
2053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2055 int min_uV, int max_uV)
2056{
2057 int rc = 0;
2058
2059 if (vreg->set_voltage_sup) {
2060 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2061 if (rc) {
2062 pr_err("%s: regulator_set_voltage(%s) failed."
2063 " min_uV=%d, max_uV=%d, rc=%d\n",
2064 __func__, vreg->name, min_uV, max_uV, rc);
2065 }
2066 }
2067
2068 return rc;
2069}
2070
2071static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2072 int uA_load)
2073{
2074 int rc = 0;
2075
Krishna Kondafea60182011-11-01 16:01:34 -07002076 /* regulators that do not support regulator_set_voltage also
2077 do not support regulator_set_optimum_mode */
2078 if (vreg->set_voltage_sup) {
2079 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2080 if (rc < 0)
2081 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2082 "uA_load=%d) failed. rc=%d\n", __func__,
2083 vreg->name, uA_load, rc);
2084 else
2085 /* regulator_set_optimum_mode() can return non zero
2086 * value even for success case.
2087 */
2088 rc = 0;
2089 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090
2091 return rc;
2092}
2093
2094static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2095 struct device *dev)
2096{
2097 int rc = 0;
2098
2099 /* check if regulator is already initialized? */
2100 if (vreg->reg)
2101 goto out;
2102
2103 /* Get the regulator handle */
2104 vreg->reg = regulator_get(dev, vreg->name);
2105 if (IS_ERR(vreg->reg)) {
2106 rc = PTR_ERR(vreg->reg);
2107 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2108 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002109 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002110 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002111
2112 if (regulator_count_voltages(vreg->reg) > 0)
2113 vreg->set_voltage_sup = 1;
2114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115out:
2116 return rc;
2117}
2118
2119static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2120{
2121 if (vreg->reg)
2122 regulator_put(vreg->reg);
2123}
2124
2125/* This init function should be called only once for each SDCC slot */
2126static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2127{
2128 int rc = 0;
2129 struct msm_mmc_slot_reg_data *curr_slot;
2130 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2131 struct device *dev = mmc_dev(host->mmc);
2132
2133 curr_slot = host->plat->vreg_data;
2134 if (!curr_slot)
2135 goto out;
2136
2137 curr_vdd_reg = curr_slot->vdd_data;
2138 curr_vccq_reg = curr_slot->vccq_data;
2139 curr_vddp_reg = curr_slot->vddp_data;
2140
2141 if (is_init) {
2142 /*
2143 * Get the regulator handle from voltage regulator framework
2144 * and then try to set the voltage level for the regulator
2145 */
2146 if (curr_vdd_reg) {
2147 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2148 if (rc)
2149 goto out;
2150 }
2151 if (curr_vccq_reg) {
2152 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2153 if (rc)
2154 goto vdd_reg_deinit;
2155 }
2156 if (curr_vddp_reg) {
2157 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2158 if (rc)
2159 goto vccq_reg_deinit;
2160 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002161 rc = msmsdcc_vreg_reset(host);
2162 if (rc)
2163 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2164 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002165 goto out;
2166 } else {
2167 /* Deregister all regulators from regulator framework */
2168 goto vddp_reg_deinit;
2169 }
2170vddp_reg_deinit:
2171 if (curr_vddp_reg)
2172 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2173vccq_reg_deinit:
2174 if (curr_vccq_reg)
2175 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2176vdd_reg_deinit:
2177 if (curr_vdd_reg)
2178 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2179out:
2180 return rc;
2181}
2182
2183static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2184{
2185 int rc = 0;
2186
Subhash Jadavanicc922692011-08-01 23:05:01 +05302187 /* Put regulator in HPM (high power mode) */
2188 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2189 if (rc < 0)
2190 goto out;
2191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 if (!vreg->is_enabled) {
2193 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302194 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2195 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 if (rc)
2197 goto out;
2198
2199 rc = regulator_enable(vreg->reg);
2200 if (rc) {
2201 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2202 __func__, vreg->name, rc);
2203 goto out;
2204 }
2205 vreg->is_enabled = true;
2206 }
2207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208out:
2209 return rc;
2210}
2211
2212static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2213{
2214 int rc = 0;
2215
2216 /* Never disable regulator marked as always_on */
2217 if (vreg->is_enabled && !vreg->always_on) {
2218 rc = regulator_disable(vreg->reg);
2219 if (rc) {
2220 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2221 __func__, vreg->name, rc);
2222 goto out;
2223 }
2224 vreg->is_enabled = false;
2225
2226 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2227 if (rc < 0)
2228 goto out;
2229
2230 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302231 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 if (rc)
2233 goto out;
2234 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2235 /* Put always_on regulator in LPM (low power mode) */
2236 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2237 if (rc < 0)
2238 goto out;
2239 }
2240out:
2241 return rc;
2242}
2243
2244static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2245{
2246 int rc = 0, i;
2247 struct msm_mmc_slot_reg_data *curr_slot;
2248 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2249 struct msm_mmc_reg_data *vreg_table[3];
2250
2251 curr_slot = host->plat->vreg_data;
2252 if (!curr_slot)
2253 goto out;
2254
2255 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2256 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2257 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2258
2259 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2260 if (vreg_table[i]) {
2261 if (enable)
2262 rc = msmsdcc_vreg_enable(vreg_table[i]);
2263 else
2264 rc = msmsdcc_vreg_disable(vreg_table[i]);
2265 if (rc)
2266 goto out;
2267 }
2268 }
2269out:
2270 return rc;
2271}
2272
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002273/*
2274 * Reset vreg by ensuring it is off during probe. A call
2275 * to enable vreg is needed to balance disable vreg
2276 */
2277static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2278{
2279 int rc;
2280
2281 rc = msmsdcc_setup_vreg(host, 1);
2282 if (rc)
2283 return rc;
2284 rc = msmsdcc_setup_vreg(host, 0);
2285 return rc;
2286}
2287
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302288static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289{
2290 int rc = 0;
2291
2292 if (host->plat->vreg_data) {
2293 struct msm_mmc_reg_data *vddp_reg =
2294 host->plat->vreg_data->vddp_data;
2295
2296 if (vddp_reg && vddp_reg->is_enabled)
2297 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2298 }
2299
2300 return rc;
2301}
2302
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302303static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2304{
2305 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2306 int rc = 0;
2307
2308 if (curr_slot && curr_slot->vddp_data) {
2309 rc = msmsdcc_set_vddp_level(host,
2310 curr_slot->vddp_data->low_vol_level);
2311
2312 if (rc)
2313 pr_err("%s: %s: failed to change vddp level to %d",
2314 mmc_hostname(host->mmc), __func__,
2315 curr_slot->vddp_data->low_vol_level);
2316 }
2317
2318 return rc;
2319}
2320
2321static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2322{
2323 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2324 int rc = 0;
2325
2326 if (curr_slot && curr_slot->vddp_data) {
2327 rc = msmsdcc_set_vddp_level(host,
2328 curr_slot->vddp_data->high_vol_level);
2329
2330 if (rc)
2331 pr_err("%s: %s: failed to change vddp level to %d",
2332 mmc_hostname(host->mmc), __func__,
2333 curr_slot->vddp_data->high_vol_level);
2334 }
2335
2336 return rc;
2337}
2338
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302339static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2340{
2341 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2342 int rc = 0;
2343
2344 if (curr_slot && curr_slot->vccq_data) {
2345 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2346 level, level);
2347 if (rc)
2348 pr_err("%s: %s: failed to change vccq level to %d",
2349 mmc_hostname(host->mmc), __func__, level);
2350 }
2351
2352 return rc;
2353}
2354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2356{
2357 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2358 return 1;
2359 return 0;
2360}
2361
Asutosh Dasf5298c32012-04-03 14:51:47 +05302362/*
2363 * Any function calling msmsdcc_setup_clocks must
2364 * acquire clk_mutex. May sleep.
2365 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2367{
2368 if (enable) {
2369 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302370 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302372 clk_prepare_enable(host->pclk);
2373 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302374 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302375 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302377 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302378 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302379 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302381 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302383 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002384 }
2385}
2386
2387static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2388 unsigned int req_clk)
2389{
2390 unsigned int sel_clk = -1;
2391
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302392 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2393 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2394 goto out;
2395 }
2396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002397 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2398 unsigned char cnt;
2399
2400 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2401 if (host->plat->sup_clk_table[cnt] > req_clk)
2402 break;
2403 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2404 sel_clk = host->plat->sup_clk_table[cnt];
2405 break;
2406 } else
2407 sel_clk = host->plat->sup_clk_table[cnt];
2408 }
2409 } else {
2410 if ((req_clk < host->plat->msmsdcc_fmax) &&
2411 (req_clk > host->plat->msmsdcc_fmid))
2412 sel_clk = host->plat->msmsdcc_fmid;
2413 else
2414 sel_clk = req_clk;
2415 }
2416
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302417out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418 return sel_clk;
2419}
2420
2421static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2422 struct msmsdcc_host *host)
2423{
2424 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2425 return host->plat->sup_clk_table[0];
2426 else
2427 return host->plat->msmsdcc_fmin;
2428}
2429
2430static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2431 struct msmsdcc_host *host)
2432{
2433 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2434 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2435 else
2436 return host->plat->msmsdcc_fmax;
2437}
2438
2439static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302440{
2441 struct msm_mmc_gpio_data *curr;
2442 int i, rc = 0;
2443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302445 for (i = 0; i < curr->size; i++) {
2446 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 if (curr->gpio[i].is_always_on &&
2448 curr->gpio[i].is_enabled)
2449 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302450 rc = gpio_request(curr->gpio[i].no,
2451 curr->gpio[i].name);
2452 if (rc) {
2453 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2454 mmc_hostname(host->mmc),
2455 curr->gpio[i].no,
2456 curr->gpio[i].name, rc);
2457 goto free_gpios;
2458 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302460 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 if (curr->gpio[i].is_always_on)
2462 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302463 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302465 }
2466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302468
2469free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302471 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 curr->gpio[i].is_enabled = false;
2473 }
2474out:
2475 return rc;
2476}
2477
2478static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2479{
2480 struct msm_mmc_pad_data *curr;
2481 int i;
2482
2483 curr = host->plat->pin_data->pad_data;
2484 for (i = 0; i < curr->drv->size; i++) {
2485 if (enable)
2486 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2487 curr->drv->on[i].val);
2488 else
2489 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2490 curr->drv->off[i].val);
2491 }
2492
2493 for (i = 0; i < curr->pull->size; i++) {
2494 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002495 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 curr->pull->on[i].val);
2497 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002498 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499 curr->pull->off[i].val);
2500 }
2501
2502 return 0;
2503}
2504
2505static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2506{
2507 int rc = 0;
2508
2509 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2510 return 0;
2511
2512 if (host->plat->pin_data->is_gpio)
2513 rc = msmsdcc_setup_gpio(host, enable);
2514 else
2515 rc = msmsdcc_setup_pad(host, enable);
2516
2517 if (!rc)
2518 host->plat->pin_data->cfg_sts = enable;
2519
2520 return rc;
2521}
2522
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302523static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2524 unsigned mode)
2525{
2526 int ret = 0;
2527 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2528
2529 if (!pin)
2530 return 0;
2531
2532 switch (mode) {
2533 case SDC_DAT1_DISABLE:
2534 ret = msm_mpm_enable_pin(pin, 0);
2535 break;
2536 case SDC_DAT1_ENABLE:
2537 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2538 ret = msm_mpm_enable_pin(pin, 1);
2539 break;
2540 case SDC_DAT1_ENWAKE:
2541 ret = msm_mpm_set_pin_wake(pin, 1);
2542 break;
2543 case SDC_DAT1_DISWAKE:
2544 ret = msm_mpm_set_pin_wake(pin, 0);
2545 break;
2546 default:
2547 ret = -EINVAL;
2548 break;
2549 }
2550
2551 return ret;
2552}
2553
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302554static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2555{
2556 u32 pwr = 0;
2557 int ret = 0;
2558 struct mmc_host *mmc = host->mmc;
2559
2560 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2561 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2562 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2563 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2564
2565 if (ret) {
2566 pr_err("%s: Failed to setup voltage regulators\n",
2567 mmc_hostname(host->mmc));
2568 goto out;
2569 }
2570
2571 switch (ios->power_mode) {
2572 case MMC_POWER_OFF:
2573 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302574 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302575 /*
2576 * As VDD pad rail is always on, set low voltage for VDD
2577 * pad rail when slot is unused (when card is not present
2578 * or during system suspend).
2579 */
2580 msmsdcc_set_vddp_low_vol(host);
2581 msmsdcc_setup_pins(host, false);
2582 break;
2583 case MMC_POWER_UP:
2584 /* writing PWR_UP bit is redundant */
2585 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302586 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302587
2588 msmsdcc_set_vddp_high_vol(host);
2589 msmsdcc_setup_pins(host, true);
2590 break;
2591 case MMC_POWER_ON:
2592 pwr = MCI_PWR_ON;
2593 break;
2594 }
2595
2596out:
2597 return pwr;
2598}
2599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2601{
2602 unsigned int wakeup_irq;
2603
2604 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2605 host->plat->sdiowakeup_irq :
2606 host->core_irqres->start;
2607
2608 if (!host->irq_wake_enabled) {
2609 enable_irq_wake(wakeup_irq);
2610 host->irq_wake_enabled = true;
2611 }
2612}
2613
2614static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2615{
2616 unsigned int wakeup_irq;
2617
2618 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2619 host->plat->sdiowakeup_irq :
2620 host->core_irqres->start;
2621
2622 if (host->irq_wake_enabled) {
2623 disable_irq_wake(wakeup_irq);
2624 host->irq_wake_enabled = false;
2625 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302626}
2627
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302628/* Returns required bandwidth in Bytes per Sec */
2629static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2630 struct mmc_ios *ios)
2631{
2632 unsigned int bw;
2633
2634 bw = host->clk_rate;
2635 /*
2636 * For DDR mode, SDCC controller clock will be at
2637 * the double rate than the actual clock that goes to card.
2638 */
2639 if (ios->bus_width == MMC_BUS_WIDTH_4)
2640 bw /= 2;
2641 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2642 bw /= 8;
2643
2644 return bw;
2645}
2646
2647static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2648 unsigned int bw)
2649{
2650 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2651 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2652 int i;
2653
2654 if (host->msm_bus_vote.is_max_bw_needed && bw)
2655 return host->msm_bus_vote.max_bw_vote;
2656
2657 for (i = 0; i < size; i++) {
2658 if (bw <= table[i])
2659 break;
2660 }
2661
2662 if (i && (i == size))
2663 i--;
2664
2665 return i;
2666}
2667
2668static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2669{
2670 int rc = 0;
2671 struct msm_bus_scale_pdata *use_cases;
2672
2673 if (host->plat->msm_bus_voting_data &&
2674 host->plat->msm_bus_voting_data->use_cases &&
2675 host->plat->msm_bus_voting_data->bw_vecs &&
2676 host->plat->msm_bus_voting_data->bw_vecs_size) {
2677 use_cases = host->plat->msm_bus_voting_data->use_cases;
2678 host->msm_bus_vote.client_handle =
2679 msm_bus_scale_register_client(use_cases);
2680 } else {
2681 return 0;
2682 }
2683
2684 if (!host->msm_bus_vote.client_handle) {
2685 pr_err("%s: msm_bus_scale_register_client() failed\n",
2686 mmc_hostname(host->mmc));
2687 rc = -EFAULT;
2688 } else {
2689 /* cache the vote index for minimum and maximum bandwidth */
2690 host->msm_bus_vote.min_bw_vote =
2691 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2692 host->msm_bus_vote.max_bw_vote =
2693 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2694 }
2695
2696 return rc;
2697}
2698
2699static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2700{
2701 if (host->msm_bus_vote.client_handle)
2702 msm_bus_scale_unregister_client(
2703 host->msm_bus_vote.client_handle);
2704}
2705
2706/*
2707 * This function must be called with host lock acquired.
2708 * Caller of this function should also ensure that msm bus client
2709 * handle is not null.
2710 */
2711static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2712 int vote,
2713 unsigned long flags)
2714{
2715 int rc = 0;
2716
2717 if (vote != host->msm_bus_vote.curr_vote) {
2718 spin_unlock_irqrestore(&host->lock, flags);
2719 rc = msm_bus_scale_client_update_request(
2720 host->msm_bus_vote.client_handle, vote);
2721 if (rc)
2722 pr_err("%s: msm_bus_scale_client_update_request() failed."
2723 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2724 mmc_hostname(host->mmc),
2725 host->msm_bus_vote.client_handle, vote, rc);
2726 spin_lock_irqsave(&host->lock, flags);
2727 if (!rc)
2728 host->msm_bus_vote.curr_vote = vote;
2729 }
2730
2731 return rc;
2732}
2733
2734/*
2735 * Internal work. Work to set 0 bandwidth for msm bus.
2736 */
2737static void msmsdcc_msm_bus_work(struct work_struct *work)
2738{
2739 struct msmsdcc_host *host = container_of(work,
2740 struct msmsdcc_host,
2741 msm_bus_vote.vote_work.work);
2742 unsigned long flags;
2743
2744 if (!host->msm_bus_vote.client_handle)
2745 return;
2746
2747 spin_lock_irqsave(&host->lock, flags);
2748 /* don't vote for 0 bandwidth if any request is in progress */
2749 if (!host->curr.mrq)
2750 msmsdcc_msm_bus_set_vote(host,
2751 host->msm_bus_vote.min_bw_vote, flags);
2752 else
2753 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2754 " bus voting to 0 bandwidth\n",
2755 mmc_hostname(host->mmc), __func__);
2756 spin_unlock_irqrestore(&host->lock, flags);
2757}
2758
2759/*
2760 * This function cancels any scheduled delayed work
2761 * and sets the bus vote based on ios argument.
2762 * If "ios" argument is NULL, bandwidth required is 0 else
2763 * calculate the bandwidth based on ios parameters.
2764 */
2765static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2766 struct msmsdcc_host *host,
2767 struct mmc_ios *ios)
2768{
2769 unsigned long flags;
2770 unsigned int bw;
2771 int vote;
2772
2773 if (!host->msm_bus_vote.client_handle)
2774 return;
2775
2776 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2777
2778 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2779 spin_lock_irqsave(&host->lock, flags);
2780 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2781 msmsdcc_msm_bus_set_vote(host, vote, flags);
2782 spin_unlock_irqrestore(&host->lock, flags);
2783}
2784
2785/* This function queues a work which will set the bandwidth requiement to 0 */
2786static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2787{
2788 unsigned long flags;
2789
2790 if (!host->msm_bus_vote.client_handle)
2791 return;
2792
2793 spin_lock_irqsave(&host->lock, flags);
2794 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2795 queue_delayed_work(system_nrt_wq,
2796 &host->msm_bus_vote.vote_work,
2797 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2798 spin_unlock_irqrestore(&host->lock, flags);
2799}
2800
San Mehat9d2bd732009-09-22 16:44:22 -07002801static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302802msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2803{
2804 struct mmc_host *mmc = host->mmc;
2805
2806 /*
2807 * SDIO_AL clients has different mechanism of handling LPM through
2808 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2809 * part of that. Here, we are interested only in clients like WLAN.
2810 */
2811 if (!(mmc->card && mmc_card_sdio(mmc->card))
2812 || host->plat->is_sdio_al_client)
2813 goto out;
2814
2815 if (!host->sdcc_suspended) {
2816 /*
2817 * When MSM is not in power collapse and we
2818 * are disabling clocks, enable bit 22 in MASK0
2819 * to handle asynchronous SDIO interrupts.
2820 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302821 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302822 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302823 mb();
2824 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302825 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302826 msmsdcc_sync_reg_wr(host);
2827 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302828 goto out;
2829 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2830 /*
2831 * Wakeup MSM only if SDIO function drivers set
2832 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2833 */
2834 goto out;
2835 }
2836
2837 if (enable_wakeup_irq) {
2838 if (!host->plat->sdiowakeup_irq) {
2839 /*
2840 * When there is no gpio line that can be configured
2841 * as wakeup interrupt handle it by configuring
2842 * asynchronous sdio interrupts and DAT1 line.
2843 */
2844 writel_relaxed(MCI_SDIOINTMASK,
2845 host->base + MMCIMASK0);
2846 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302847 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302848 /* configure sdcc core interrupt as wakeup interrupt */
2849 msmsdcc_enable_irq_wake(host);
2850 } else {
2851 /* Let gpio line handle wakeup interrupt */
2852 writel_relaxed(0, host->base + MMCIMASK0);
2853 mb();
2854 if (host->sdio_wakeupirq_disabled) {
2855 host->sdio_wakeupirq_disabled = 0;
2856 /* configure gpio line as wakeup interrupt */
2857 msmsdcc_enable_irq_wake(host);
2858 enable_irq(host->plat->sdiowakeup_irq);
2859 }
2860 }
2861 } else {
2862 if (!host->plat->sdiowakeup_irq) {
2863 /*
2864 * We may not have cleared bit 22 in the interrupt
2865 * handler as the clocks might be off at that time.
2866 */
2867 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302868 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302869 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302870 msmsdcc_disable_irq_wake(host);
2871 } else if (!host->sdio_wakeupirq_disabled) {
2872 disable_irq_nosync(host->plat->sdiowakeup_irq);
2873 msmsdcc_disable_irq_wake(host);
2874 host->sdio_wakeupirq_disabled = 1;
2875 }
2876 }
2877out:
2878 return;
2879}
2880
2881static void
San Mehat9d2bd732009-09-22 16:44:22 -07002882msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2883{
2884 struct msmsdcc_host *host = mmc_priv(mmc);
2885 u32 clk = 0, pwr = 0;
2886 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002887 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002889
Sahitya Tummala7a892482011-01-18 11:22:49 +05302890
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302891 /*
2892 * Disable SDCC core interrupt until set_ios is completed.
2893 * This avoids any race conditions with interrupt raised
2894 * when turning on/off the clocks. One possible
2895 * scenario is SDIO operational interrupt while the clock
2896 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302897 * host->lock is being released intermittently below.
2898 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302899 */
2900
Asutosh Dasf5298c32012-04-03 14:51:47 +05302901 mutex_lock(&host->clk_mutex);
2902 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302903 spin_lock_irqsave(&host->lock, flags);
2904 if (!host->sdcc_irq_disabled) {
2905 spin_unlock_irqrestore(&host->lock, flags);
2906 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302908 host->sdcc_irq_disabled = 1;
2909 }
2910 spin_unlock_irqrestore(&host->lock, flags);
2911
2912 pwr = msmsdcc_setup_pwr(host, ios);
2913
2914 spin_lock_irqsave(&host->lock, flags);
2915 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302917 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002918 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302919 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302921 writel_relaxed(host->mci_irqenable,
2922 host->base + MMCIMASK0);
2923 mb();
2924 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002925 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926
2927 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2928 /*
2929 * For DDR50 mode, controller needs clock rate to be
2930 * double than what is required on the SD card CLK pin.
2931 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302932 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933 /*
2934 * Make sure that we don't double the clock if
2935 * doubled clock rate is already set
2936 */
2937 if (!host->ddr_doubled_clk_rate ||
2938 (host->ddr_doubled_clk_rate &&
2939 (host->ddr_doubled_clk_rate != ios->clock))) {
2940 host->ddr_doubled_clk_rate =
2941 msmsdcc_get_sup_clk_rate(
2942 host, (ios->clock * 2));
2943 clock = host->ddr_doubled_clk_rate;
2944 }
2945 } else {
2946 host->ddr_doubled_clk_rate = 0;
2947 }
2948
2949 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302950 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002951 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302952 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002953 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302954 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002955 mmc_hostname(mmc), clock);
2956 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302957 host->reg_write_delay =
2958 (1 + ((3 * USEC_PER_SEC) /
2959 (host->clk_rate ? host->clk_rate :
2960 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 }
2962 /*
2963 * give atleast 2 MCLK cycles delay for clocks
2964 * and SDCC core to stabilize
2965 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302966 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002967 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002968 clk |= MCI_CLK_ENABLE;
2969 }
2970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 if (ios->bus_width == MMC_BUS_WIDTH_8)
2972 clk |= MCI_CLK_WIDEBUS_8;
2973 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2974 clk |= MCI_CLK_WIDEBUS_4;
2975 else
2976 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 if (msmsdcc_is_pwrsave(host))
2979 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002981 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983 host->tuning_needed = 0;
2984 /*
2985 * Select the controller timing mode according
2986 * to current bus speed mode
2987 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302988 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2989 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990 clk |= (4 << 14);
2991 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302992 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 clk |= (3 << 14);
2994 } else {
2995 clk |= (2 << 14); /* feedback clock */
2996 }
2997
2998 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2999 clk |= (2 << 23);
3000
Subhash Jadavani00083572012-02-15 16:18:01 +05303001 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3002 if (!ios->vdd)
3003 host->io_pad_pwr_switch = 0;
3004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 if (host->io_pad_pwr_switch)
3006 clk |= IO_PAD_PWR_SWITCH;
3007
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303008 /* Don't write into registers if clocks are disabled */
3009 if (host->clks_on) {
3010 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3011 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303012 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303014 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3015 host->pwr = pwr;
3016 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303017 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003018 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 }
3020
3021 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303022 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303023 spin_unlock_irqrestore(&host->lock, flags);
3024 /*
3025 * May get a wake-up interrupt the instant we disable the
3026 * clocks. This would disable the wake-up interrupt.
3027 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303029 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 host->clks_on = 0;
3031 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303032
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303033 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303034 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303035 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303036
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303037 /* Let interrupts be disabled if the host is powered off */
3038 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3039 enable_irq(host->core_irqres->start);
3040 host->sdcc_irq_disabled = 0;
3041 }
3042
San Mehat4adbbcc2009-11-08 13:00:37 -08003043 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303044 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003045}
3046
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003047int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3048{
3049 struct msmsdcc_host *host = mmc_priv(mmc);
3050 u32 clk;
3051
3052 clk = readl_relaxed(host->base + MMCICLOCK);
3053 pr_debug("Changing to pwr_save=%d", pwrsave);
3054 if (pwrsave && msmsdcc_is_pwrsave(host))
3055 clk |= MCI_CLK_PWRSAVE;
3056 else
3057 clk &= ~MCI_CLK_PWRSAVE;
3058 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303059 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060
3061 return 0;
3062}
3063
3064static int msmsdcc_get_ro(struct mmc_host *mmc)
3065{
3066 int status = -ENOSYS;
3067 struct msmsdcc_host *host = mmc_priv(mmc);
3068
3069 if (host->plat->wpswitch) {
3070 status = host->plat->wpswitch(mmc_dev(mmc));
3071 } else if (host->plat->wpswitch_gpio) {
3072 status = gpio_request(host->plat->wpswitch_gpio,
3073 "SD_WP_Switch");
3074 if (status) {
3075 pr_err("%s: %s: Failed to request GPIO %d\n",
3076 mmc_hostname(mmc), __func__,
3077 host->plat->wpswitch_gpio);
3078 } else {
3079 status = gpio_direction_input(
3080 host->plat->wpswitch_gpio);
3081 if (!status) {
3082 /*
3083 * Wait for atleast 300ms as debounce
3084 * time for GPIO input to stabilize.
3085 */
3086 msleep(300);
3087 status = gpio_get_value_cansleep(
3088 host->plat->wpswitch_gpio);
3089 status ^= !host->plat->wpswitch_polarity;
3090 }
3091 gpio_free(host->plat->wpswitch_gpio);
3092 }
3093 }
3094
3095 if (status < 0)
3096 status = -ENOSYS;
3097 pr_debug("%s: Card read-only status %d\n", __func__, status);
3098
3099 return status;
3100}
3101
San Mehat9d2bd732009-09-22 16:44:22 -07003102static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3103{
3104 struct msmsdcc_host *host = mmc_priv(mmc);
3105 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303107 /*
3108 * We may come here with clocks turned off in that case don't
3109 * attempt to write into MASK0 register. While turning on the
3110 * clocks mci_irqenable will be written to MASK0 register.
3111 */
3112
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303113 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003114 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303116 if (host->clks_on) {
3117 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303119 mb();
3120 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003121 } else {
3122 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303123 if (host->clks_on) {
3124 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303126 mb();
3127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303129 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003130}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003131
3132#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303133static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
3134{
3135 struct device *dev = mmc_dev(host->mmc);
3136
3137 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3138 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3139 " request_pending=%d, request=%d\n",
3140 mmc_hostname(host->mmc), dev->power.runtime_status,
3141 atomic_read(&dev->power.usage_count),
3142 dev->power.is_suspended, dev->power.disable_depth,
3143 dev->power.runtime_error, dev->power.request_pending,
3144 dev->power.request);
3145}
3146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003147static int msmsdcc_enable(struct mmc_host *mmc)
3148{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003149 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003150 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303151 struct msmsdcc_host *host = mmc_priv(mmc);
3152
3153 msmsdcc_pm_qos_update_latency(host, 1);
3154
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003155 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303156 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003158 if (host->sdcc_suspended && host->pending_resume &&
3159 !pm_runtime_suspended(dev)) {
3160 host->pending_resume = false;
3161 pm_runtime_get_noresume(dev);
3162 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303163 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003164 }
3165
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303166 if (dev->power.runtime_status == RPM_SUSPENDING) {
3167 if (mmc->suspend_task == current) {
3168 pm_runtime_get_noresume(dev);
3169 goto out;
3170 }
3171 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303173 rc = pm_runtime_get_sync(dev);
3174
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303175skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303176 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3178 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303179 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303180 return rc;
3181 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303182out:
3183 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303184 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003185}
3186
3187static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3188{
3189 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303190 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003191
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303192 msmsdcc_pm_qos_update_latency(host, 0);
3193
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303194 if (mmc->card && mmc_card_sdio(mmc->card)) {
3195 rc = 0;
3196 goto out;
3197 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303198
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303199 if (host->plat->disable_runtime_pm)
3200 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201
3202 rc = pm_runtime_put_sync(mmc->parent);
3203
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003204 /*
3205 * Ignore -EAGAIN as that is not fatal, it means that
3206 * either runtime usage count is non-zero or the runtime
3207 * pm itself is disabled or not in proper state to process
3208 * idle notification.
3209 */
3210 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3212 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303213 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003214 return rc;
3215 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303216
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303217out:
3218 msmsdcc_msm_bus_queue_work(host);
3219 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220}
3221#else
subhashj245831e2012-04-30 18:46:17 +05303222static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3223
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303224static int msmsdcc_enable(struct mmc_host *mmc)
3225{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003226 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303227 struct msmsdcc_host *host = mmc_priv(mmc);
3228 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303229 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303230
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303231 msmsdcc_pm_qos_update_latency(host, 1);
3232
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303233 if (mmc->card && mmc_card_sdio(mmc->card)) {
3234 rc = 0;
3235 goto out;
3236 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003237
3238 if (host->sdcc_suspended && host->pending_resume) {
3239 host->pending_resume = false;
3240 rc = msmsdcc_runtime_resume(dev);
3241 goto out;
3242 }
3243
Asutosh Dasf5298c32012-04-03 14:51:47 +05303244 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303245 spin_lock_irqsave(&host->lock, flags);
3246 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303247 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303248 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303249 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303250 host->clks_on = 1;
3251 }
3252 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303253 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303254
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003255out:
3256 if (rc < 0) {
3257 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3258 __func__, rc);
3259 return rc;
3260 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303261 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303262 return 0;
3263}
3264
3265static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3266{
3267 struct msmsdcc_host *host = mmc_priv(mmc);
3268 unsigned long flags;
3269
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303270 msmsdcc_pm_qos_update_latency(host, 0);
3271
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303272 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303273 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303274
Asutosh Dasf5298c32012-04-03 14:51:47 +05303275 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303276 spin_lock_irqsave(&host->lock, flags);
3277 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303278 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303279 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303280 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303281 host->clks_on = 0;
3282 }
3283 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303284 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303285
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303286out:
3287 msmsdcc_msm_bus_queue_work(host);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303288 return 0;
3289}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003290#endif
3291
3292static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3293 struct mmc_ios *ios)
3294{
3295 struct msmsdcc_host *host = mmc_priv(mmc);
3296 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303297 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003298
Subhash Jadavani00083572012-02-15 16:18:01 +05303299 spin_lock_irqsave(&host->lock, flags);
3300 host->io_pad_pwr_switch = 0;
3301 spin_unlock_irqrestore(&host->lock, flags);
3302
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303303 /*
3304 * For eMMC cards, VccQ voltage range must be changed
3305 * only if it operates in HS200 SDR 1.2V mode or in
3306 * DDR 1.2V mode.
3307 */
3308 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3309 rc = msmsdcc_set_vccq_vol(host, 1200000);
3310 goto out;
3311 }
3312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003313 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3314 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303315 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316 goto out;
3317 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3318 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303319 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320 goto out;
3321 }
San Mehat9d2bd732009-09-22 16:44:22 -07003322
3323 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003324 /*
3325 * If we are here means voltage switch from high voltage to
3326 * low voltage is required
3327 */
3328
3329 /*
3330 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3331 * register until they become all zeros.
3332 */
3333 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303334 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3336 mmc_hostname(mmc), __func__);
3337 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003338 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339
3340 /* Stop SD CLK output. */
3341 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3342 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303343 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003344 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345
3346 /*
3347 * Switch VDDPX from high voltage to low voltage
3348 * to change the VDD of the SD IO pads.
3349 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303350 rc = msmsdcc_set_vddp_low_vol(host);
3351 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353
3354 spin_lock_irqsave(&host->lock, flags);
3355 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3356 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303357 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 host->io_pad_pwr_switch = 1;
3359 spin_unlock_irqrestore(&host->lock, flags);
3360
3361 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3362 usleep_range(5000, 5500);
3363
3364 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303365 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003366 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3367 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303368 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 spin_unlock_irqrestore(&host->lock, flags);
3370
3371 /*
3372 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3373 * don't become all ones within 1 ms then a Voltage Switch
3374 * sequence has failed and a power cycle to the card is required.
3375 * Otherwise Voltage Switch sequence is completed successfully.
3376 */
3377 usleep_range(1000, 1500);
3378
3379 spin_lock_irqsave(&host->lock, flags);
3380 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3381 != (0xF << 1)) {
3382 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3383 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303384 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385 goto out_unlock;
3386 }
3387
3388out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303389 /* Enable PWRSAVE */
3390 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3391 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303392 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 spin_unlock_irqrestore(&host->lock, flags);
3394out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303395 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396}
3397
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303398static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401
3402 /* Program the MCLK value to MCLK_FREQ bit field */
3403 if (host->clk_rate <= 112000000)
3404 mclk_freq = 0;
3405 else if (host->clk_rate <= 125000000)
3406 mclk_freq = 1;
3407 else if (host->clk_rate <= 137000000)
3408 mclk_freq = 2;
3409 else if (host->clk_rate <= 150000000)
3410 mclk_freq = 3;
3411 else if (host->clk_rate <= 162000000)
3412 mclk_freq = 4;
3413 else if (host->clk_rate <= 175000000)
3414 mclk_freq = 5;
3415 else if (host->clk_rate <= 187000000)
3416 mclk_freq = 6;
3417 else if (host->clk_rate <= 200000000)
3418 mclk_freq = 7;
3419
3420 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3421 & ~(7 << 24)) | (mclk_freq << 24)),
3422 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423}
3424
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303425/* Initialize the DLL (Programmable Delay Line ) */
3426static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303429 unsigned long flags;
3430 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003431
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303432 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433 /*
3434 * Make sure that clock is always enabled when DLL
3435 * tuning is in progress. Keeping PWRSAVE ON may
3436 * turn off the clock. So let's disable the PWRSAVE
3437 * here and re-enable it once tuning is completed.
3438 */
3439 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3440 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303441 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303442
3443 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3444 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3445 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3446
3447 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3448 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3449 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3450
3451 msmsdcc_cm_sdc4_dll_set_freq(host);
3452
3453 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3454 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3455 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3456
3457 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3458 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3459 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3460
3461 /* Set DLL_EN bit to 1. */
3462 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3463 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3464
3465 /* Set CK_OUT_EN bit to 1. */
3466 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3467 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3468
3469 wait_cnt = 50;
3470 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3471 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3472 /* max. wait for 50us sec for LOCK bit to be set */
3473 if (--wait_cnt == 0) {
3474 pr_err("%s: %s: DLL failed to LOCK\n",
3475 mmc_hostname(host->mmc), __func__);
3476 rc = -ETIMEDOUT;
3477 goto out;
3478 }
3479 /* wait for 1us before polling again */
3480 udelay(1);
3481 }
3482
3483out:
3484 /* re-enable PWRSAVE */
3485 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3486 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303487 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303488 spin_unlock_irqrestore(&host->lock, flags);
3489
3490 return rc;
3491}
3492
3493static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3494 u8 poll)
3495{
3496 int rc = 0;
3497 u32 wait_cnt = 50;
3498 u8 ck_out_en = 0;
3499
3500 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3501 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3502 MCI_CK_OUT_EN);
3503
3504 while (ck_out_en != poll) {
3505 if (--wait_cnt == 0) {
3506 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3507 mmc_hostname(host->mmc), __func__, poll);
3508 rc = -ETIMEDOUT;
3509 goto out;
3510 }
3511 udelay(1);
3512
3513 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3514 MCI_CK_OUT_EN);
3515 }
3516out:
3517 return rc;
3518}
3519
3520/*
3521 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3522 * calibration sequence. This function should be called before
3523 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3524 * commands (CMD17/CMD18).
3525 *
3526 * This function gets called when host spinlock acquired.
3527 */
3528static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3529{
3530 int rc = 0;
3531 u32 config;
3532
3533 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3534 config |= MCI_CDR_EN;
3535 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3536 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3537
3538 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3539 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3540 if (rc)
3541 goto err_out;
3542
3543 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3544 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3545 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3546
3547 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3548 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3549 if (rc)
3550 goto err_out;
3551
3552 goto out;
3553
3554err_out:
3555 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3556out:
3557 return rc;
3558}
3559
3560static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3561 u8 phase)
3562{
3563 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303564 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3565 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3566 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303567 unsigned long flags;
3568 u32 config;
3569
3570 spin_lock_irqsave(&host->lock, flags);
3571
3572 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3573 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3574 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3575 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3576
3577 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3578 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3579 if (rc)
3580 goto err_out;
3581
3582 /*
3583 * Write the selected DLL clock output phase (0 ... 15)
3584 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3585 */
3586 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3587 & ~(0xF << 20))
3588 | (grey_coded_phase_table[phase] << 20)),
3589 host->base + MCI_DLL_CONFIG);
3590
3591 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3592 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3593 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3594
3595 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3596 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3597 if (rc)
3598 goto err_out;
3599
3600 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3601 config |= MCI_CDR_EN;
3602 config &= ~MCI_CDR_EXT_EN;
3603 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3604 goto out;
3605
3606err_out:
3607 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3608 mmc_hostname(host->mmc), __func__, phase);
3609out:
3610 spin_unlock_irqrestore(&host->lock, flags);
3611 return rc;
3612}
3613
3614/*
3615 * Find out the greatest range of consecuitive selected
3616 * DLL clock output phases that can be used as sampling
3617 * setting for SD3.0 UHS-I card read operation (in SDR104
3618 * timing mode) or for eMMC4.5 card read operation (in HS200
3619 * timing mode).
3620 * Select the 3/4 of the range and configure the DLL with the
3621 * selected DLL clock output phase.
3622*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303623static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303624 u8 *phase_table, u8 total_phases)
3625{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303626 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303627 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303628 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3629 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303630 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303631 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3632 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303633
Subhash Jadavani6159c622012-03-15 19:05:55 +05303634 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303635 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3636 mmc_hostname(host->mmc), __func__, total_phases);
3637 return -EINVAL;
3638 }
3639
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303640 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641 ranges[row_index][col_index] = phase_table[cnt];
3642 phases_per_row[row_index] += 1;
3643 col_index++;
3644
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303645 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303646 continue;
3647 /* check if next phase in phase_table is consecutive or not */
3648 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3649 row_index++;
3650 col_index = 0;
3651 }
3652 }
3653
Subhash Jadavani6159c622012-03-15 19:05:55 +05303654 if (row_index >= MAX_PHASES)
3655 return -EINVAL;
3656
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303657 /* Check if phase-0 is present in first valid window? */
3658 if (!ranges[0][0]) {
3659 phase_0_found = true;
3660 phase_0_raw_index = 0;
3661 /* Check if cycle exist between 2 valid windows */
3662 for (cnt = 1; cnt <= row_index; cnt++) {
3663 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303664 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303665 if (ranges[cnt][i] == 15) {
3666 phase_15_found = true;
3667 phase_15_raw_index = cnt;
3668 break;
3669 }
3670 }
3671 }
3672 }
3673 }
3674
3675 /* If 2 valid windows form cycle then merge them as single window */
3676 if (phase_0_found && phase_15_found) {
3677 /* number of phases in raw where phase 0 is present */
3678 u8 phases_0 = phases_per_row[phase_0_raw_index];
3679 /* number of phases in raw where phase 15 is present */
3680 u8 phases_15 = phases_per_row[phase_15_raw_index];
3681
Subhash Jadavani6159c622012-03-15 19:05:55 +05303682 if (phases_0 + phases_15 >= MAX_PHASES)
3683 /*
3684 * If there are more than 1 phase windows then total
3685 * number of phases in both the windows should not be
3686 * more than or equal to MAX_PHASES.
3687 */
3688 return -EINVAL;
3689
3690 /* Merge 2 cyclic windows */
3691 i = phases_15;
3692 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303693 ranges[phase_15_raw_index][i] =
3694 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303695 if (++i >= MAX_PHASES)
3696 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303697 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303698
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303699 phases_per_row[phase_0_raw_index] = 0;
3700 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3701 }
3702
3703 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303704 if (phases_per_row[cnt] > curr_max) {
3705 curr_max = phases_per_row[cnt];
3706 selected_row_index = cnt;
3707 }
3708 }
3709
Subhash Jadavani6159c622012-03-15 19:05:55 +05303710 i = ((curr_max * 3) / 4);
3711 if (i)
3712 i--;
3713
Subhash Jadavani34187042012-03-02 10:59:49 +05303714 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303715
Subhash Jadavani6159c622012-03-15 19:05:55 +05303716 if (ret >= MAX_PHASES) {
3717 ret = -EINVAL;
3718 pr_err("%s: %s: invalid phase selected=%d\n",
3719 mmc_hostname(host->mmc), __func__, ret);
3720 }
3721
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303722 return ret;
3723}
3724
Girish K Sa3f41692012-02-29 12:00:09 +05303725static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303726{
3727 int rc = 0;
3728 struct msmsdcc_host *host = mmc_priv(mmc);
3729 unsigned long flags;
3730 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303731 const u32 *tuning_block_pattern = tuning_block_64;
3732 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303733
3734 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3735
3736 /* Tuning is only required for SDR104 modes */
3737 if (!host->tuning_needed) {
3738 rc = 0;
3739 goto exit;
3740 }
3741
3742 spin_lock_irqsave(&host->lock, flags);
3743 WARN(!host->pwr, "SDCC power is turned off\n");
3744 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3745 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3746
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303747 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303748 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3749 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3750 tuning_block_pattern = tuning_block_128;
3751 size = sizeof(tuning_block_128);
3752 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303753 spin_unlock_irqrestore(&host->lock, flags);
3754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003755 /* first of all reset the tuning block */
3756 rc = msmsdcc_init_cm_sdc4_dll(host);
3757 if (rc)
3758 goto out;
3759
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303760 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761 if (!data_buf) {
3762 rc = -ENOMEM;
3763 goto out;
3764 }
3765
3766 phase = 0;
3767 do {
3768 struct mmc_command cmd = {0};
3769 struct mmc_data data = {0};
3770 struct mmc_request mrq = {
3771 .cmd = &cmd,
3772 .data = &data
3773 };
3774 struct scatterlist sg;
3775
3776 /* set the phase in delay line hw block */
3777 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3778 if (rc)
3779 goto kfree;
3780
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303781 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003782 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3783
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303784 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785 data.blocks = 1;
3786 data.flags = MMC_DATA_READ;
3787 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3788
3789 data.sg = &sg;
3790 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303791 sg_init_one(&sg, data_buf, size);
3792 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003793 mmc_wait_for_req(mmc, &mrq);
3794
3795 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303796 !memcmp(data_buf, tuning_block_pattern, size)) {
3797 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303799 pr_debug("%s: %s: found good phase = %d\n",
3800 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 }
3802 } while (++phase < 16);
3803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003804 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303805 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303806 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303807 if (rc < 0)
3808 goto kfree;
3809 else
3810 phase = (u8)rc;
3811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812 /*
3813 * Finally set the selected phase in delay
3814 * line hw block.
3815 */
3816 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3817 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303818 goto kfree;
3819 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3820 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821 } else {
3822 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303823 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303825 msmsdcc_dump_sdcc_state(host);
3826 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003828
3829kfree:
3830 kfree(data_buf);
3831out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303832 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303833 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303834 spin_unlock_irqrestore(&host->lock, flags);
3835exit:
3836 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003838}
3839
3840static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841 .enable = msmsdcc_enable,
3842 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303843 .pre_req = msmsdcc_pre_req,
3844 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003845 .request = msmsdcc_request,
3846 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003848 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3850 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003851};
3852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003853static unsigned int
3854msmsdcc_slot_status(struct msmsdcc_host *host)
3855{
3856 int status;
3857 unsigned int gpio_no = host->plat->status_gpio;
3858
3859 status = gpio_request(gpio_no, "SD_HW_Detect");
3860 if (status) {
3861 pr_err("%s: %s: Failed to request GPIO %d\n",
3862 mmc_hostname(host->mmc), __func__, gpio_no);
3863 } else {
3864 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003865 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003866 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003867 if (host->plat->is_status_gpio_active_low)
3868 status = !status;
3869 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003870 gpio_free(gpio_no);
3871 }
3872 return status;
3873}
3874
San Mehat9d2bd732009-09-22 16:44:22 -07003875static void
3876msmsdcc_check_status(unsigned long data)
3877{
3878 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3879 unsigned int status;
3880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003882 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003884 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885 status = msmsdcc_slot_status(host);
3886
Krishna Konda941604a2012-01-10 17:46:34 -08003887 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003889 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003890 if (host->plat->status)
3891 pr_info("%s: Slot status change detected "
3892 "(%d -> %d)\n",
3893 mmc_hostname(host->mmc),
3894 host->oldstat, status);
3895 else if (host->plat->is_status_gpio_active_low)
3896 pr_info("%s: Slot status change detected "
3897 "(%d -> %d) and the card detect GPIO"
3898 " is ACTIVE_LOW\n",
3899 mmc_hostname(host->mmc),
3900 host->oldstat, status);
3901 else
3902 pr_info("%s: Slot status change detected "
3903 "(%d -> %d) and the card detect GPIO"
3904 " is ACTIVE_HIGH\n",
3905 mmc_hostname(host->mmc),
3906 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003907 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908 }
3909 host->oldstat = status;
3910 } else {
3911 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003912 }
San Mehat9d2bd732009-09-22 16:44:22 -07003913}
3914
3915static irqreturn_t
3916msmsdcc_platform_status_irq(int irq, void *dev_id)
3917{
3918 struct msmsdcc_host *host = dev_id;
3919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003921 msmsdcc_check_status((unsigned long) host);
3922 return IRQ_HANDLED;
3923}
3924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003925static irqreturn_t
3926msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3927{
3928 struct msmsdcc_host *host = dev_id;
3929
3930 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3931 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303932 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303934 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 wake_lock(&host->sdio_wlock);
3936 msmsdcc_disable_irq_wake(host);
3937 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303938 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003939 }
3940 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303942 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303943 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303944 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945 }
3946 spin_unlock(&host->lock);
3947
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303948out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949 return IRQ_HANDLED;
3950}
3951
San Mehat9d2bd732009-09-22 16:44:22 -07003952static void
3953msmsdcc_status_notify_cb(int card_present, void *dev_id)
3954{
3955 struct msmsdcc_host *host = dev_id;
3956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003957 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003958 card_present);
3959 msmsdcc_check_status((unsigned long) host);
3960}
3961
San Mehat9d2bd732009-09-22 16:44:22 -07003962static int
3963msmsdcc_init_dma(struct msmsdcc_host *host)
3964{
3965 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3966 host->dma.host = host;
3967 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003968 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003969
3970 if (!host->dmares)
3971 return -ENODEV;
3972
3973 host->dma.nc = dma_alloc_coherent(NULL,
3974 sizeof(struct msmsdcc_nc_dmadata),
3975 &host->dma.nc_busaddr,
3976 GFP_KERNEL);
3977 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003978 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003979 return -ENOMEM;
3980 }
3981 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3982 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3983 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3984 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3985 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003986 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003987
3988 return 0;
3989}
3990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003991#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3992/**
3993 * Allocate and Connect a SDCC peripheral's SPS endpoint
3994 *
3995 * This function allocates endpoint context and
3996 * connect it with memory endpoint by calling
3997 * appropriate SPS driver APIs.
3998 *
3999 * Also registers a SPS callback function with
4000 * SPS driver
4001 *
4002 * This function should only be called once typically
4003 * during driver probe.
4004 *
4005 * @host - Pointer to sdcc host structure
4006 * @ep - Pointer to sps endpoint data structure
4007 * @is_produce - 1 means Producer endpoint
4008 * 0 means Consumer endpoint
4009 *
4010 * @return - 0 if successful else negative value.
4011 *
4012 */
4013static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4014 struct msmsdcc_sps_ep_conn_data *ep,
4015 bool is_producer)
4016{
4017 int rc = 0;
4018 struct sps_pipe *sps_pipe_handle;
4019 struct sps_connect *sps_config = &ep->config;
4020 struct sps_register_event *sps_event = &ep->event;
4021
4022 /* Allocate endpoint context */
4023 sps_pipe_handle = sps_alloc_endpoint();
4024 if (!sps_pipe_handle) {
4025 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4026 mmc_hostname(host->mmc), is_producer);
4027 rc = -ENOMEM;
4028 goto out;
4029 }
4030
4031 /* Get default connection configuration for an endpoint */
4032 rc = sps_get_config(sps_pipe_handle, sps_config);
4033 if (rc) {
4034 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4035 " rc=%d", mmc_hostname(host->mmc),
4036 (u32)sps_pipe_handle, rc);
4037 goto get_config_err;
4038 }
4039
4040 /* Modify the default connection configuration */
4041 if (is_producer) {
4042 /*
4043 * For SDCC producer transfer, source should be
4044 * SDCC peripheral where as destination should
4045 * be system memory.
4046 */
4047 sps_config->source = host->sps.bam_handle;
4048 sps_config->destination = SPS_DEV_HANDLE_MEM;
4049 /* Producer pipe will handle this connection */
4050 sps_config->mode = SPS_MODE_SRC;
4051 sps_config->options =
4052 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4053 } else {
4054 /*
4055 * For SDCC consumer transfer, source should be
4056 * system memory where as destination should
4057 * SDCC peripheral
4058 */
4059 sps_config->source = SPS_DEV_HANDLE_MEM;
4060 sps_config->destination = host->sps.bam_handle;
4061 sps_config->mode = SPS_MODE_DEST;
4062 sps_config->options =
4063 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4064 }
4065
4066 /* Producer pipe index */
4067 sps_config->src_pipe_index = host->sps.src_pipe_index;
4068 /* Consumer pipe index */
4069 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4070 /*
4071 * This event thresold value is only significant for BAM-to-BAM
4072 * transfer. It's ignored for BAM-to-System mode transfer.
4073 */
4074 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304075
4076 /* Allocate maximum descriptor fifo size */
4077 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4078 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004079 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4080 sps_config->desc.size,
4081 &sps_config->desc.phys_base,
4082 GFP_KERNEL);
4083
Pratibhasagar V00b94332011-10-18 14:57:27 +05304084 if (!sps_config->desc.base) {
4085 rc = -ENOMEM;
4086 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4087 , mmc_hostname(host->mmc));
4088 goto get_config_err;
4089 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4091
4092 /* Establish connection between peripheral and memory endpoint */
4093 rc = sps_connect(sps_pipe_handle, sps_config);
4094 if (rc) {
4095 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4096 " rc=%d", mmc_hostname(host->mmc),
4097 (u32)sps_pipe_handle, rc);
4098 goto sps_connect_err;
4099 }
4100
4101 sps_event->mode = SPS_TRIGGER_CALLBACK;
4102 sps_event->options = SPS_O_EOT;
4103 sps_event->callback = msmsdcc_sps_complete_cb;
4104 sps_event->xfer_done = NULL;
4105 sps_event->user = (void *)host;
4106
4107 /* Register callback event for EOT (End of transfer) event. */
4108 rc = sps_register_event(sps_pipe_handle, sps_event);
4109 if (rc) {
4110 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4111 " rc=%d", mmc_hostname(host->mmc),
4112 (u32)sps_pipe_handle, rc);
4113 goto reg_event_err;
4114 }
4115 /* Now save the sps pipe handle */
4116 ep->pipe_handle = sps_pipe_handle;
4117 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4118 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4119 __func__, is_producer ? "READ" : "WRITE",
4120 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4121 goto out;
4122
4123reg_event_err:
4124 sps_disconnect(sps_pipe_handle);
4125sps_connect_err:
4126 dma_free_coherent(mmc_dev(host->mmc),
4127 sps_config->desc.size,
4128 sps_config->desc.base,
4129 sps_config->desc.phys_base);
4130get_config_err:
4131 sps_free_endpoint(sps_pipe_handle);
4132out:
4133 return rc;
4134}
4135
4136/**
4137 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4138 *
4139 * This function disconnect endpoint and deallocates
4140 * endpoint context.
4141 *
4142 * This function should only be called once typically
4143 * during driver remove.
4144 *
4145 * @host - Pointer to sdcc host structure
4146 * @ep - Pointer to sps endpoint data structure
4147 *
4148 */
4149static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4150 struct msmsdcc_sps_ep_conn_data *ep)
4151{
4152 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4153 struct sps_connect *sps_config = &ep->config;
4154 struct sps_register_event *sps_event = &ep->event;
4155
4156 sps_event->xfer_done = NULL;
4157 sps_event->callback = NULL;
4158 sps_register_event(sps_pipe_handle, sps_event);
4159 sps_disconnect(sps_pipe_handle);
4160 dma_free_coherent(mmc_dev(host->mmc),
4161 sps_config->desc.size,
4162 sps_config->desc.base,
4163 sps_config->desc.phys_base);
4164 sps_free_endpoint(sps_pipe_handle);
4165}
4166
4167/**
4168 * Reset SDCC peripheral's SPS endpoint
4169 *
4170 * This function disconnects an endpoint.
4171 *
4172 * This function should be called for reseting
4173 * SPS endpoint when data transfer error is
4174 * encountered during data transfer. This
4175 * can be considered as soft reset to endpoint.
4176 *
4177 * This function should only be called if
4178 * msmsdcc_sps_init() is already called.
4179 *
4180 * @host - Pointer to sdcc host structure
4181 * @ep - Pointer to sps endpoint data structure
4182 *
4183 * @return - 0 if successful else negative value.
4184 */
4185static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4186 struct msmsdcc_sps_ep_conn_data *ep)
4187{
4188 int rc = 0;
4189 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4190
4191 rc = sps_disconnect(sps_pipe_handle);
4192 if (rc) {
4193 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4194 " rc=%d", mmc_hostname(host->mmc), __func__,
4195 (u32)sps_pipe_handle, rc);
4196 goto out;
4197 }
4198 out:
4199 return rc;
4200}
4201
4202/**
4203 * Restore SDCC peripheral's SPS endpoint
4204 *
4205 * This function connects an endpoint.
4206 *
4207 * This function should be called for restoring
4208 * SPS endpoint after data transfer error is
4209 * encountered during data transfer. This
4210 * can be considered as soft reset to endpoint.
4211 *
4212 * This function should only be called if
4213 * msmsdcc_sps_reset_ep() is called before.
4214 *
4215 * @host - Pointer to sdcc host structure
4216 * @ep - Pointer to sps endpoint data structure
4217 *
4218 * @return - 0 if successful else negative value.
4219 */
4220static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4221 struct msmsdcc_sps_ep_conn_data *ep)
4222{
4223 int rc = 0;
4224 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4225 struct sps_connect *sps_config = &ep->config;
4226 struct sps_register_event *sps_event = &ep->event;
4227
4228 /* Establish connection between peripheral and memory endpoint */
4229 rc = sps_connect(sps_pipe_handle, sps_config);
4230 if (rc) {
4231 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4232 " rc=%d", mmc_hostname(host->mmc), __func__,
4233 (u32)sps_pipe_handle, rc);
4234 goto out;
4235 }
4236
4237 /* Register callback event for EOT (End of transfer) event. */
4238 rc = sps_register_event(sps_pipe_handle, sps_event);
4239 if (rc) {
4240 pr_err("%s: %s: sps_register_event() failed!!!"
4241 " pipe_handle=0x%x, rc=%d",
4242 mmc_hostname(host->mmc), __func__,
4243 (u32)sps_pipe_handle, rc);
4244 goto reg_event_err;
4245 }
4246 goto out;
4247
4248reg_event_err:
4249 sps_disconnect(sps_pipe_handle);
4250out:
4251 return rc;
4252}
4253
4254/**
4255 * Initialize SPS HW connected with SDCC core
4256 *
4257 * This function register BAM HW resources with
4258 * SPS driver and then initialize 2 SPS endpoints
4259 *
4260 * This function should only be called once typically
4261 * during driver probe.
4262 *
4263 * @host - Pointer to sdcc host structure
4264 *
4265 * @return - 0 if successful else negative value.
4266 *
4267 */
4268static int msmsdcc_sps_init(struct msmsdcc_host *host)
4269{
4270 int rc = 0;
4271 struct sps_bam_props bam = {0};
4272
4273 host->bam_base = ioremap(host->bam_memres->start,
4274 resource_size(host->bam_memres));
4275 if (!host->bam_base) {
4276 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4277 " size=0x%x", mmc_hostname(host->mmc),
4278 host->bam_memres->start,
4279 (host->bam_memres->end -
4280 host->bam_memres->start));
4281 rc = -ENOMEM;
4282 goto out;
4283 }
4284
4285 bam.phys_addr = host->bam_memres->start;
4286 bam.virt_addr = host->bam_base;
4287 /*
4288 * This event thresold value is only significant for BAM-to-BAM
4289 * transfer. It's ignored for BAM-to-System mode transfer.
4290 */
4291 bam.event_threshold = 0x10; /* Pipe event threshold */
4292 /*
4293 * This threshold controls when the BAM publish
4294 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304295 * SPS HW will be used for data transfer size even
4296 * less than SDCC FIFO size. So let's set BAM summing
4297 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004298 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304299 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004300 /* SPS driver wll handle the SDCC BAM IRQ */
4301 bam.irq = (u32)host->bam_irqres->start;
4302 bam.manage = SPS_BAM_MGR_LOCAL;
4303
4304 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4305 (u32)bam.phys_addr);
4306 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4307 (u32)bam.virt_addr);
4308
4309 /* Register SDCC Peripheral BAM device to SPS driver */
4310 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4311 if (rc) {
4312 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4313 mmc_hostname(host->mmc), rc);
4314 goto reg_bam_err;
4315 }
4316 pr_info("%s: BAM device registered. bam_handle=0x%x",
4317 mmc_hostname(host->mmc), host->sps.bam_handle);
4318
4319 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4320 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4321
4322 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4323 SPS_PROD_PERIPHERAL);
4324 if (rc)
4325 goto sps_reset_err;
4326 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4327 SPS_CONS_PERIPHERAL);
4328 if (rc)
4329 goto cons_conn_err;
4330
4331 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4332 mmc_hostname(host->mmc),
4333 (unsigned long long)host->bam_memres->start,
4334 (unsigned int)host->bam_irqres->start);
4335 goto out;
4336
4337cons_conn_err:
4338 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4339sps_reset_err:
4340 sps_deregister_bam_device(host->sps.bam_handle);
4341reg_bam_err:
4342 iounmap(host->bam_base);
4343out:
4344 return rc;
4345}
4346
4347/**
4348 * De-initialize SPS HW connected with SDCC core
4349 *
4350 * This function deinitialize SPS endpoints and then
4351 * deregisters BAM resources from SPS driver.
4352 *
4353 * This function should only be called once typically
4354 * during driver remove.
4355 *
4356 * @host - Pointer to sdcc host structure
4357 *
4358 */
4359static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4360{
4361 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4362 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4363 sps_deregister_bam_device(host->sps.bam_handle);
4364 iounmap(host->bam_base);
4365}
4366#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4367
4368static ssize_t
4369show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4370{
4371 struct mmc_host *mmc = dev_get_drvdata(dev);
4372 struct msmsdcc_host *host = mmc_priv(mmc);
4373 int poll;
4374 unsigned long flags;
4375
4376 spin_lock_irqsave(&host->lock, flags);
4377 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4378 spin_unlock_irqrestore(&host->lock, flags);
4379
4380 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4381}
4382
4383static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304384store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004385 const char *buf, size_t count)
4386{
4387 struct mmc_host *mmc = dev_get_drvdata(dev);
4388 struct msmsdcc_host *host = mmc_priv(mmc);
4389 int value;
4390 unsigned long flags;
4391
4392 sscanf(buf, "%d", &value);
4393
4394 spin_lock_irqsave(&host->lock, flags);
4395 if (value) {
4396 mmc->caps |= MMC_CAP_NEEDS_POLL;
4397 mmc_detect_change(host->mmc, 0);
4398 } else {
4399 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4400 }
4401#ifdef CONFIG_HAS_EARLYSUSPEND
4402 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4403#endif
4404 spin_unlock_irqrestore(&host->lock, flags);
4405 return count;
4406}
4407
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304408static ssize_t
4409show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4410 char *buf)
4411{
4412 struct mmc_host *mmc = dev_get_drvdata(dev);
4413 struct msmsdcc_host *host = mmc_priv(mmc);
4414
4415 return snprintf(buf, PAGE_SIZE, "%u\n",
4416 host->msm_bus_vote.is_max_bw_needed);
4417}
4418
4419static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304420store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304421 const char *buf, size_t count)
4422{
4423 struct mmc_host *mmc = dev_get_drvdata(dev);
4424 struct msmsdcc_host *host = mmc_priv(mmc);
4425 uint32_t value;
4426 unsigned long flags;
4427
4428 if (!kstrtou32(buf, 0, &value)) {
4429 spin_lock_irqsave(&host->lock, flags);
4430 host->msm_bus_vote.is_max_bw_needed = !!value;
4431 spin_unlock_irqrestore(&host->lock, flags);
4432 }
4433
4434 return count;
4435}
4436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004437#ifdef CONFIG_HAS_EARLYSUSPEND
4438static void msmsdcc_early_suspend(struct early_suspend *h)
4439{
4440 struct msmsdcc_host *host =
4441 container_of(h, struct msmsdcc_host, early_suspend);
4442 unsigned long flags;
4443
4444 spin_lock_irqsave(&host->lock, flags);
4445 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4446 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4447 spin_unlock_irqrestore(&host->lock, flags);
4448};
4449static void msmsdcc_late_resume(struct early_suspend *h)
4450{
4451 struct msmsdcc_host *host =
4452 container_of(h, struct msmsdcc_host, early_suspend);
4453 unsigned long flags;
4454
4455 if (host->polling_enabled) {
4456 spin_lock_irqsave(&host->lock, flags);
4457 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4458 mmc_detect_change(host->mmc, 0);
4459 spin_unlock_irqrestore(&host->lock, flags);
4460 }
4461};
4462#endif
4463
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304464static void msmsdcc_print_regs(const char *name, void __iomem *base,
4465 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304466{
4467 unsigned int i;
4468
4469 if (!base)
4470 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304471
4472 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4473 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304474 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304475 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4476 (u32)readl_relaxed(base + i*4),
4477 (u32)readl_relaxed(base + ((i+1)*4)),
4478 (u32)readl_relaxed(base + ((i+2)*4)),
4479 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304480 }
4481}
4482
4483static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4484{
4485 /* Dump current state of SDCC clocks, power and irq */
4486 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304487 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304488 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304489 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4490 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304491 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4492 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4493
4494 /* Now dump SDCC registers. Don't print FIFO registers */
4495 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304496 msmsdcc_print_regs("SDCC-CORE", host->base,
4497 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304498
4499 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304500 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304501 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4502 else if (host->is_dma_mode)
4503 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4504 mmc_hostname(host->mmc), host->dma.busy,
4505 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304506 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304507 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304508 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4509 host->dml_memres->start,
4510 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304511 pr_info("%s: SPS mode: busy=%d\n",
4512 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304513 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304514
4515 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4516 mmc_hostname(host->mmc), host->curr.xfer_size,
4517 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304518 }
4519
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304520 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304521 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4522 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4523 host->curr.got_dataend, host->prog_enable,
4524 host->curr.wait_for_auto_prog_done,
4525 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304526 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304527}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004529static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4530{
4531 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4532 struct mmc_request *mrq;
4533 unsigned long flags;
4534
4535 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004536 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004537 pr_info("%s: %s: dummy CMD52 timeout\n",
4538 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004539 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 }
4541
4542 mrq = host->curr.mrq;
4543
4544 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304545 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4546 mrq->cmd->opcode);
4547 msmsdcc_dump_sdcc_state(host);
4548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004549 if (!mrq->cmd->error)
4550 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304551 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 if (mrq->data && !mrq->data->error)
4554 mrq->data->error = -ETIMEDOUT;
4555 host->curr.data_xfered = 0;
4556 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004557 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558 } else if (host->sps.sg && host->is_sps_mode) {
4559 /* Stop current SPS transfer */
4560 msmsdcc_sps_exit_curr_xfer(host);
4561 } else {
4562 msmsdcc_reset_and_restore(host);
4563 msmsdcc_stop_data(host);
4564 if (mrq->data && mrq->data->stop)
4565 msmsdcc_start_command(host,
4566 mrq->data->stop, 0);
4567 else
4568 msmsdcc_request_end(host, mrq);
4569 }
4570 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304571 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304572 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004573 msmsdcc_reset_and_restore(host);
4574 msmsdcc_request_end(host, mrq);
4575 }
4576 }
4577 spin_unlock_irqrestore(&host->lock, flags);
4578}
4579
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304580static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4581{
4582 int i, ret;
4583 struct mmc_platform_data *pdata;
4584 struct device_node *np = dev->of_node;
4585 u32 bus_width = 0;
4586 u32 *clk_table;
4587 int clk_table_len;
4588 u32 *sup_voltages;
4589 int sup_volt_len;
4590
4591 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4592 if (!pdata) {
4593 dev_err(dev, "could not allocate memory for platform data\n");
4594 goto err;
4595 }
4596
4597 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4598 if (bus_width == 8) {
4599 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4600 } else if (bus_width == 4) {
4601 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4602 } else {
4603 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4604 pdata->mmc_bus_width = 0;
4605 }
4606
4607 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4608 size_t sz;
4609 sz = sup_volt_len / sizeof(*sup_voltages);
4610 if (sz > 0) {
4611 sup_voltages = devm_kzalloc(dev,
4612 sz * sizeof(*sup_voltages), GFP_KERNEL);
4613 if (!sup_voltages) {
4614 dev_err(dev, "No memory for supported voltage\n");
4615 goto err;
4616 }
4617
4618 ret = of_property_read_u32_array(np,
4619 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4620 if (ret < 0) {
4621 dev_err(dev, "error while reading voltage"
4622 "ranges %d\n", ret);
4623 goto err;
4624 }
4625 } else {
4626 dev_err(dev, "No supported voltages\n");
4627 goto err;
4628 }
4629 for (i = 0; i < sz; i += 2) {
4630 u32 mask;
4631
4632 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4633 sup_voltages[i + 1]);
4634 if (!mask)
4635 dev_err(dev, "Invalide voltage range %d\n", i);
4636 pdata->ocr_mask |= mask;
4637 }
4638 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4639 } else {
4640 dev_err(dev, "Supported voltage range not specified\n");
4641 }
4642
4643 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4644 size_t sz;
4645 sz = clk_table_len / sizeof(*clk_table);
4646
4647 if (sz > 0) {
4648 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4649 GFP_KERNEL);
4650 if (!clk_table) {
4651 dev_err(dev, "No memory for clock table\n");
4652 goto err;
4653 }
4654
4655 ret = of_property_read_u32_array(np,
4656 "qcom,sdcc-clk-rates", clk_table, sz);
4657 if (ret < 0) {
4658 dev_err(dev, "error while reading clk"
4659 "table %d\n", ret);
4660 goto err;
4661 }
4662 } else {
4663 dev_err(dev, "clk_table not specified\n");
4664 goto err;
4665 }
4666 pdata->sup_clk_table = clk_table;
4667 pdata->sup_clk_cnt = sz;
4668 } else {
4669 dev_err(dev, "Supported clock rates not specified\n");
4670 }
4671
4672 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4673 pdata->nonremovable = true;
4674 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4675 pdata->disable_cmd23 = true;
4676
4677 return pdata;
4678err:
4679 return NULL;
4680}
4681
San Mehat9d2bd732009-09-22 16:44:22 -07004682static int
4683msmsdcc_probe(struct platform_device *pdev)
4684{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304685 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004686 struct msmsdcc_host *host;
4687 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688 unsigned long flags;
4689 struct resource *core_irqres = NULL;
4690 struct resource *bam_irqres = NULL;
4691 struct resource *core_memres = NULL;
4692 struct resource *dml_memres = NULL;
4693 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004694 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004695 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304696 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004697 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004698
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304699 if (pdev->dev.of_node) {
4700 plat = msmsdcc_populate_pdata(&pdev->dev);
4701 of_property_read_u32((&pdev->dev)->of_node,
4702 "cell-index", &pdev->id);
4703 } else {
4704 plat = pdev->dev.platform_data;
4705 }
4706
San Mehat9d2bd732009-09-22 16:44:22 -07004707 /* must have platform data */
4708 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004709 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004710 ret = -EINVAL;
4711 goto out;
4712 }
4713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004714 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004715 return -EINVAL;
4716
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304717 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4718 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4719 return -EINVAL;
4720 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004721
San Mehat9d2bd732009-09-22 16:44:22 -07004722 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004723 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004724 return -ENXIO;
4725 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304726 if (pdev->dev.of_node) {
4727 /*
4728 * Device tree iomem resources are only accessible by index.
4729 * index = 0 -> SDCC register interface
4730 * index = 1 -> DML register interface
4731 * index = 2 -> BAM register interface
4732 * IRQ resources:
4733 * index = 0 -> SDCC IRQ
4734 * index = 1 -> BAM IRQ
4735 */
4736 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4737 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4738 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4739 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4740 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4741 } else {
4742 for (i = 0; i < pdev->num_resources; i++) {
4743 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4744 if (!strncmp(pdev->resource[i].name,
4745 "sdcc_dml_addr",
4746 sizeof("sdcc_dml_addr")))
4747 dml_memres = &pdev->resource[i];
4748 else if (!strncmp(pdev->resource[i].name,
4749 "sdcc_bam_addr",
4750 sizeof("sdcc_bam_addr")))
4751 bam_memres = &pdev->resource[i];
4752 else
4753 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004754
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304755 }
4756 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4757 if (!strncmp(pdev->resource[i].name,
4758 "sdcc_bam_irq",
4759 sizeof("sdcc_bam_irq")))
4760 bam_irqres = &pdev->resource[i];
4761 else
4762 core_irqres = &pdev->resource[i];
4763 }
4764 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4765 if (!strncmp(pdev->resource[i].name,
4766 "sdcc_dma_chnl",
4767 sizeof("sdcc_dma_chnl")))
4768 dmares = &pdev->resource[i];
4769 else if (!strncmp(pdev->resource[i].name,
4770 "sdcc_dma_crci",
4771 sizeof("sdcc_dma_crci")))
4772 dma_crci_res = &pdev->resource[i];
4773 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004774 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 }
4776
4777 if (!core_irqres || !core_memres) {
4778 pr_err("%s: Invalid sdcc core resource\n", __func__);
4779 return -ENXIO;
4780 }
4781
4782 /*
4783 * Both BAM and DML memory resource should be preset.
4784 * BAM IRQ resource should also be present.
4785 */
4786 if ((bam_memres && !dml_memres) ||
4787 (!bam_memres && dml_memres) ||
4788 ((bam_memres && dml_memres) && !bam_irqres)) {
4789 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004790 return -ENXIO;
4791 }
4792
4793 /*
4794 * Setup our host structure
4795 */
San Mehat9d2bd732009-09-22 16:44:22 -07004796 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4797 if (!mmc) {
4798 ret = -ENOMEM;
4799 goto out;
4800 }
4801
4802 host = mmc_priv(mmc);
4803 host->pdev_id = pdev->id;
4804 host->plat = plat;
4805 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004806 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304807
4808 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004809 host->is_sps_mode = 1;
4810 else if (dmares)
4811 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004813 host->base = ioremap(core_memres->start,
4814 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004815 if (!host->base) {
4816 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004817 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004818 }
4819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004820 host->core_irqres = core_irqres;
4821 host->bam_irqres = bam_irqres;
4822 host->core_memres = core_memres;
4823 host->dml_memres = dml_memres;
4824 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004825 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004826 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004827 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304828 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004830#ifdef CONFIG_MMC_EMBEDDED_SDIO
4831 if (plat->embedded_sdio)
4832 mmc_set_embedded_sdio_data(mmc,
4833 &plat->embedded_sdio->cis,
4834 &plat->embedded_sdio->cccr,
4835 plat->embedded_sdio->funcs,
4836 plat->embedded_sdio->num_funcs);
4837#endif
4838
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304839 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4840 (unsigned long)host);
4841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004842 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4843 (unsigned long)host);
4844 if (host->is_dma_mode) {
4845 /* Setup DMA */
4846 ret = msmsdcc_init_dma(host);
4847 if (ret)
4848 goto ioremap_free;
4849 } else {
4850 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004851 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004852 }
4853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004854 /*
4855 * Setup SDCC clock if derived from Dayatona
4856 * fabric core clock.
4857 */
4858 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004859 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004860 if (!IS_ERR(host->dfab_pclk)) {
4861 /* Set the clock rate to 64MHz for max. performance */
4862 ret = clk_set_rate(host->dfab_pclk, 64000000);
4863 if (ret)
4864 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304865 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 if (ret)
4867 goto dfab_pclk_put;
4868 } else
4869 goto dma_free;
4870 }
4871
4872 /*
4873 * Setup main peripheral bus clock
4874 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004875 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004876 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304877 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004878 if (ret)
4879 goto pclk_put;
4880
4881 host->pclk_rate = clk_get_rate(host->pclk);
4882 }
4883
4884 /*
4885 * Setup SDC MMC clock
4886 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004887 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004888 if (IS_ERR(host->clk)) {
4889 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004890 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004891 }
4892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004893 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4894 if (ret) {
4895 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4896 goto clk_put;
4897 }
4898
Asutosh Dasf5298c32012-04-03 14:51:47 +05304899 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004900 if (ret)
4901 goto clk_put;
4902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004903 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304904 if (!host->clk_rate)
4905 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304906
4907 /*
4908 * Lookup the Controller Version, to identify the supported features
4909 * Version number read as 0 would indicate SDCC3 or earlier versions
4910 */
4911 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4912 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4913 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304914 /*
4915 * Set the register write delay according to min. clock frequency
4916 * supported and update later when the host->clk_rate changes.
4917 */
4918 host->reg_write_delay =
4919 (1 + ((3 * USEC_PER_SEC) /
4920 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004921
4922 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304923 /* Apply Hard reset to SDCC to put it in power on default state */
4924 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004925
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004926#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304927 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004928 if (host->plat->cpu_dma_latency)
4929 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4930 else
4931 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4932 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304933 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4934
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304935 ret = msmsdcc_msm_bus_register(host);
4936 if (ret)
4937 goto pm_qos_remove;
4938
4939 if (host->msm_bus_vote.client_handle)
4940 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4941 msmsdcc_msm_bus_work);
4942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004943 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004944 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004946 goto clk_disable;
4947 }
4948
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949
4950 /* Clocks has to be running before accessing SPS/DML HW blocks */
4951 if (host->is_sps_mode) {
4952 /* Initialize SPS */
4953 ret = msmsdcc_sps_init(host);
4954 if (ret)
4955 goto vreg_deinit;
4956 /* Initialize DML */
4957 ret = msmsdcc_dml_init(host);
4958 if (ret)
4959 goto sps_exit;
4960 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304961 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004962
San Mehat9d2bd732009-09-22 16:44:22 -07004963 /*
4964 * Setup MMC host structure
4965 */
4966 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004967 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4968 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004969 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4971 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004972
San Mehat9d2bd732009-09-22 16:44:22 -07004973 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304974 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304975
4976 /*
4977 * If we send the CMD23 before multi block write/read command
4978 * then we need not to send CMD12 at the end of the transfer.
4979 * If we don't send the CMD12 then only way to detect the PROG_DONE
4980 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4981 * controller. So let's enable the CMD23 for SDCC4 only.
4982 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304983 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304984 mmc->caps |= MMC_CAP_CMD23;
4985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004986 mmc->caps |= plat->uhs_caps;
4987 /*
4988 * XPC controls the maximum current in the default speed mode of SDXC
4989 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4990 * XPC=1 means 150mA (max.) and speed class is supported.
4991 */
4992 if (plat->xpc_cap)
4993 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4994 MMC_CAP_SET_XPC_180);
4995
Maya Erez25e22612012-05-20 08:45:01 +03004996 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03004997 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304998 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03004999 mmc->caps2 |= MMC_CAP2_SANITIZE;
5000
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05305001 if (pdev->dev.of_node) {
5002 if (of_get_property((&pdev->dev)->of_node,
5003 "qcom,sdcc-hs200", NULL))
5004 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5005 }
5006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005007 if (plat->nonremovable)
5008 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005009 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005010
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005011 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005013 if (plat->is_sdio_al_client)
5014 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005015
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305016 mmc->max_segs = msmsdcc_get_nr_sg(host);
5017 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5018 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005019
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305020 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05305021 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07005022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005023 writel_relaxed(0, host->base + MMCIMASK0);
5024 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305025 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005027 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5028 mb();
5029 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005031 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5032 DRIVER_NAME " (cmd)", host);
5033 if (ret)
5034 goto dml_exit;
5035
5036 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5037 DRIVER_NAME " (pio)", host);
5038 if (ret)
5039 goto irq_free;
5040
5041 /*
5042 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5043 * IRQ is un-necessarily being monitored by MPM (Modem power
5044 * management block) during idle-power collapse. The MPM will be
5045 * configured to monitor the DATA1 GPIO line with level-low trigger
5046 * and thus depending on the GPIO status, it prevents TCXO shutdown
5047 * during idle-power collapse.
5048 */
5049 disable_irq(core_irqres->start);
5050 host->sdcc_irq_disabled = 1;
5051
5052 if (plat->sdiowakeup_irq) {
5053 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5054 mmc_hostname(mmc));
5055 ret = request_irq(plat->sdiowakeup_irq,
5056 msmsdcc_platform_sdiowakeup_irq,
5057 IRQF_SHARED | IRQF_TRIGGER_LOW,
5058 DRIVER_NAME "sdiowakeup", host);
5059 if (ret) {
5060 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5061 plat->sdiowakeup_irq, ret);
5062 goto pio_irq_free;
5063 } else {
5064 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305065 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005066 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305067 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005068 }
5069 spin_unlock_irqrestore(&host->lock, flags);
5070 }
5071 }
5072
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305073 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5075 mmc_hostname(mmc));
5076 }
5077
5078 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5079 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005080 /*
5081 * Setup card detect change
5082 */
5083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005084 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005085 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005087 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08005089
Krishna Konda941604a2012-01-10 17:46:34 -08005090 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005091 }
San Mehat9d2bd732009-09-22 16:44:22 -07005092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005093 if (plat->status_irq) {
5094 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005095 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005096 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005097 DRIVER_NAME " (slot)",
5098 host);
5099 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005100 pr_err("Unable to get slot IRQ %d (%d)\n",
5101 plat->status_irq, ret);
5102 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005103 }
5104 } else if (plat->register_status_notify) {
5105 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5106 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005107 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005108 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005109
5110 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005111
5112 ret = pm_runtime_set_active(&(pdev)->dev);
5113 if (ret < 0)
5114 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5115 __func__, ret);
5116 /*
5117 * There is no notion of suspend/resume for SD/MMC/SDIO
5118 * cards. So host can be suspended/resumed with out
5119 * worrying about its children.
5120 */
5121 pm_suspend_ignore_children(&(pdev)->dev, true);
5122
5123 /*
5124 * MMC/SD/SDIO bus suspend/resume operations are defined
5125 * only for the slots that will be used for non-removable
5126 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5127 * defined. Otherwise, they simply become card removal and
5128 * insertion events during suspend and resume respectively.
5129 * Hence, enable run-time PM only for slots for which bus
5130 * suspend/resume operations are defined.
5131 */
5132#ifdef CONFIG_MMC_UNSAFE_RESUME
5133 /*
5134 * If this capability is set, MMC core will enable/disable host
5135 * for every claim/release operation on a host. We use this
5136 * notification to increment/decrement runtime pm usage count.
5137 */
5138 mmc->caps |= MMC_CAP_DISABLE;
5139 pm_runtime_enable(&(pdev)->dev);
5140#else
5141 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
5142 mmc->caps |= MMC_CAP_DISABLE;
5143 pm_runtime_enable(&(pdev)->dev);
5144 }
5145#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05305146#ifndef CONFIG_PM_RUNTIME
5147 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
5148#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005149 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5150 (unsigned long)host);
5151
San Mehat9d2bd732009-09-22 16:44:22 -07005152 mmc_add_host(mmc);
5153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005154#ifdef CONFIG_HAS_EARLYSUSPEND
5155 host->early_suspend.suspend = msmsdcc_early_suspend;
5156 host->early_suspend.resume = msmsdcc_late_resume;
5157 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5158 register_early_suspend(&host->early_suspend);
5159#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005160
Krishna Konda25786ec2011-07-25 16:21:36 -07005161 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5162 " dmacrcri %d\n", mmc_hostname(mmc),
5163 (unsigned long long)core_memres->start,
5164 (unsigned int) core_irqres->start,
5165 (unsigned int) plat->status_irq, host->dma.channel,
5166 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005167
5168 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5169 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5170 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5171 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5172 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5173 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5174 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5175 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5176 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5177 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5178 host->eject);
5179 pr_info("%s: Power save feature enable = %d\n",
5180 mmc_hostname(mmc), msmsdcc_pwrsave);
5181
Krishna Konda25786ec2011-07-25 16:21:36 -07005182 if (host->is_dma_mode && host->dma.channel != -1
5183 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005184 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005185 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005186 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005187 mmc_hostname(mmc), host->dma.cmd_busaddr,
5188 host->dma.cmdptr_busaddr);
5189 } else if (host->is_sps_mode) {
5190 pr_info("%s: SPS-BAM data transfer mode available\n",
5191 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005192 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005193 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005195#if defined(CONFIG_DEBUG_FS)
5196 msmsdcc_dbg_createhost(host);
5197#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305198
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305199 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5200 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5201 sysfs_attr_init(&host->max_bus_bw.attr);
5202 host->max_bus_bw.attr.name = "max_bus_bw";
5203 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5204 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305205 if (ret)
5206 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305207
5208 if (!plat->status_irq) {
5209 host->polling.show = show_polling;
5210 host->polling.store = store_polling;
5211 sysfs_attr_init(&host->polling.attr);
5212 host->polling.attr.name = "polling";
5213 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5214 ret = device_create_file(&pdev->dev, &host->polling);
5215 if (ret)
5216 goto remove_max_bus_bw_file;
5217 }
San Mehat9d2bd732009-09-22 16:44:22 -07005218 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005219
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305220 remove_max_bus_bw_file:
5221 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005222 platform_irq_free:
5223 del_timer_sync(&host->req_tout_timer);
5224 pm_runtime_disable(&(pdev)->dev);
5225 pm_runtime_set_suspended(&(pdev)->dev);
5226
5227 if (plat->status_irq)
5228 free_irq(plat->status_irq, host);
5229 sdiowakeup_irq_free:
5230 wake_lock_destroy(&host->sdio_suspend_wlock);
5231 if (plat->sdiowakeup_irq)
5232 free_irq(plat->sdiowakeup_irq, host);
5233 pio_irq_free:
5234 if (plat->sdiowakeup_irq)
5235 wake_lock_destroy(&host->sdio_wlock);
5236 free_irq(core_irqres->start, host);
5237 irq_free:
5238 free_irq(core_irqres->start, host);
5239 dml_exit:
5240 if (host->is_sps_mode)
5241 msmsdcc_dml_exit(host);
5242 sps_exit:
5243 if (host->is_sps_mode)
5244 msmsdcc_sps_exit(host);
5245 vreg_deinit:
5246 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005247 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005248 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305249 msmsdcc_msm_bus_unregister(host);
5250 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005251 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305252 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005253 clk_put:
5254 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005255 pclk_disable:
5256 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305257 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005258 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005259 if (!IS_ERR(host->pclk))
5260 clk_put(host->pclk);
5261 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305262 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005263 dfab_pclk_put:
5264 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5265 clk_put(host->dfab_pclk);
5266 dma_free:
5267 if (host->is_dma_mode) {
5268 if (host->dmares)
5269 dma_free_coherent(NULL,
5270 sizeof(struct msmsdcc_nc_dmadata),
5271 host->dma.nc, host->dma.nc_busaddr);
5272 }
5273 ioremap_free:
5274 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005275 host_free:
5276 mmc_free_host(mmc);
5277 out:
5278 return ret;
5279}
5280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005281static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005282{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005283 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5284 struct mmc_platform_data *plat;
5285 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005287 if (!mmc)
5288 return -ENXIO;
5289
5290 if (pm_runtime_suspended(&(pdev)->dev))
5291 pm_runtime_resume(&(pdev)->dev);
5292
5293 host = mmc_priv(mmc);
5294
5295 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5296 plat = host->plat;
5297
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305298 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005299 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305300 device_remove_file(&pdev->dev, &host->polling);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005301
5302 del_timer_sync(&host->req_tout_timer);
5303 tasklet_kill(&host->dma_tlet);
5304 tasklet_kill(&host->sps.tlet);
5305 mmc_remove_host(mmc);
5306
5307 if (plat->status_irq)
5308 free_irq(plat->status_irq, host);
5309
5310 wake_lock_destroy(&host->sdio_suspend_wlock);
5311 if (plat->sdiowakeup_irq) {
5312 wake_lock_destroy(&host->sdio_wlock);
5313 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5314 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005315 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005316
5317 free_irq(host->core_irqres->start, host);
5318 free_irq(host->core_irqres->start, host);
5319
5320 clk_put(host->clk);
5321 if (!IS_ERR(host->pclk))
5322 clk_put(host->pclk);
5323 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5324 clk_put(host->dfab_pclk);
5325
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005326 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305327 pm_qos_remove_request(&host->pm_qos_req_dma);
5328
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305329 if (host->msm_bus_vote.client_handle) {
5330 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5331 msmsdcc_msm_bus_unregister(host);
5332 }
5333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005334 msmsdcc_vreg_init(host, false);
5335
5336 if (host->is_dma_mode) {
5337 if (host->dmares)
5338 dma_free_coherent(NULL,
5339 sizeof(struct msmsdcc_nc_dmadata),
5340 host->dma.nc, host->dma.nc_busaddr);
5341 }
5342
5343 if (host->is_sps_mode) {
5344 msmsdcc_dml_exit(host);
5345 msmsdcc_sps_exit(host);
5346 }
5347
5348 iounmap(host->base);
5349 mmc_free_host(mmc);
5350
5351#ifdef CONFIG_HAS_EARLYSUSPEND
5352 unregister_early_suspend(&host->early_suspend);
5353#endif
5354 pm_runtime_disable(&(pdev)->dev);
5355 pm_runtime_set_suspended(&(pdev)->dev);
5356
5357 return 0;
5358}
5359
5360#ifdef CONFIG_MSM_SDIO_AL
5361int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5362{
5363 struct msmsdcc_host *host = mmc_priv(mmc);
5364 unsigned long flags;
5365
Asutosh Dasf5298c32012-04-03 14:51:47 +05305366 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005367 spin_lock_irqsave(&host->lock, flags);
5368 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5369 enable ? "En" : "Dis");
5370
5371 if (enable) {
5372 if (!host->sdcc_irq_disabled) {
5373 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305374 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005375 host->sdcc_irq_disabled = 1;
5376 }
5377
5378 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305379 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005380 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305381 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005382 host->clks_on = 0;
5383 }
5384
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305385 if (host->plat->sdio_lpm_gpio_setup &&
5386 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005387 spin_unlock_irqrestore(&host->lock, flags);
5388 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5389 spin_lock_irqsave(&host->lock, flags);
5390 host->sdio_gpio_lpm = 1;
5391 }
5392
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305393 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005394 msmsdcc_enable_irq_wake(host);
5395 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305396 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005397 }
5398 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305399 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005400 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305401 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005402 msmsdcc_disable_irq_wake(host);
5403 }
5404
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305405 if (host->plat->sdio_lpm_gpio_setup &&
5406 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005407 spin_unlock_irqrestore(&host->lock, flags);
5408 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5409 spin_lock_irqsave(&host->lock, flags);
5410 host->sdio_gpio_lpm = 0;
5411 }
5412
5413 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305414 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005415 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305416 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005417 host->clks_on = 1;
5418 }
5419
5420 if (host->sdcc_irq_disabled) {
5421 writel_relaxed(host->mci_irqenable,
5422 host->base + MMCIMASK0);
5423 mb();
5424 enable_irq(host->core_irqres->start);
5425 host->sdcc_irq_disabled = 0;
5426 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005427 }
5428 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305429 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005430 return 0;
5431}
5432#else
5433int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5434{
5435 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005436}
5437#endif
5438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005439#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005440static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005441msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005442{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005443 struct mmc_host *mmc = dev_get_drvdata(dev);
5444 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005445 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305446 unsigned long flags;
5447
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305448 if (host->plat->is_sdio_al_client) {
5449 rc = 0;
5450 goto out;
5451 }
San Mehat9d2bd732009-09-22 16:44:22 -07005452
Sahitya Tummala7661a452011-07-18 13:28:35 +05305453 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005454 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005455 host->sdcc_suspending = 1;
5456 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005458 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005459 * MMC core thinks that host is disabled by now since
5460 * runtime suspend is scheduled after msmsdcc_disable()
5461 * is called. Thus, MMC core will try to enable the host
5462 * while suspending it. This results in a synchronous
5463 * runtime resume request while in runtime suspending
5464 * context and hence inorder to complete this resume
5465 * requet, it will wait for suspend to be complete,
5466 * but runtime suspend also can not proceed further
5467 * until the host is resumed. Thus, it leads to a hang.
5468 * Hence, increase the pm usage count before suspending
5469 * the host so that any resume requests after this will
5470 * simple become pm usage counter increment operations.
5471 */
5472 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305473 /* If there is pending detect work abort runtime suspend */
5474 if (unlikely(work_busy(&mmc->detect.work)))
5475 rc = -EAGAIN;
5476 else
5477 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005478 pm_runtime_put_noidle(dev);
5479
5480 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305481 spin_lock_irqsave(&host->lock, flags);
5482 host->sdcc_suspended = true;
5483 spin_unlock_irqrestore(&host->lock, flags);
5484 if (mmc->card && mmc_card_sdio(mmc->card) &&
5485 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005486 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305487 * If SDIO function driver doesn't want
5488 * to power off the card, atleast turn off
5489 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005490 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305491 mmc_host_clk_hold(mmc);
5492 spin_lock_irqsave(&mmc->clk_lock, flags);
5493 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005494 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305495 mmc->clk_gated = true;
5496 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5497 mmc_set_ios(mmc);
5498 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005499 }
5500 }
5501 host->sdcc_suspending = 0;
5502 mmc->suspend_task = NULL;
5503 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5504 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005505 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305506 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305507out:
5508 /* set bus bandwidth to 0 immediately */
5509 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005510 return rc;
5511}
5512
5513static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005514msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005515{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005516 struct mmc_host *mmc = dev_get_drvdata(dev);
5517 struct msmsdcc_host *host = mmc_priv(mmc);
5518 unsigned long flags;
5519
5520 if (host->plat->is_sdio_al_client)
5521 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005522
Sahitya Tummala7661a452011-07-18 13:28:35 +05305523 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005524 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305525 if (mmc->card && mmc_card_sdio(mmc->card) &&
5526 mmc_card_keep_power(mmc)) {
5527 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305528 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305529 mmc_set_ios(mmc);
5530 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305531 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005532
5533 mmc_resume_host(mmc);
5534
5535 /*
5536 * FIXME: Clearing of flags must be handled in clients
5537 * resume handler.
5538 */
5539 spin_lock_irqsave(&host->lock, flags);
5540 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305541 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005542 spin_unlock_irqrestore(&host->lock, flags);
5543
5544 /*
5545 * After resuming the host wait for sometime so that
5546 * the SDIO work will be processed.
5547 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305548 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305549 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005550 host->plat->sdiowakeup_irq) &&
5551 wake_lock_active(&host->sdio_wlock))
5552 wake_lock_timeout(&host->sdio_wlock, 1);
5553 }
5554
5555 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005556 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305557 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005558 return 0;
5559}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005560
5561static int msmsdcc_runtime_idle(struct device *dev)
5562{
5563 struct mmc_host *mmc = dev_get_drvdata(dev);
5564 struct msmsdcc_host *host = mmc_priv(mmc);
5565
5566 if (host->plat->is_sdio_al_client)
5567 return 0;
5568
5569 /* Idle timeout is not configurable for now */
5570 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5571
5572 return -EAGAIN;
5573}
5574
5575static int msmsdcc_pm_suspend(struct device *dev)
5576{
5577 struct mmc_host *mmc = dev_get_drvdata(dev);
5578 struct msmsdcc_host *host = mmc_priv(mmc);
5579 int rc = 0;
5580
5581 if (host->plat->is_sdio_al_client)
5582 return 0;
5583
5584
5585 if (host->plat->status_irq)
5586 disable_irq(host->plat->status_irq);
5587
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005588 if (!pm_runtime_suspended(dev))
5589 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005590
5591 return rc;
5592}
5593
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305594static int msmsdcc_suspend_noirq(struct device *dev)
5595{
5596 struct mmc_host *mmc = dev_get_drvdata(dev);
5597 struct msmsdcc_host *host = mmc_priv(mmc);
5598 int rc = 0;
5599
5600 /*
5601 * After platform suspend there may be active request
5602 * which might have enabled clocks. For example, in SDIO
5603 * case, ksdioirq thread might have scheduled after sdcc
5604 * suspend but before system freeze. In that case abort
5605 * suspend and retry instead of keeping the clocks on
5606 * during suspend and not allowing TCXO.
5607 */
5608
Asutosh Dasf5298c32012-04-03 14:51:47 +05305609 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305610 pr_warn("%s: clocks are on after suspend, aborting system "
5611 "suspend\n", mmc_hostname(mmc));
5612 rc = -EAGAIN;
5613 }
5614
5615 return rc;
5616}
5617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005618static int msmsdcc_pm_resume(struct device *dev)
5619{
5620 struct mmc_host *mmc = dev_get_drvdata(dev);
5621 struct msmsdcc_host *host = mmc_priv(mmc);
5622 int rc = 0;
5623
5624 if (host->plat->is_sdio_al_client)
5625 return 0;
5626
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005627 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305628 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005629 else
5630 host->pending_resume = true;
5631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005632 if (host->plat->status_irq) {
5633 msmsdcc_check_status((unsigned long)host);
5634 enable_irq(host->plat->status_irq);
5635 }
5636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005637 return rc;
5638}
5639
Daniel Walker08ecfde2010-06-23 12:32:20 -07005640#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005641static int msmsdcc_runtime_suspend(struct device *dev)
5642{
5643 return 0;
5644}
5645static int msmsdcc_runtime_idle(struct device *dev)
5646{
5647 return 0;
5648}
5649static int msmsdcc_pm_suspend(struct device *dev)
5650{
5651 return 0;
5652}
5653static int msmsdcc_pm_resume(struct device *dev)
5654{
5655 return 0;
5656}
5657static int msmsdcc_suspend_noirq(struct device *dev)
5658{
5659 return 0;
5660}
5661static int msmsdcc_runtime_resume(struct device *dev)
5662{
5663 return 0;
5664}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005665#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005667static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5668 .runtime_suspend = msmsdcc_runtime_suspend,
5669 .runtime_resume = msmsdcc_runtime_resume,
5670 .runtime_idle = msmsdcc_runtime_idle,
5671 .suspend = msmsdcc_pm_suspend,
5672 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305673 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005674};
5675
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305676static const struct of_device_id msmsdcc_dt_match[] = {
5677 {.compatible = "qcom,msm-sdcc"},
5678
5679};
5680MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5681
San Mehat9d2bd732009-09-22 16:44:22 -07005682static struct platform_driver msmsdcc_driver = {
5683 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005684 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005685 .driver = {
5686 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005687 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305688 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005689 },
5690};
5691
5692static int __init msmsdcc_init(void)
5693{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005694#if defined(CONFIG_DEBUG_FS)
5695 int ret = 0;
5696 ret = msmsdcc_dbg_init();
5697 if (ret) {
5698 pr_err("Failed to create debug fs dir \n");
5699 return ret;
5700 }
5701#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005702 return platform_driver_register(&msmsdcc_driver);
5703}
5704
5705static void __exit msmsdcc_exit(void)
5706{
5707 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005708
5709#if defined(CONFIG_DEBUG_FS)
5710 debugfs_remove(debugfs_file);
5711 debugfs_remove(debugfs_dir);
5712#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005713}
5714
5715module_init(msmsdcc_init);
5716module_exit(msmsdcc_exit);
5717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005718MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005719MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005720
5721#if defined(CONFIG_DEBUG_FS)
5722
5723static int
5724msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5725{
5726 file->private_data = inode->i_private;
5727 return 0;
5728}
5729
5730static ssize_t
5731msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5732 size_t count, loff_t *ppos)
5733{
5734 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005735 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005736 int max, i;
5737
5738 i = 0;
5739 max = sizeof(buf) - 1;
5740
5741 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5742 host->curr.cmd, host->curr.data);
5743 if (host->curr.cmd) {
5744 struct mmc_command *cmd = host->curr.cmd;
5745
5746 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5747 cmd->opcode, cmd->arg, cmd->flags);
5748 }
5749 if (host->curr.data) {
5750 struct mmc_data *data = host->curr.data;
5751 i += scnprintf(buf + i, max - i,
5752 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5753 data->timeout_ns, data->timeout_clks,
5754 data->blksz, data->blocks, data->error,
5755 data->flags);
5756 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5757 host->curr.xfer_size, host->curr.xfer_remain,
5758 host->curr.data_xfered, host->dma.sg);
5759 }
5760
5761 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5762}
5763
5764static const struct file_operations msmsdcc_dbg_state_ops = {
5765 .read = msmsdcc_dbg_state_read,
5766 .open = msmsdcc_dbg_state_open,
5767};
5768
5769static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5770{
5771 if (debugfs_dir) {
5772 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5773 0644, debugfs_dir, host,
5774 &msmsdcc_dbg_state_ops);
5775 }
5776}
5777
5778static int __init msmsdcc_dbg_init(void)
5779{
5780 int err;
5781
5782 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5783 if (IS_ERR(debugfs_dir)) {
5784 err = PTR_ERR(debugfs_dir);
5785 debugfs_dir = NULL;
5786 return err;
5787 }
5788
5789 return 0;
5790}
5791#endif