blob: 717f1d3970900b9ee3b720142a0e200431179f35 [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 Jadavani7a651aa2011-08-03 20:44:58 +0530379 host->curr.wait_for_auto_prog_done = 0;
380 host->curr.got_auto_prog_done = 0;
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 Jadavani7a651aa2011-08-03 20:44:58 +05301121 host->curr.got_auto_prog_done = 0;
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
1617 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 if (host->curr.data && host->dma.sg &&
1619 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001620 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 else if (host->curr.data && host->sps.sg &&
1622 host->is_sps_mode){
1623 /* Stop current SPS transfer */
1624 msmsdcc_sps_exit_curr_xfer(host);
1625 }
San Mehat9d2bd732009-09-22 16:44:22 -07001626 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301627 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001628 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301629 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301630 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301631 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301632 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301634 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301636 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301637 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301638 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301639 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001640 if (host->dummy_52_needed)
1641 host->dummy_52_needed = 0;
1642 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301644 msmsdcc_request_end(host, cmd->mrq);
1645 }
1646 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301647 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301648 if (cmd == host->curr.mrq->sbc)
1649 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1650 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1651 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301652 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001653 }
1654}
1655
San Mehat9d2bd732009-09-22 16:44:22 -07001656static irqreturn_t
1657msmsdcc_irq(int irq, void *dev_id)
1658{
1659 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001660 u32 status;
1661 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001663
1664 spin_lock(&host->lock);
1665
1666 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 struct mmc_command *cmd;
1668 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 if (timer) {
1671 timer = 0;
1672 msmsdcc_delay(host);
1673 }
San Mehat865c8062009-11-13 13:42:06 -08001674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 if (!host->clks_on) {
1676 pr_debug("%s: %s: SDIO async irq received\n",
1677 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301678
1679 /*
1680 * Only async interrupt can come when clocks are off,
1681 * disable further interrupts and enable them when
1682 * clocks are on.
1683 */
1684 if (!host->sdcc_irq_disabled) {
1685 disable_irq_nosync(irq);
1686 host->sdcc_irq_disabled = 1;
1687 }
1688
1689 /*
1690 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1691 * will take care of signaling sdio irq during
1692 * mmc_sdio_resume().
1693 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301694 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301695 /*
1696 * This is a wakeup interrupt so hold wakelock
1697 * until SDCC resume is handled.
1698 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301700 } else {
1701 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301702 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301703 spin_lock(&host->lock);
1704 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301705 ret = 1;
1706 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 }
1708
1709 status = readl_relaxed(host->base + MMCISTATUS);
1710
1711 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1712 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001713 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715#if IRQ_DEBUG
1716 msmsdcc_print_status(host, "irq0-r", status);
1717#endif
1718 status &= readl_relaxed(host->base + MMCIMASK0);
1719 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301720 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301721 if (host->clk_rate <=
1722 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301723 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724#if IRQ_DEBUG
1725 msmsdcc_print_status(host, "irq0-p", status);
1726#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 if (status & MCI_SDIOINTROPE) {
1729 if (host->sdcc_suspending)
1730 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301731 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301733 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001734 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001735 data = host->curr.data;
1736
1737 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1739 MCI_CMDTIMEOUT)) {
1740 if (status & MCI_CMDTIMEOUT)
1741 pr_debug("%s: dummy CMD52 timeout\n",
1742 mmc_hostname(host->mmc));
1743 if (status & MCI_CMDCRCFAIL)
1744 pr_debug("%s: dummy CMD52 CRC failed\n",
1745 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001746 host->dummy_52_sent = 0;
1747 host->dummy_52_needed = 0;
1748 if (data) {
1749 msmsdcc_stop_data(host);
1750 msmsdcc_request_end(host, data->mrq);
1751 }
1752 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 spin_unlock(&host->lock);
1754 return IRQ_HANDLED;
1755 }
1756 break;
1757 }
1758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 /*
1760 * Check for proper command response
1761 */
1762 cmd = host->curr.cmd;
1763 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1764 MCI_CMDTIMEOUT | MCI_PROGDONE |
1765 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1766 msmsdcc_do_cmdirq(host, status);
1767 }
1768
Sathish Ambley081d7842011-11-29 11:19:41 -08001769 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 /* Check for data errors */
1771 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1772 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1773 msmsdcc_data_err(host, data, status);
1774 host->curr.data_xfered = 0;
1775 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001776 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 else if (host->sps.sg && host->is_sps_mode) {
1778 /* Stop current SPS transfer */
1779 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301780 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 msmsdcc_reset_and_restore(host);
1782 if (host->curr.data)
1783 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301784 if (!data->stop || (host->curr.mrq->sbc
1785 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 timer |=
1787 msmsdcc_request_end(host,
1788 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301789 else if ((host->curr.mrq->sbc
1790 && data->error) ||
1791 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 msmsdcc_start_command(host,
1793 data->stop,
1794 0);
1795 timer = 1;
1796 }
1797 }
1798 }
1799
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301800 /* Check for prog done */
1801 if (host->curr.wait_for_auto_prog_done &&
1802 (status & MCI_PROGDONE))
1803 host->curr.got_auto_prog_done = 1;
1804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 /* Check for data done */
1806 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1807 host->curr.got_dataend = 1;
1808
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301809 if (host->curr.got_dataend &&
1810 (!host->curr.wait_for_auto_prog_done ||
1811 (host->curr.wait_for_auto_prog_done &&
1812 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 /*
1814 * If DMA is still in progress, we complete
1815 * via the completion handler
1816 */
1817 if (!host->dma.busy && !host->sps.busy) {
1818 /*
1819 * There appears to be an issue in the
1820 * controller where if you request a
1821 * small block transfer (< fifo size),
1822 * you may get your DATAEND/DATABLKEND
1823 * irq without the PIO data irq.
1824 *
1825 * Check to see if theres still data
1826 * to be read, and simulate a PIO irq.
1827 */
1828 if (data->flags & MMC_DATA_READ)
1829 msmsdcc_wait_for_rxdata(host,
1830 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 if (!data->error) {
1832 host->curr.data_xfered =
1833 host->curr.xfer_size;
1834 host->curr.xfer_remain -=
1835 host->curr.xfer_size;
1836 }
1837
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001838 if (!host->dummy_52_needed) {
1839 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301840 if (!data->stop ||
1841 (host->curr.mrq->sbc
1842 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001843 msmsdcc_request_end(
1844 host,
1845 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301846 else if ((host->curr.mrq->sbc
1847 && data->error) ||
1848 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001849 msmsdcc_start_command(
1850 host,
1851 data->stop, 0);
1852 timer = 1;
1853 }
1854 } else {
1855 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001857 &dummy52cmd,
1858 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 }
1860 }
1861 }
1862 }
1863
San Mehat9d2bd732009-09-22 16:44:22 -07001864 ret = 1;
1865 } while (status);
1866
1867 spin_unlock(&host->lock);
1868
San Mehat9d2bd732009-09-22 16:44:22 -07001869 return IRQ_RETVAL(ret);
1870}
1871
1872static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301873msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1874 bool is_first_request)
1875{
1876 struct msmsdcc_host *host = mmc_priv(mmc);
1877 struct mmc_data *data = mrq->data;
1878 int rc = 0;
1879
1880 if (unlikely(!data)) {
1881 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1882 __func__);
1883 return;
1884 }
1885 if (unlikely(data->host_cookie)) {
1886 /* Very wrong */
1887 data->host_cookie = 0;
1888 pr_err("%s: %s Request reposted for prepare\n",
1889 mmc_hostname(mmc), __func__);
1890 return;
1891 }
1892
1893 if (!msmsdcc_is_dma_possible(host, data))
1894 return;
1895
1896 rc = msmsdcc_prep_xfer(host, data);
1897 if (unlikely(rc < 0)) {
1898 data->host_cookie = 0;
1899 return;
1900 }
1901
1902 data->host_cookie = 1;
1903}
1904
1905static void
1906msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1907{
1908 struct msmsdcc_host *host = mmc_priv(mmc);
1909 unsigned int dir;
1910 struct mmc_data *data = mrq->data;
1911
1912 if (unlikely(!data)) {
1913 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1914 __func__);
1915 return;
1916 }
1917 if (data->flags & MMC_DATA_READ)
1918 dir = DMA_FROM_DEVICE;
1919 else
1920 dir = DMA_TO_DEVICE;
1921
1922 if (data->host_cookie)
1923 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1924 data->sg_len, dir);
1925
1926 data->host_cookie = 0;
1927}
1928
1929static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1931{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301932 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001933 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301934 if ((mrq->data->flags & MMC_DATA_READ) ||
1935 host->curr.use_wr_data_pend)
1936 msmsdcc_start_data(host, mrq->data,
1937 mrq->sbc ? mrq->sbc : mrq->cmd,
1938 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301939 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301940 msmsdcc_start_command(host,
1941 mrq->sbc ? mrq->sbc : mrq->cmd,
1942 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943 } else {
1944 msmsdcc_start_command(host, mrq->cmd, 0);
1945 }
1946}
1947
1948static void
San Mehat9d2bd732009-09-22 16:44:22 -07001949msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1950{
1951 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301952 unsigned long flags, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 /*
1955 * Get the SDIO AL client out of LPM.
1956 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001957 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 if (host->plat->is_sdio_al_client)
1959 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001960
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301961 /* check if sps pipe reset is pending? */
1962 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1963 msmsdcc_sps_pipes_reset_and_restore(host);
1964 host->sps.pipe_reset_pending = false;
1965 }
1966
San Mehat9d2bd732009-09-22 16:44:22 -07001967 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001968
1969 if (host->eject) {
1970 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1971 mrq->cmd->error = 0;
1972 mrq->data->bytes_xfered = mrq->data->blksz *
1973 mrq->data->blocks;
1974 } else
1975 mrq->cmd->error = -ENOMEDIUM;
1976
1977 spin_unlock_irqrestore(&host->lock, flags);
1978 mmc_request_done(mmc, mrq);
1979 return;
1980 }
1981
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301982 /*
subhashjf181c292012-05-02 13:07:40 +05301983 * Don't start the request if SDCC is not in proper state to handle it
1984 */
1985 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1986 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1987 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1988 __func__, mrq->cmd->opcode);
1989 msmsdcc_dump_sdcc_state(host);
1990 mrq->cmd->error = -EIO;
1991 if (mrq->data) {
1992 mrq->data->error = -EIO;
1993 mrq->data->bytes_xfered = 0;
1994 }
1995 spin_unlock_irqrestore(&host->lock, flags);
1996 mmc_request_done(mmc, mrq);
1997 return;
1998 }
1999
2000 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2001 " other request (CMD%d) is in progress\n",
2002 mmc_hostname(host->mmc), __func__,
2003 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2004
2005 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302006 * Set timeout value to 10 secs (or more in case of buggy cards)
2007 */
2008 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
2009 timeout = 20000;
2010 else
2011 timeout = MSM_MMC_REQ_TIMEOUT;
2012 /*
2013 * Kick the software request timeout timer here with the timeout
2014 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302015 */
2016 mod_timer(&host->req_tout_timer,
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302017 (jiffies + msecs_to_jiffies(timeout)));
San Mehat9d2bd732009-09-22 16:44:22 -07002018
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302019 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302020 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302021 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
2022 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05302023 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302025 else
2026 /*
2027 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
2028 * write operations using CMD53 and CMD54.
2029 * Setting this bit with CMD53 would
2030 * automatically triggers PROG_DONE interrupt
2031 * without the need of sending dummy CMD52.
2032 */
2033 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05302034 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
2035 host->sdcc_version) {
2036 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302038 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2039 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2040 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002041 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302042
Pratibhasagar V00b94332011-10-18 14:57:27 +05302043 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302044 mrq->sbc->mrq = mrq;
2045 mrq->sbc->data = mrq->data;
Subhash Jadavanif5277752011-10-12 16:47:52 +05302046 if (mrq->data->flags & MMC_DATA_WRITE)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302047 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19: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
4384set_polling(struct device *dev, struct device_attribute *attr,
4385 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
4408static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4409 show_polling, set_polling);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304410
4411static ssize_t
4412show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4413 char *buf)
4414{
4415 struct mmc_host *mmc = dev_get_drvdata(dev);
4416 struct msmsdcc_host *host = mmc_priv(mmc);
4417
4418 return snprintf(buf, PAGE_SIZE, "%u\n",
4419 host->msm_bus_vote.is_max_bw_needed);
4420}
4421
4422static ssize_t
4423set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4424 const char *buf, size_t count)
4425{
4426 struct mmc_host *mmc = dev_get_drvdata(dev);
4427 struct msmsdcc_host *host = mmc_priv(mmc);
4428 uint32_t value;
4429 unsigned long flags;
4430
4431 if (!kstrtou32(buf, 0, &value)) {
4432 spin_lock_irqsave(&host->lock, flags);
4433 host->msm_bus_vote.is_max_bw_needed = !!value;
4434 spin_unlock_irqrestore(&host->lock, flags);
4435 }
4436
4437 return count;
4438}
4439
4440static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
4441 show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
4442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004443static struct attribute *dev_attrs[] = {
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304444 &dev_attr_max_bus_bw.attr,
4445 /* if polling is enabled, this will be filled with dev_attr_polling */
4446 NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447 NULL,
4448};
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004450static struct attribute_group dev_attr_grp = {
4451 .attrs = dev_attrs,
4452};
4453
4454#ifdef CONFIG_HAS_EARLYSUSPEND
4455static void msmsdcc_early_suspend(struct early_suspend *h)
4456{
4457 struct msmsdcc_host *host =
4458 container_of(h, struct msmsdcc_host, early_suspend);
4459 unsigned long flags;
4460
4461 spin_lock_irqsave(&host->lock, flags);
4462 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4463 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4464 spin_unlock_irqrestore(&host->lock, flags);
4465};
4466static void msmsdcc_late_resume(struct early_suspend *h)
4467{
4468 struct msmsdcc_host *host =
4469 container_of(h, struct msmsdcc_host, early_suspend);
4470 unsigned long flags;
4471
4472 if (host->polling_enabled) {
4473 spin_lock_irqsave(&host->lock, flags);
4474 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4475 mmc_detect_change(host->mmc, 0);
4476 spin_unlock_irqrestore(&host->lock, flags);
4477 }
4478};
4479#endif
4480
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304481static void msmsdcc_print_regs(const char *name, void __iomem *base,
4482 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304483{
4484 unsigned int i;
4485
4486 if (!base)
4487 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304488
4489 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4490 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304491 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304492 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4493 (u32)readl_relaxed(base + i*4),
4494 (u32)readl_relaxed(base + ((i+1)*4)),
4495 (u32)readl_relaxed(base + ((i+2)*4)),
4496 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304497 }
4498}
4499
4500static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4501{
4502 /* Dump current state of SDCC clocks, power and irq */
4503 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304504 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304505 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304506 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4507 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304508 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4509 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4510
4511 /* Now dump SDCC registers. Don't print FIFO registers */
4512 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304513 msmsdcc_print_regs("SDCC-CORE", host->base,
4514 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304515
4516 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304517 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304518 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4519 else if (host->is_dma_mode)
4520 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4521 mmc_hostname(host->mmc), host->dma.busy,
4522 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304523 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304524 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304525 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4526 host->dml_memres->start,
4527 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304528 pr_info("%s: SPS mode: busy=%d\n",
4529 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304530 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304531
4532 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4533 mmc_hostname(host->mmc), host->curr.xfer_size,
4534 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304535 }
4536
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304537 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4538 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4539 mmc_hostname(host->mmc), host->curr.got_dataend,
4540 host->prog_enable, host->curr.wait_for_auto_prog_done,
4541 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304542 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304543}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4546{
4547 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4548 struct mmc_request *mrq;
4549 unsigned long flags;
4550
4551 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004552 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 pr_info("%s: %s: dummy CMD52 timeout\n",
4554 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004555 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004556 }
4557
4558 mrq = host->curr.mrq;
4559
4560 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304561 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4562 mrq->cmd->opcode);
4563 msmsdcc_dump_sdcc_state(host);
4564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004565 if (!mrq->cmd->error)
4566 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304567 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004568 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004569 if (mrq->data && !mrq->data->error)
4570 mrq->data->error = -ETIMEDOUT;
4571 host->curr.data_xfered = 0;
4572 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004573 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004574 } else if (host->sps.sg && host->is_sps_mode) {
4575 /* Stop current SPS transfer */
4576 msmsdcc_sps_exit_curr_xfer(host);
4577 } else {
4578 msmsdcc_reset_and_restore(host);
4579 msmsdcc_stop_data(host);
4580 if (mrq->data && mrq->data->stop)
4581 msmsdcc_start_command(host,
4582 mrq->data->stop, 0);
4583 else
4584 msmsdcc_request_end(host, mrq);
4585 }
4586 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304587 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304588 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 msmsdcc_reset_and_restore(host);
4590 msmsdcc_request_end(host, mrq);
4591 }
4592 }
4593 spin_unlock_irqrestore(&host->lock, flags);
4594}
4595
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304596static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4597{
4598 int i, ret;
4599 struct mmc_platform_data *pdata;
4600 struct device_node *np = dev->of_node;
4601 u32 bus_width = 0;
4602 u32 *clk_table;
4603 int clk_table_len;
4604 u32 *sup_voltages;
4605 int sup_volt_len;
4606
4607 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4608 if (!pdata) {
4609 dev_err(dev, "could not allocate memory for platform data\n");
4610 goto err;
4611 }
4612
4613 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4614 if (bus_width == 8) {
4615 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4616 } else if (bus_width == 4) {
4617 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4618 } else {
4619 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4620 pdata->mmc_bus_width = 0;
4621 }
4622
4623 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4624 size_t sz;
4625 sz = sup_volt_len / sizeof(*sup_voltages);
4626 if (sz > 0) {
4627 sup_voltages = devm_kzalloc(dev,
4628 sz * sizeof(*sup_voltages), GFP_KERNEL);
4629 if (!sup_voltages) {
4630 dev_err(dev, "No memory for supported voltage\n");
4631 goto err;
4632 }
4633
4634 ret = of_property_read_u32_array(np,
4635 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4636 if (ret < 0) {
4637 dev_err(dev, "error while reading voltage"
4638 "ranges %d\n", ret);
4639 goto err;
4640 }
4641 } else {
4642 dev_err(dev, "No supported voltages\n");
4643 goto err;
4644 }
4645 for (i = 0; i < sz; i += 2) {
4646 u32 mask;
4647
4648 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4649 sup_voltages[i + 1]);
4650 if (!mask)
4651 dev_err(dev, "Invalide voltage range %d\n", i);
4652 pdata->ocr_mask |= mask;
4653 }
4654 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4655 } else {
4656 dev_err(dev, "Supported voltage range not specified\n");
4657 }
4658
4659 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4660 size_t sz;
4661 sz = clk_table_len / sizeof(*clk_table);
4662
4663 if (sz > 0) {
4664 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4665 GFP_KERNEL);
4666 if (!clk_table) {
4667 dev_err(dev, "No memory for clock table\n");
4668 goto err;
4669 }
4670
4671 ret = of_property_read_u32_array(np,
4672 "qcom,sdcc-clk-rates", clk_table, sz);
4673 if (ret < 0) {
4674 dev_err(dev, "error while reading clk"
4675 "table %d\n", ret);
4676 goto err;
4677 }
4678 } else {
4679 dev_err(dev, "clk_table not specified\n");
4680 goto err;
4681 }
4682 pdata->sup_clk_table = clk_table;
4683 pdata->sup_clk_cnt = sz;
4684 } else {
4685 dev_err(dev, "Supported clock rates not specified\n");
4686 }
4687
4688 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4689 pdata->nonremovable = true;
4690 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4691 pdata->disable_cmd23 = true;
4692
4693 return pdata;
4694err:
4695 return NULL;
4696}
4697
San Mehat9d2bd732009-09-22 16:44:22 -07004698static int
4699msmsdcc_probe(struct platform_device *pdev)
4700{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304701 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004702 struct msmsdcc_host *host;
4703 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004704 unsigned long flags;
4705 struct resource *core_irqres = NULL;
4706 struct resource *bam_irqres = NULL;
4707 struct resource *core_memres = NULL;
4708 struct resource *dml_memres = NULL;
4709 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004710 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004711 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304712 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004714
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304715 if (pdev->dev.of_node) {
4716 plat = msmsdcc_populate_pdata(&pdev->dev);
4717 of_property_read_u32((&pdev->dev)->of_node,
4718 "cell-index", &pdev->id);
4719 } else {
4720 plat = pdev->dev.platform_data;
4721 }
4722
San Mehat9d2bd732009-09-22 16:44:22 -07004723 /* must have platform data */
4724 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004725 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004726 ret = -EINVAL;
4727 goto out;
4728 }
4729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004730 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004731 return -EINVAL;
4732
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304733 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4734 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4735 return -EINVAL;
4736 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737
San Mehat9d2bd732009-09-22 16:44:22 -07004738 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004739 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004740 return -ENXIO;
4741 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304742 if (pdev->dev.of_node) {
4743 /*
4744 * Device tree iomem resources are only accessible by index.
4745 * index = 0 -> SDCC register interface
4746 * index = 1 -> DML register interface
4747 * index = 2 -> BAM register interface
4748 * IRQ resources:
4749 * index = 0 -> SDCC IRQ
4750 * index = 1 -> BAM IRQ
4751 */
4752 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4753 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4754 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4755 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4756 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4757 } else {
4758 for (i = 0; i < pdev->num_resources; i++) {
4759 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4760 if (!strncmp(pdev->resource[i].name,
4761 "sdcc_dml_addr",
4762 sizeof("sdcc_dml_addr")))
4763 dml_memres = &pdev->resource[i];
4764 else if (!strncmp(pdev->resource[i].name,
4765 "sdcc_bam_addr",
4766 sizeof("sdcc_bam_addr")))
4767 bam_memres = &pdev->resource[i];
4768 else
4769 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004770
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304771 }
4772 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4773 if (!strncmp(pdev->resource[i].name,
4774 "sdcc_bam_irq",
4775 sizeof("sdcc_bam_irq")))
4776 bam_irqres = &pdev->resource[i];
4777 else
4778 core_irqres = &pdev->resource[i];
4779 }
4780 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4781 if (!strncmp(pdev->resource[i].name,
4782 "sdcc_dma_chnl",
4783 sizeof("sdcc_dma_chnl")))
4784 dmares = &pdev->resource[i];
4785 else if (!strncmp(pdev->resource[i].name,
4786 "sdcc_dma_crci",
4787 sizeof("sdcc_dma_crci")))
4788 dma_crci_res = &pdev->resource[i];
4789 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004790 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004791 }
4792
4793 if (!core_irqres || !core_memres) {
4794 pr_err("%s: Invalid sdcc core resource\n", __func__);
4795 return -ENXIO;
4796 }
4797
4798 /*
4799 * Both BAM and DML memory resource should be preset.
4800 * BAM IRQ resource should also be present.
4801 */
4802 if ((bam_memres && !dml_memres) ||
4803 (!bam_memres && dml_memres) ||
4804 ((bam_memres && dml_memres) && !bam_irqres)) {
4805 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004806 return -ENXIO;
4807 }
4808
4809 /*
4810 * Setup our host structure
4811 */
San Mehat9d2bd732009-09-22 16:44:22 -07004812 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4813 if (!mmc) {
4814 ret = -ENOMEM;
4815 goto out;
4816 }
4817
4818 host = mmc_priv(mmc);
4819 host->pdev_id = pdev->id;
4820 host->plat = plat;
4821 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004822 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304823
4824 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004825 host->is_sps_mode = 1;
4826 else if (dmares)
4827 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829 host->base = ioremap(core_memres->start,
4830 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004831 if (!host->base) {
4832 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004834 }
4835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004836 host->core_irqres = core_irqres;
4837 host->bam_irqres = bam_irqres;
4838 host->core_memres = core_memres;
4839 host->dml_memres = dml_memres;
4840 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004841 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004842 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004843 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304844 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846#ifdef CONFIG_MMC_EMBEDDED_SDIO
4847 if (plat->embedded_sdio)
4848 mmc_set_embedded_sdio_data(mmc,
4849 &plat->embedded_sdio->cis,
4850 &plat->embedded_sdio->cccr,
4851 plat->embedded_sdio->funcs,
4852 plat->embedded_sdio->num_funcs);
4853#endif
4854
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304855 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4856 (unsigned long)host);
4857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004858 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4859 (unsigned long)host);
4860 if (host->is_dma_mode) {
4861 /* Setup DMA */
4862 ret = msmsdcc_init_dma(host);
4863 if (ret)
4864 goto ioremap_free;
4865 } else {
4866 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004867 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004868 }
4869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 /*
4871 * Setup SDCC clock if derived from Dayatona
4872 * fabric core clock.
4873 */
4874 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004875 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004876 if (!IS_ERR(host->dfab_pclk)) {
4877 /* Set the clock rate to 64MHz for max. performance */
4878 ret = clk_set_rate(host->dfab_pclk, 64000000);
4879 if (ret)
4880 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304881 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004882 if (ret)
4883 goto dfab_pclk_put;
4884 } else
4885 goto dma_free;
4886 }
4887
4888 /*
4889 * Setup main peripheral bus clock
4890 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004891 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004892 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304893 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004894 if (ret)
4895 goto pclk_put;
4896
4897 host->pclk_rate = clk_get_rate(host->pclk);
4898 }
4899
4900 /*
4901 * Setup SDC MMC clock
4902 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004903 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004904 if (IS_ERR(host->clk)) {
4905 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004906 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004907 }
4908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004909 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4910 if (ret) {
4911 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4912 goto clk_put;
4913 }
4914
Asutosh Dasf5298c32012-04-03 14:51:47 +05304915 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004916 if (ret)
4917 goto clk_put;
4918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004919 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304920 if (!host->clk_rate)
4921 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304922
4923 /*
4924 * Lookup the Controller Version, to identify the supported features
4925 * Version number read as 0 would indicate SDCC3 or earlier versions
4926 */
4927 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4928 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4929 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304930 /*
4931 * Set the register write delay according to min. clock frequency
4932 * supported and update later when the host->clk_rate changes.
4933 */
4934 host->reg_write_delay =
4935 (1 + ((3 * USEC_PER_SEC) /
4936 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004937
4938 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304939 /* Apply Hard reset to SDCC to put it in power on default state */
4940 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004941
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004942#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304943 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004944 if (host->plat->cpu_dma_latency)
4945 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4946 else
4947 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4948 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304949 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4950
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304951 ret = msmsdcc_msm_bus_register(host);
4952 if (ret)
4953 goto pm_qos_remove;
4954
4955 if (host->msm_bus_vote.client_handle)
4956 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4957 msmsdcc_msm_bus_work);
4958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004959 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004960 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004961 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004962 goto clk_disable;
4963 }
4964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004965
4966 /* Clocks has to be running before accessing SPS/DML HW blocks */
4967 if (host->is_sps_mode) {
4968 /* Initialize SPS */
4969 ret = msmsdcc_sps_init(host);
4970 if (ret)
4971 goto vreg_deinit;
4972 /* Initialize DML */
4973 ret = msmsdcc_dml_init(host);
4974 if (ret)
4975 goto sps_exit;
4976 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304977 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004978
San Mehat9d2bd732009-09-22 16:44:22 -07004979 /*
4980 * Setup MMC host structure
4981 */
4982 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004983 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4984 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004985 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004986 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4987 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004988
San Mehat9d2bd732009-09-22 16:44:22 -07004989 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304990 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304991
4992 /*
4993 * If we send the CMD23 before multi block write/read command
4994 * then we need not to send CMD12 at the end of the transfer.
4995 * If we don't send the CMD12 then only way to detect the PROG_DONE
4996 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4997 * controller. So let's enable the CMD23 for SDCC4 only.
4998 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304999 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305000 mmc->caps |= MMC_CAP_CMD23;
5001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005002 mmc->caps |= plat->uhs_caps;
5003 /*
5004 * XPC controls the maximum current in the default speed mode of SDXC
5005 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5006 * XPC=1 means 150mA (max.) and speed class is supported.
5007 */
5008 if (plat->xpc_cap)
5009 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5010 MMC_CAP_SET_XPC_180);
5011
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305012 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05305013 if (pdev->dev.of_node) {
5014 if (of_get_property((&pdev->dev)->of_node,
5015 "qcom,sdcc-hs200", NULL))
5016 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5017 }
5018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005019 if (plat->nonremovable)
5020 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005021 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005022
5023 if (plat->is_sdio_al_client)
5024 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005025
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305026 mmc->max_segs = msmsdcc_get_nr_sg(host);
5027 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5028 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005029
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305030 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05305031 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07005032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 writel_relaxed(0, host->base + MMCIMASK0);
5034 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305035 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005037 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5038 mb();
5039 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005041 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5042 DRIVER_NAME " (cmd)", host);
5043 if (ret)
5044 goto dml_exit;
5045
5046 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5047 DRIVER_NAME " (pio)", host);
5048 if (ret)
5049 goto irq_free;
5050
5051 /*
5052 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5053 * IRQ is un-necessarily being monitored by MPM (Modem power
5054 * management block) during idle-power collapse. The MPM will be
5055 * configured to monitor the DATA1 GPIO line with level-low trigger
5056 * and thus depending on the GPIO status, it prevents TCXO shutdown
5057 * during idle-power collapse.
5058 */
5059 disable_irq(core_irqres->start);
5060 host->sdcc_irq_disabled = 1;
5061
5062 if (plat->sdiowakeup_irq) {
5063 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5064 mmc_hostname(mmc));
5065 ret = request_irq(plat->sdiowakeup_irq,
5066 msmsdcc_platform_sdiowakeup_irq,
5067 IRQF_SHARED | IRQF_TRIGGER_LOW,
5068 DRIVER_NAME "sdiowakeup", host);
5069 if (ret) {
5070 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5071 plat->sdiowakeup_irq, ret);
5072 goto pio_irq_free;
5073 } else {
5074 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305075 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005076 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305077 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005078 }
5079 spin_unlock_irqrestore(&host->lock, flags);
5080 }
5081 }
5082
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305083 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005084 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5085 mmc_hostname(mmc));
5086 }
5087
5088 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5089 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005090 /*
5091 * Setup card detect change
5092 */
5093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005094 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005095 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005096 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005097 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005098 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08005099
Krishna Konda941604a2012-01-10 17:46:34 -08005100 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005101 }
San Mehat9d2bd732009-09-22 16:44:22 -07005102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005103 if (plat->status_irq) {
5104 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005105 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005106 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005107 DRIVER_NAME " (slot)",
5108 host);
5109 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005110 pr_err("Unable to get slot IRQ %d (%d)\n",
5111 plat->status_irq, ret);
5112 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005113 }
5114 } else if (plat->register_status_notify) {
5115 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5116 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005117 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005118 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005119
5120 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005121
5122 ret = pm_runtime_set_active(&(pdev)->dev);
5123 if (ret < 0)
5124 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5125 __func__, ret);
5126 /*
5127 * There is no notion of suspend/resume for SD/MMC/SDIO
5128 * cards. So host can be suspended/resumed with out
5129 * worrying about its children.
5130 */
5131 pm_suspend_ignore_children(&(pdev)->dev, true);
5132
5133 /*
5134 * MMC/SD/SDIO bus suspend/resume operations are defined
5135 * only for the slots that will be used for non-removable
5136 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5137 * defined. Otherwise, they simply become card removal and
5138 * insertion events during suspend and resume respectively.
5139 * Hence, enable run-time PM only for slots for which bus
5140 * suspend/resume operations are defined.
5141 */
5142#ifdef CONFIG_MMC_UNSAFE_RESUME
5143 /*
5144 * If this capability is set, MMC core will enable/disable host
5145 * for every claim/release operation on a host. We use this
5146 * notification to increment/decrement runtime pm usage count.
5147 */
5148 mmc->caps |= MMC_CAP_DISABLE;
5149 pm_runtime_enable(&(pdev)->dev);
5150#else
5151 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
5152 mmc->caps |= MMC_CAP_DISABLE;
5153 pm_runtime_enable(&(pdev)->dev);
5154 }
5155#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05305156#ifndef CONFIG_PM_RUNTIME
5157 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
5158#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005159 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5160 (unsigned long)host);
5161
San Mehat9d2bd732009-09-22 16:44:22 -07005162 mmc_add_host(mmc);
5163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005164#ifdef CONFIG_HAS_EARLYSUSPEND
5165 host->early_suspend.suspend = msmsdcc_early_suspend;
5166 host->early_suspend.resume = msmsdcc_late_resume;
5167 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5168 register_early_suspend(&host->early_suspend);
5169#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005170
Krishna Konda25786ec2011-07-25 16:21:36 -07005171 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5172 " dmacrcri %d\n", mmc_hostname(mmc),
5173 (unsigned long long)core_memres->start,
5174 (unsigned int) core_irqres->start,
5175 (unsigned int) plat->status_irq, host->dma.channel,
5176 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005177
5178 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5179 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5180 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5181 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5182 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5183 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5184 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5185 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5186 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5187 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5188 host->eject);
5189 pr_info("%s: Power save feature enable = %d\n",
5190 mmc_hostname(mmc), msmsdcc_pwrsave);
5191
Krishna Konda25786ec2011-07-25 16:21:36 -07005192 if (host->is_dma_mode && host->dma.channel != -1
5193 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005194 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005195 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005196 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005197 mmc_hostname(mmc), host->dma.cmd_busaddr,
5198 host->dma.cmdptr_busaddr);
5199 } else if (host->is_sps_mode) {
5200 pr_info("%s: SPS-BAM data transfer mode available\n",
5201 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005202 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005203 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205#if defined(CONFIG_DEBUG_FS)
5206 msmsdcc_dbg_createhost(host);
5207#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305208 if (!plat->status_irq)
5209 dev_attrs[1] = &dev_attr_polling.attr;
5210
5211 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
5212 if (ret)
5213 goto platform_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005214 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005215
5216 platform_irq_free:
5217 del_timer_sync(&host->req_tout_timer);
5218 pm_runtime_disable(&(pdev)->dev);
5219 pm_runtime_set_suspended(&(pdev)->dev);
5220
5221 if (plat->status_irq)
5222 free_irq(plat->status_irq, host);
5223 sdiowakeup_irq_free:
5224 wake_lock_destroy(&host->sdio_suspend_wlock);
5225 if (plat->sdiowakeup_irq)
5226 free_irq(plat->sdiowakeup_irq, host);
5227 pio_irq_free:
5228 if (plat->sdiowakeup_irq)
5229 wake_lock_destroy(&host->sdio_wlock);
5230 free_irq(core_irqres->start, host);
5231 irq_free:
5232 free_irq(core_irqres->start, host);
5233 dml_exit:
5234 if (host->is_sps_mode)
5235 msmsdcc_dml_exit(host);
5236 sps_exit:
5237 if (host->is_sps_mode)
5238 msmsdcc_sps_exit(host);
5239 vreg_deinit:
5240 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005241 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005242 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305243 msmsdcc_msm_bus_unregister(host);
5244 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005245 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305246 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005247 clk_put:
5248 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005249 pclk_disable:
5250 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305251 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005252 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005253 if (!IS_ERR(host->pclk))
5254 clk_put(host->pclk);
5255 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305256 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005257 dfab_pclk_put:
5258 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5259 clk_put(host->dfab_pclk);
5260 dma_free:
5261 if (host->is_dma_mode) {
5262 if (host->dmares)
5263 dma_free_coherent(NULL,
5264 sizeof(struct msmsdcc_nc_dmadata),
5265 host->dma.nc, host->dma.nc_busaddr);
5266 }
5267 ioremap_free:
5268 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005269 host_free:
5270 mmc_free_host(mmc);
5271 out:
5272 return ret;
5273}
5274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005275static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005276{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005277 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5278 struct mmc_platform_data *plat;
5279 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005281 if (!mmc)
5282 return -ENXIO;
5283
5284 if (pm_runtime_suspended(&(pdev)->dev))
5285 pm_runtime_resume(&(pdev)->dev);
5286
5287 host = mmc_priv(mmc);
5288
5289 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5290 plat = host->plat;
5291
5292 if (!plat->status_irq)
5293 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
5294
5295 del_timer_sync(&host->req_tout_timer);
5296 tasklet_kill(&host->dma_tlet);
5297 tasklet_kill(&host->sps.tlet);
5298 mmc_remove_host(mmc);
5299
5300 if (plat->status_irq)
5301 free_irq(plat->status_irq, host);
5302
5303 wake_lock_destroy(&host->sdio_suspend_wlock);
5304 if (plat->sdiowakeup_irq) {
5305 wake_lock_destroy(&host->sdio_wlock);
5306 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5307 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005308 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005309
5310 free_irq(host->core_irqres->start, host);
5311 free_irq(host->core_irqres->start, host);
5312
5313 clk_put(host->clk);
5314 if (!IS_ERR(host->pclk))
5315 clk_put(host->pclk);
5316 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5317 clk_put(host->dfab_pclk);
5318
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005319 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305320 pm_qos_remove_request(&host->pm_qos_req_dma);
5321
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305322 if (host->msm_bus_vote.client_handle) {
5323 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5324 msmsdcc_msm_bus_unregister(host);
5325 }
5326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005327 msmsdcc_vreg_init(host, false);
5328
5329 if (host->is_dma_mode) {
5330 if (host->dmares)
5331 dma_free_coherent(NULL,
5332 sizeof(struct msmsdcc_nc_dmadata),
5333 host->dma.nc, host->dma.nc_busaddr);
5334 }
5335
5336 if (host->is_sps_mode) {
5337 msmsdcc_dml_exit(host);
5338 msmsdcc_sps_exit(host);
5339 }
5340
5341 iounmap(host->base);
5342 mmc_free_host(mmc);
5343
5344#ifdef CONFIG_HAS_EARLYSUSPEND
5345 unregister_early_suspend(&host->early_suspend);
5346#endif
5347 pm_runtime_disable(&(pdev)->dev);
5348 pm_runtime_set_suspended(&(pdev)->dev);
5349
5350 return 0;
5351}
5352
5353#ifdef CONFIG_MSM_SDIO_AL
5354int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5355{
5356 struct msmsdcc_host *host = mmc_priv(mmc);
5357 unsigned long flags;
5358
Asutosh Dasf5298c32012-04-03 14:51:47 +05305359 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005360 spin_lock_irqsave(&host->lock, flags);
5361 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5362 enable ? "En" : "Dis");
5363
5364 if (enable) {
5365 if (!host->sdcc_irq_disabled) {
5366 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305367 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005368 host->sdcc_irq_disabled = 1;
5369 }
5370
5371 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305372 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005373 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305374 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005375 host->clks_on = 0;
5376 }
5377
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305378 if (host->plat->sdio_lpm_gpio_setup &&
5379 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005380 spin_unlock_irqrestore(&host->lock, flags);
5381 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5382 spin_lock_irqsave(&host->lock, flags);
5383 host->sdio_gpio_lpm = 1;
5384 }
5385
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305386 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005387 msmsdcc_enable_irq_wake(host);
5388 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305389 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005390 }
5391 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305392 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005393 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305394 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005395 msmsdcc_disable_irq_wake(host);
5396 }
5397
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305398 if (host->plat->sdio_lpm_gpio_setup &&
5399 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005400 spin_unlock_irqrestore(&host->lock, flags);
5401 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5402 spin_lock_irqsave(&host->lock, flags);
5403 host->sdio_gpio_lpm = 0;
5404 }
5405
5406 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305407 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005408 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305409 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005410 host->clks_on = 1;
5411 }
5412
5413 if (host->sdcc_irq_disabled) {
5414 writel_relaxed(host->mci_irqenable,
5415 host->base + MMCIMASK0);
5416 mb();
5417 enable_irq(host->core_irqres->start);
5418 host->sdcc_irq_disabled = 0;
5419 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005420 }
5421 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305422 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005423 return 0;
5424}
5425#else
5426int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5427{
5428 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005429}
5430#endif
5431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005432#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005433static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005434msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005435{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005436 struct mmc_host *mmc = dev_get_drvdata(dev);
5437 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005438 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305439 unsigned long flags;
5440
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305441 if (host->plat->is_sdio_al_client) {
5442 rc = 0;
5443 goto out;
5444 }
San Mehat9d2bd732009-09-22 16:44:22 -07005445
Sahitya Tummala7661a452011-07-18 13:28:35 +05305446 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005447 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005448 host->sdcc_suspending = 1;
5449 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005451 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005452 * MMC core thinks that host is disabled by now since
5453 * runtime suspend is scheduled after msmsdcc_disable()
5454 * is called. Thus, MMC core will try to enable the host
5455 * while suspending it. This results in a synchronous
5456 * runtime resume request while in runtime suspending
5457 * context and hence inorder to complete this resume
5458 * requet, it will wait for suspend to be complete,
5459 * but runtime suspend also can not proceed further
5460 * until the host is resumed. Thus, it leads to a hang.
5461 * Hence, increase the pm usage count before suspending
5462 * the host so that any resume requests after this will
5463 * simple become pm usage counter increment operations.
5464 */
5465 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305466 /* If there is pending detect work abort runtime suspend */
5467 if (unlikely(work_busy(&mmc->detect.work)))
5468 rc = -EAGAIN;
5469 else
5470 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005471 pm_runtime_put_noidle(dev);
5472
5473 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305474 spin_lock_irqsave(&host->lock, flags);
5475 host->sdcc_suspended = true;
5476 spin_unlock_irqrestore(&host->lock, flags);
5477 if (mmc->card && mmc_card_sdio(mmc->card) &&
5478 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005479 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305480 * If SDIO function driver doesn't want
5481 * to power off the card, atleast turn off
5482 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005483 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305484 mmc_host_clk_hold(mmc);
5485 spin_lock_irqsave(&mmc->clk_lock, flags);
5486 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005487 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305488 mmc->clk_gated = true;
5489 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5490 mmc_set_ios(mmc);
5491 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005492 }
5493 }
5494 host->sdcc_suspending = 0;
5495 mmc->suspend_task = NULL;
5496 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5497 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005498 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305499 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305500out:
5501 /* set bus bandwidth to 0 immediately */
5502 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005503 return rc;
5504}
5505
5506static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005507msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005508{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005509 struct mmc_host *mmc = dev_get_drvdata(dev);
5510 struct msmsdcc_host *host = mmc_priv(mmc);
5511 unsigned long flags;
5512
5513 if (host->plat->is_sdio_al_client)
5514 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005515
Sahitya Tummala7661a452011-07-18 13:28:35 +05305516 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005517 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305518 if (mmc->card && mmc_card_sdio(mmc->card) &&
5519 mmc_card_keep_power(mmc)) {
5520 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305521 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305522 mmc_set_ios(mmc);
5523 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305524 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005525
5526 mmc_resume_host(mmc);
5527
5528 /*
5529 * FIXME: Clearing of flags must be handled in clients
5530 * resume handler.
5531 */
5532 spin_lock_irqsave(&host->lock, flags);
5533 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305534 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005535 spin_unlock_irqrestore(&host->lock, flags);
5536
5537 /*
5538 * After resuming the host wait for sometime so that
5539 * the SDIO work will be processed.
5540 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305541 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305542 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005543 host->plat->sdiowakeup_irq) &&
5544 wake_lock_active(&host->sdio_wlock))
5545 wake_lock_timeout(&host->sdio_wlock, 1);
5546 }
5547
5548 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005549 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305550 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005551 return 0;
5552}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005553
5554static int msmsdcc_runtime_idle(struct device *dev)
5555{
5556 struct mmc_host *mmc = dev_get_drvdata(dev);
5557 struct msmsdcc_host *host = mmc_priv(mmc);
5558
5559 if (host->plat->is_sdio_al_client)
5560 return 0;
5561
5562 /* Idle timeout is not configurable for now */
5563 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5564
5565 return -EAGAIN;
5566}
5567
5568static int msmsdcc_pm_suspend(struct device *dev)
5569{
5570 struct mmc_host *mmc = dev_get_drvdata(dev);
5571 struct msmsdcc_host *host = mmc_priv(mmc);
5572 int rc = 0;
5573
5574 if (host->plat->is_sdio_al_client)
5575 return 0;
5576
5577
5578 if (host->plat->status_irq)
5579 disable_irq(host->plat->status_irq);
5580
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005581 if (!pm_runtime_suspended(dev))
5582 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005583
5584 return rc;
5585}
5586
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305587static int msmsdcc_suspend_noirq(struct device *dev)
5588{
5589 struct mmc_host *mmc = dev_get_drvdata(dev);
5590 struct msmsdcc_host *host = mmc_priv(mmc);
5591 int rc = 0;
5592
5593 /*
5594 * After platform suspend there may be active request
5595 * which might have enabled clocks. For example, in SDIO
5596 * case, ksdioirq thread might have scheduled after sdcc
5597 * suspend but before system freeze. In that case abort
5598 * suspend and retry instead of keeping the clocks on
5599 * during suspend and not allowing TCXO.
5600 */
5601
Asutosh Dasf5298c32012-04-03 14:51:47 +05305602 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305603 pr_warn("%s: clocks are on after suspend, aborting system "
5604 "suspend\n", mmc_hostname(mmc));
5605 rc = -EAGAIN;
5606 }
5607
5608 return rc;
5609}
5610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611static int msmsdcc_pm_resume(struct device *dev)
5612{
5613 struct mmc_host *mmc = dev_get_drvdata(dev);
5614 struct msmsdcc_host *host = mmc_priv(mmc);
5615 int rc = 0;
5616
5617 if (host->plat->is_sdio_al_client)
5618 return 0;
5619
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005620 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305621 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005622 else
5623 host->pending_resume = true;
5624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005625 if (host->plat->status_irq) {
5626 msmsdcc_check_status((unsigned long)host);
5627 enable_irq(host->plat->status_irq);
5628 }
5629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005630 return rc;
5631}
5632
Daniel Walker08ecfde2010-06-23 12:32:20 -07005633#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005634static int msmsdcc_runtime_suspend(struct device *dev)
5635{
5636 return 0;
5637}
5638static int msmsdcc_runtime_idle(struct device *dev)
5639{
5640 return 0;
5641}
5642static int msmsdcc_pm_suspend(struct device *dev)
5643{
5644 return 0;
5645}
5646static int msmsdcc_pm_resume(struct device *dev)
5647{
5648 return 0;
5649}
5650static int msmsdcc_suspend_noirq(struct device *dev)
5651{
5652 return 0;
5653}
5654static int msmsdcc_runtime_resume(struct device *dev)
5655{
5656 return 0;
5657}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005658#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005660static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5661 .runtime_suspend = msmsdcc_runtime_suspend,
5662 .runtime_resume = msmsdcc_runtime_resume,
5663 .runtime_idle = msmsdcc_runtime_idle,
5664 .suspend = msmsdcc_pm_suspend,
5665 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305666 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005667};
5668
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305669static const struct of_device_id msmsdcc_dt_match[] = {
5670 {.compatible = "qcom,msm-sdcc"},
5671
5672};
5673MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5674
San Mehat9d2bd732009-09-22 16:44:22 -07005675static struct platform_driver msmsdcc_driver = {
5676 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005677 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005678 .driver = {
5679 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005680 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305681 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005682 },
5683};
5684
5685static int __init msmsdcc_init(void)
5686{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005687#if defined(CONFIG_DEBUG_FS)
5688 int ret = 0;
5689 ret = msmsdcc_dbg_init();
5690 if (ret) {
5691 pr_err("Failed to create debug fs dir \n");
5692 return ret;
5693 }
5694#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005695 return platform_driver_register(&msmsdcc_driver);
5696}
5697
5698static void __exit msmsdcc_exit(void)
5699{
5700 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005701
5702#if defined(CONFIG_DEBUG_FS)
5703 debugfs_remove(debugfs_file);
5704 debugfs_remove(debugfs_dir);
5705#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005706}
5707
5708module_init(msmsdcc_init);
5709module_exit(msmsdcc_exit);
5710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005711MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005712MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005713
5714#if defined(CONFIG_DEBUG_FS)
5715
5716static int
5717msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5718{
5719 file->private_data = inode->i_private;
5720 return 0;
5721}
5722
5723static ssize_t
5724msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5725 size_t count, loff_t *ppos)
5726{
5727 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005728 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005729 int max, i;
5730
5731 i = 0;
5732 max = sizeof(buf) - 1;
5733
5734 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5735 host->curr.cmd, host->curr.data);
5736 if (host->curr.cmd) {
5737 struct mmc_command *cmd = host->curr.cmd;
5738
5739 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5740 cmd->opcode, cmd->arg, cmd->flags);
5741 }
5742 if (host->curr.data) {
5743 struct mmc_data *data = host->curr.data;
5744 i += scnprintf(buf + i, max - i,
5745 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5746 data->timeout_ns, data->timeout_clks,
5747 data->blksz, data->blocks, data->error,
5748 data->flags);
5749 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5750 host->curr.xfer_size, host->curr.xfer_remain,
5751 host->curr.data_xfered, host->dma.sg);
5752 }
5753
5754 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5755}
5756
5757static const struct file_operations msmsdcc_dbg_state_ops = {
5758 .read = msmsdcc_dbg_state_read,
5759 .open = msmsdcc_dbg_state_open,
5760};
5761
5762static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5763{
5764 if (debugfs_dir) {
5765 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5766 0644, debugfs_dir, host,
5767 &msmsdcc_dbg_state_ops);
5768 }
5769}
5770
5771static int __init msmsdcc_dbg_init(void)
5772{
5773 int err;
5774
5775 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5776 if (IS_ERR(debugfs_dir)) {
5777 err = PTR_ERR(debugfs_dir);
5778 debugfs_dir = NULL;
5779 return err;
5780 }
5781
5782 return 0;
5783}
5784#endif