blob: e6405ab2db5030b2a7be9ae568017374d2238edb [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
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301617 if (!cmd->error) {
1618 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1619 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1620 mod_timer(&host->req_tout_timer, (jiffies +
1621 msecs_to_jiffies(host->curr.req_tout_ms)));
1622 }
1623 }
1624
San Mehat9d2bd732009-09-22 16:44:22 -07001625 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 if (host->curr.data && host->dma.sg &&
1627 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001628 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 else if (host->curr.data && host->sps.sg &&
1630 host->is_sps_mode){
1631 /* Stop current SPS transfer */
1632 msmsdcc_sps_exit_curr_xfer(host);
1633 }
San Mehat9d2bd732009-09-22 16:44:22 -07001634 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301635 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001636 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301637 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301638 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301639 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301640 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301642 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301644 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301645 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301646 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301647 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001648 if (host->dummy_52_needed)
1649 host->dummy_52_needed = 0;
1650 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301652 msmsdcc_request_end(host, cmd->mrq);
1653 }
1654 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301655 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301656 if (cmd == host->curr.mrq->sbc)
1657 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1658 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1659 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301660 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001661 }
1662}
1663
San Mehat9d2bd732009-09-22 16:44:22 -07001664static irqreturn_t
1665msmsdcc_irq(int irq, void *dev_id)
1666{
1667 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001668 u32 status;
1669 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001671
1672 spin_lock(&host->lock);
1673
1674 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 struct mmc_command *cmd;
1676 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 if (timer) {
1679 timer = 0;
1680 msmsdcc_delay(host);
1681 }
San Mehat865c8062009-11-13 13:42:06 -08001682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 if (!host->clks_on) {
1684 pr_debug("%s: %s: SDIO async irq received\n",
1685 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301686
1687 /*
1688 * Only async interrupt can come when clocks are off,
1689 * disable further interrupts and enable them when
1690 * clocks are on.
1691 */
1692 if (!host->sdcc_irq_disabled) {
1693 disable_irq_nosync(irq);
1694 host->sdcc_irq_disabled = 1;
1695 }
1696
1697 /*
1698 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1699 * will take care of signaling sdio irq during
1700 * mmc_sdio_resume().
1701 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301702 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301703 /*
1704 * This is a wakeup interrupt so hold wakelock
1705 * until SDCC resume is handled.
1706 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301708 } else {
1709 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301710 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301711 spin_lock(&host->lock);
1712 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301713 ret = 1;
1714 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715 }
1716
1717 status = readl_relaxed(host->base + MMCISTATUS);
1718
1719 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1720 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001721 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723#if IRQ_DEBUG
1724 msmsdcc_print_status(host, "irq0-r", status);
1725#endif
1726 status &= readl_relaxed(host->base + MMCIMASK0);
1727 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301728 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301729 if (host->clk_rate <=
1730 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301731 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732#if IRQ_DEBUG
1733 msmsdcc_print_status(host, "irq0-p", status);
1734#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 if (status & MCI_SDIOINTROPE) {
1737 if (host->sdcc_suspending)
1738 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301739 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301741 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001742 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001743 data = host->curr.data;
1744
1745 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1747 MCI_CMDTIMEOUT)) {
1748 if (status & MCI_CMDTIMEOUT)
1749 pr_debug("%s: dummy CMD52 timeout\n",
1750 mmc_hostname(host->mmc));
1751 if (status & MCI_CMDCRCFAIL)
1752 pr_debug("%s: dummy CMD52 CRC failed\n",
1753 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001754 host->dummy_52_sent = 0;
1755 host->dummy_52_needed = 0;
1756 if (data) {
1757 msmsdcc_stop_data(host);
1758 msmsdcc_request_end(host, data->mrq);
1759 }
1760 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 spin_unlock(&host->lock);
1762 return IRQ_HANDLED;
1763 }
1764 break;
1765 }
1766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 /*
1768 * Check for proper command response
1769 */
1770 cmd = host->curr.cmd;
1771 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1772 MCI_CMDTIMEOUT | MCI_PROGDONE |
1773 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1774 msmsdcc_do_cmdirq(host, status);
1775 }
1776
Sathish Ambley081d7842011-11-29 11:19:41 -08001777 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 /* Check for data errors */
1779 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1780 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1781 msmsdcc_data_err(host, data, status);
1782 host->curr.data_xfered = 0;
1783 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001784 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 else if (host->sps.sg && host->is_sps_mode) {
1786 /* Stop current SPS transfer */
1787 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301788 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 msmsdcc_reset_and_restore(host);
1790 if (host->curr.data)
1791 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301792 if (!data->stop || (host->curr.mrq->sbc
1793 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 timer |=
1795 msmsdcc_request_end(host,
1796 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301797 else if ((host->curr.mrq->sbc
1798 && data->error) ||
1799 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 msmsdcc_start_command(host,
1801 data->stop,
1802 0);
1803 timer = 1;
1804 }
1805 }
1806 }
1807
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301808 /* Check for prog done */
1809 if (host->curr.wait_for_auto_prog_done &&
1810 (status & MCI_PROGDONE))
1811 host->curr.got_auto_prog_done = 1;
1812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 /* Check for data done */
1814 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1815 host->curr.got_dataend = 1;
1816
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301817 if (host->curr.got_dataend &&
1818 (!host->curr.wait_for_auto_prog_done ||
1819 (host->curr.wait_for_auto_prog_done &&
1820 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 /*
1822 * If DMA is still in progress, we complete
1823 * via the completion handler
1824 */
1825 if (!host->dma.busy && !host->sps.busy) {
1826 /*
1827 * There appears to be an issue in the
1828 * controller where if you request a
1829 * small block transfer (< fifo size),
1830 * you may get your DATAEND/DATABLKEND
1831 * irq without the PIO data irq.
1832 *
1833 * Check to see if theres still data
1834 * to be read, and simulate a PIO irq.
1835 */
1836 if (data->flags & MMC_DATA_READ)
1837 msmsdcc_wait_for_rxdata(host,
1838 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 if (!data->error) {
1840 host->curr.data_xfered =
1841 host->curr.xfer_size;
1842 host->curr.xfer_remain -=
1843 host->curr.xfer_size;
1844 }
1845
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001846 if (!host->dummy_52_needed) {
1847 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301848 if (!data->stop ||
1849 (host->curr.mrq->sbc
1850 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001851 msmsdcc_request_end(
1852 host,
1853 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301854 else if ((host->curr.mrq->sbc
1855 && data->error) ||
1856 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001857 msmsdcc_start_command(
1858 host,
1859 data->stop, 0);
1860 timer = 1;
1861 }
1862 } else {
1863 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001865 &dummy52cmd,
1866 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 }
1868 }
1869 }
1870 }
1871
San Mehat9d2bd732009-09-22 16:44:22 -07001872 ret = 1;
1873 } while (status);
1874
1875 spin_unlock(&host->lock);
1876
San Mehat9d2bd732009-09-22 16:44:22 -07001877 return IRQ_RETVAL(ret);
1878}
1879
1880static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301881msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1882 bool is_first_request)
1883{
1884 struct msmsdcc_host *host = mmc_priv(mmc);
1885 struct mmc_data *data = mrq->data;
1886 int rc = 0;
1887
1888 if (unlikely(!data)) {
1889 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1890 __func__);
1891 return;
1892 }
1893 if (unlikely(data->host_cookie)) {
1894 /* Very wrong */
1895 data->host_cookie = 0;
1896 pr_err("%s: %s Request reposted for prepare\n",
1897 mmc_hostname(mmc), __func__);
1898 return;
1899 }
1900
1901 if (!msmsdcc_is_dma_possible(host, data))
1902 return;
1903
1904 rc = msmsdcc_prep_xfer(host, data);
1905 if (unlikely(rc < 0)) {
1906 data->host_cookie = 0;
1907 return;
1908 }
1909
1910 data->host_cookie = 1;
1911}
1912
1913static void
1914msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1915{
1916 struct msmsdcc_host *host = mmc_priv(mmc);
1917 unsigned int dir;
1918 struct mmc_data *data = mrq->data;
1919
1920 if (unlikely(!data)) {
1921 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1922 __func__);
1923 return;
1924 }
1925 if (data->flags & MMC_DATA_READ)
1926 dir = DMA_FROM_DEVICE;
1927 else
1928 dir = DMA_TO_DEVICE;
1929
1930 if (data->host_cookie)
1931 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1932 data->sg_len, dir);
1933
1934 data->host_cookie = 0;
1935}
1936
1937static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001938msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1939{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301940 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301942 if ((mrq->data->flags & MMC_DATA_READ) ||
1943 host->curr.use_wr_data_pend)
1944 msmsdcc_start_data(host, mrq->data,
1945 mrq->sbc ? mrq->sbc : mrq->cmd,
1946 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301947 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301948 msmsdcc_start_command(host,
1949 mrq->sbc ? mrq->sbc : mrq->cmd,
1950 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 } else {
1952 msmsdcc_start_command(host, mrq->cmd, 0);
1953 }
1954}
1955
1956static void
San Mehat9d2bd732009-09-22 16:44:22 -07001957msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1958{
1959 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301960 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 /*
1963 * Get the SDIO AL client out of LPM.
1964 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001965 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 if (host->plat->is_sdio_al_client)
1967 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001968
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301969 /* check if sps pipe reset is pending? */
1970 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1971 msmsdcc_sps_pipes_reset_and_restore(host);
1972 host->sps.pipe_reset_pending = false;
1973 }
1974
San Mehat9d2bd732009-09-22 16:44:22 -07001975 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001976
1977 if (host->eject) {
1978 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1979 mrq->cmd->error = 0;
1980 mrq->data->bytes_xfered = mrq->data->blksz *
1981 mrq->data->blocks;
1982 } else
1983 mrq->cmd->error = -ENOMEDIUM;
1984
1985 spin_unlock_irqrestore(&host->lock, flags);
1986 mmc_request_done(mmc, mrq);
1987 return;
1988 }
1989
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301990 /*
subhashjf181c292012-05-02 13:07:40 +05301991 * Don't start the request if SDCC is not in proper state to handle it
1992 */
1993 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1994 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1995 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1996 __func__, mrq->cmd->opcode);
1997 msmsdcc_dump_sdcc_state(host);
1998 mrq->cmd->error = -EIO;
1999 if (mrq->data) {
2000 mrq->data->error = -EIO;
2001 mrq->data->bytes_xfered = 0;
2002 }
2003 spin_unlock_irqrestore(&host->lock, flags);
2004 mmc_request_done(mmc, mrq);
2005 return;
2006 }
2007
2008 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2009 " other request (CMD%d) is in progress\n",
2010 mmc_hostname(host->mmc), __func__,
2011 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2012
2013 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302014 * Set timeout value to 10 secs (or more in case of buggy cards)
2015 */
2016 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302017 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302018 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302019 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302020 /*
2021 * Kick the software request timeout timer here with the timeout
2022 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302023 */
2024 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302025 (jiffies +
2026 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002027
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302028 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302029 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302030 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
2031 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05302032 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302034 else
2035 /*
2036 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
2037 * write operations using CMD53 and CMD54.
2038 * Setting this bit with CMD53 would
2039 * automatically triggers PROG_DONE interrupt
2040 * without the need of sending dummy CMD52.
2041 */
2042 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05302043 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
2044 host->sdcc_version) {
2045 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302047 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2048 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2049 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002050 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302051
Pratibhasagar V00b94332011-10-18 14:57:27 +05302052 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302053 mrq->sbc->mrq = mrq;
2054 mrq->sbc->data = mrq->data;
Subhash Jadavanif5277752011-10-12 16:47:52 +05302055 if (mrq->data->flags & MMC_DATA_WRITE)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302056 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302057 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302058 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302059
San Mehat9d2bd732009-09-22 16:44:22 -07002060 spin_unlock_irqrestore(&host->lock, flags);
2061}
2062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002063static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2064 int min_uV, int max_uV)
2065{
2066 int rc = 0;
2067
2068 if (vreg->set_voltage_sup) {
2069 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2070 if (rc) {
2071 pr_err("%s: regulator_set_voltage(%s) failed."
2072 " min_uV=%d, max_uV=%d, rc=%d\n",
2073 __func__, vreg->name, min_uV, max_uV, rc);
2074 }
2075 }
2076
2077 return rc;
2078}
2079
2080static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2081 int uA_load)
2082{
2083 int rc = 0;
2084
Krishna Kondafea60182011-11-01 16:01:34 -07002085 /* regulators that do not support regulator_set_voltage also
2086 do not support regulator_set_optimum_mode */
2087 if (vreg->set_voltage_sup) {
2088 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2089 if (rc < 0)
2090 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2091 "uA_load=%d) failed. rc=%d\n", __func__,
2092 vreg->name, uA_load, rc);
2093 else
2094 /* regulator_set_optimum_mode() can return non zero
2095 * value even for success case.
2096 */
2097 rc = 0;
2098 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099
2100 return rc;
2101}
2102
2103static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2104 struct device *dev)
2105{
2106 int rc = 0;
2107
2108 /* check if regulator is already initialized? */
2109 if (vreg->reg)
2110 goto out;
2111
2112 /* Get the regulator handle */
2113 vreg->reg = regulator_get(dev, vreg->name);
2114 if (IS_ERR(vreg->reg)) {
2115 rc = PTR_ERR(vreg->reg);
2116 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2117 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002118 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002120
2121 if (regulator_count_voltages(vreg->reg) > 0)
2122 vreg->set_voltage_sup = 1;
2123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124out:
2125 return rc;
2126}
2127
2128static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2129{
2130 if (vreg->reg)
2131 regulator_put(vreg->reg);
2132}
2133
2134/* This init function should be called only once for each SDCC slot */
2135static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2136{
2137 int rc = 0;
2138 struct msm_mmc_slot_reg_data *curr_slot;
2139 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2140 struct device *dev = mmc_dev(host->mmc);
2141
2142 curr_slot = host->plat->vreg_data;
2143 if (!curr_slot)
2144 goto out;
2145
2146 curr_vdd_reg = curr_slot->vdd_data;
2147 curr_vccq_reg = curr_slot->vccq_data;
2148 curr_vddp_reg = curr_slot->vddp_data;
2149
2150 if (is_init) {
2151 /*
2152 * Get the regulator handle from voltage regulator framework
2153 * and then try to set the voltage level for the regulator
2154 */
2155 if (curr_vdd_reg) {
2156 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2157 if (rc)
2158 goto out;
2159 }
2160 if (curr_vccq_reg) {
2161 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2162 if (rc)
2163 goto vdd_reg_deinit;
2164 }
2165 if (curr_vddp_reg) {
2166 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2167 if (rc)
2168 goto vccq_reg_deinit;
2169 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002170 rc = msmsdcc_vreg_reset(host);
2171 if (rc)
2172 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2173 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 goto out;
2175 } else {
2176 /* Deregister all regulators from regulator framework */
2177 goto vddp_reg_deinit;
2178 }
2179vddp_reg_deinit:
2180 if (curr_vddp_reg)
2181 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2182vccq_reg_deinit:
2183 if (curr_vccq_reg)
2184 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2185vdd_reg_deinit:
2186 if (curr_vdd_reg)
2187 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2188out:
2189 return rc;
2190}
2191
2192static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2193{
2194 int rc = 0;
2195
Subhash Jadavanicc922692011-08-01 23:05:01 +05302196 /* Put regulator in HPM (high power mode) */
2197 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2198 if (rc < 0)
2199 goto out;
2200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 if (!vreg->is_enabled) {
2202 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302203 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2204 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205 if (rc)
2206 goto out;
2207
2208 rc = regulator_enable(vreg->reg);
2209 if (rc) {
2210 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2211 __func__, vreg->name, rc);
2212 goto out;
2213 }
2214 vreg->is_enabled = true;
2215 }
2216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217out:
2218 return rc;
2219}
2220
2221static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2222{
2223 int rc = 0;
2224
2225 /* Never disable regulator marked as always_on */
2226 if (vreg->is_enabled && !vreg->always_on) {
2227 rc = regulator_disable(vreg->reg);
2228 if (rc) {
2229 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2230 __func__, vreg->name, rc);
2231 goto out;
2232 }
2233 vreg->is_enabled = false;
2234
2235 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2236 if (rc < 0)
2237 goto out;
2238
2239 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302240 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 if (rc)
2242 goto out;
2243 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2244 /* Put always_on regulator in LPM (low power mode) */
2245 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2246 if (rc < 0)
2247 goto out;
2248 }
2249out:
2250 return rc;
2251}
2252
2253static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2254{
2255 int rc = 0, i;
2256 struct msm_mmc_slot_reg_data *curr_slot;
2257 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2258 struct msm_mmc_reg_data *vreg_table[3];
2259
2260 curr_slot = host->plat->vreg_data;
2261 if (!curr_slot)
2262 goto out;
2263
2264 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2265 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2266 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2267
2268 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2269 if (vreg_table[i]) {
2270 if (enable)
2271 rc = msmsdcc_vreg_enable(vreg_table[i]);
2272 else
2273 rc = msmsdcc_vreg_disable(vreg_table[i]);
2274 if (rc)
2275 goto out;
2276 }
2277 }
2278out:
2279 return rc;
2280}
2281
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002282/*
2283 * Reset vreg by ensuring it is off during probe. A call
2284 * to enable vreg is needed to balance disable vreg
2285 */
2286static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2287{
2288 int rc;
2289
2290 rc = msmsdcc_setup_vreg(host, 1);
2291 if (rc)
2292 return rc;
2293 rc = msmsdcc_setup_vreg(host, 0);
2294 return rc;
2295}
2296
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302297static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298{
2299 int rc = 0;
2300
2301 if (host->plat->vreg_data) {
2302 struct msm_mmc_reg_data *vddp_reg =
2303 host->plat->vreg_data->vddp_data;
2304
2305 if (vddp_reg && vddp_reg->is_enabled)
2306 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2307 }
2308
2309 return rc;
2310}
2311
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302312static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2313{
2314 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2315 int rc = 0;
2316
2317 if (curr_slot && curr_slot->vddp_data) {
2318 rc = msmsdcc_set_vddp_level(host,
2319 curr_slot->vddp_data->low_vol_level);
2320
2321 if (rc)
2322 pr_err("%s: %s: failed to change vddp level to %d",
2323 mmc_hostname(host->mmc), __func__,
2324 curr_slot->vddp_data->low_vol_level);
2325 }
2326
2327 return rc;
2328}
2329
2330static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2331{
2332 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2333 int rc = 0;
2334
2335 if (curr_slot && curr_slot->vddp_data) {
2336 rc = msmsdcc_set_vddp_level(host,
2337 curr_slot->vddp_data->high_vol_level);
2338
2339 if (rc)
2340 pr_err("%s: %s: failed to change vddp level to %d",
2341 mmc_hostname(host->mmc), __func__,
2342 curr_slot->vddp_data->high_vol_level);
2343 }
2344
2345 return rc;
2346}
2347
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302348static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2349{
2350 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2351 int rc = 0;
2352
2353 if (curr_slot && curr_slot->vccq_data) {
2354 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2355 level, level);
2356 if (rc)
2357 pr_err("%s: %s: failed to change vccq level to %d",
2358 mmc_hostname(host->mmc), __func__, level);
2359 }
2360
2361 return rc;
2362}
2363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2365{
2366 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2367 return 1;
2368 return 0;
2369}
2370
Asutosh Dasf5298c32012-04-03 14:51:47 +05302371/*
2372 * Any function calling msmsdcc_setup_clocks must
2373 * acquire clk_mutex. May sleep.
2374 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2376{
2377 if (enable) {
2378 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302379 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302381 clk_prepare_enable(host->pclk);
2382 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302383 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302384 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302386 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302387 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302388 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002389 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302390 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302392 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 }
2394}
2395
2396static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2397 unsigned int req_clk)
2398{
2399 unsigned int sel_clk = -1;
2400
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302401 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2402 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2403 goto out;
2404 }
2405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002406 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2407 unsigned char cnt;
2408
2409 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2410 if (host->plat->sup_clk_table[cnt] > req_clk)
2411 break;
2412 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2413 sel_clk = host->plat->sup_clk_table[cnt];
2414 break;
2415 } else
2416 sel_clk = host->plat->sup_clk_table[cnt];
2417 }
2418 } else {
2419 if ((req_clk < host->plat->msmsdcc_fmax) &&
2420 (req_clk > host->plat->msmsdcc_fmid))
2421 sel_clk = host->plat->msmsdcc_fmid;
2422 else
2423 sel_clk = req_clk;
2424 }
2425
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302426out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427 return sel_clk;
2428}
2429
2430static inline unsigned int msmsdcc_get_min_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[0];
2435 else
2436 return host->plat->msmsdcc_fmin;
2437}
2438
2439static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2440 struct msmsdcc_host *host)
2441{
2442 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2443 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2444 else
2445 return host->plat->msmsdcc_fmax;
2446}
2447
2448static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302449{
2450 struct msm_mmc_gpio_data *curr;
2451 int i, rc = 0;
2452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302454 for (i = 0; i < curr->size; i++) {
2455 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 if (curr->gpio[i].is_always_on &&
2457 curr->gpio[i].is_enabled)
2458 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302459 rc = gpio_request(curr->gpio[i].no,
2460 curr->gpio[i].name);
2461 if (rc) {
2462 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2463 mmc_hostname(host->mmc),
2464 curr->gpio[i].no,
2465 curr->gpio[i].name, rc);
2466 goto free_gpios;
2467 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302469 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 if (curr->gpio[i].is_always_on)
2471 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302472 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302474 }
2475 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302477
2478free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302480 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481 curr->gpio[i].is_enabled = false;
2482 }
2483out:
2484 return rc;
2485}
2486
2487static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2488{
2489 struct msm_mmc_pad_data *curr;
2490 int i;
2491
2492 curr = host->plat->pin_data->pad_data;
2493 for (i = 0; i < curr->drv->size; i++) {
2494 if (enable)
2495 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2496 curr->drv->on[i].val);
2497 else
2498 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2499 curr->drv->off[i].val);
2500 }
2501
2502 for (i = 0; i < curr->pull->size; i++) {
2503 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002504 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 curr->pull->on[i].val);
2506 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002507 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 curr->pull->off[i].val);
2509 }
2510
2511 return 0;
2512}
2513
2514static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2515{
2516 int rc = 0;
2517
2518 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2519 return 0;
2520
2521 if (host->plat->pin_data->is_gpio)
2522 rc = msmsdcc_setup_gpio(host, enable);
2523 else
2524 rc = msmsdcc_setup_pad(host, enable);
2525
2526 if (!rc)
2527 host->plat->pin_data->cfg_sts = enable;
2528
2529 return rc;
2530}
2531
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302532static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2533 unsigned mode)
2534{
2535 int ret = 0;
2536 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2537
2538 if (!pin)
2539 return 0;
2540
2541 switch (mode) {
2542 case SDC_DAT1_DISABLE:
2543 ret = msm_mpm_enable_pin(pin, 0);
2544 break;
2545 case SDC_DAT1_ENABLE:
2546 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2547 ret = msm_mpm_enable_pin(pin, 1);
2548 break;
2549 case SDC_DAT1_ENWAKE:
2550 ret = msm_mpm_set_pin_wake(pin, 1);
2551 break;
2552 case SDC_DAT1_DISWAKE:
2553 ret = msm_mpm_set_pin_wake(pin, 0);
2554 break;
2555 default:
2556 ret = -EINVAL;
2557 break;
2558 }
2559
2560 return ret;
2561}
2562
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302563static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2564{
2565 u32 pwr = 0;
2566 int ret = 0;
2567 struct mmc_host *mmc = host->mmc;
2568
2569 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2570 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2571 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2572 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2573
2574 if (ret) {
2575 pr_err("%s: Failed to setup voltage regulators\n",
2576 mmc_hostname(host->mmc));
2577 goto out;
2578 }
2579
2580 switch (ios->power_mode) {
2581 case MMC_POWER_OFF:
2582 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302583 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302584 /*
2585 * As VDD pad rail is always on, set low voltage for VDD
2586 * pad rail when slot is unused (when card is not present
2587 * or during system suspend).
2588 */
2589 msmsdcc_set_vddp_low_vol(host);
2590 msmsdcc_setup_pins(host, false);
2591 break;
2592 case MMC_POWER_UP:
2593 /* writing PWR_UP bit is redundant */
2594 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302595 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302596
2597 msmsdcc_set_vddp_high_vol(host);
2598 msmsdcc_setup_pins(host, true);
2599 break;
2600 case MMC_POWER_ON:
2601 pwr = MCI_PWR_ON;
2602 break;
2603 }
2604
2605out:
2606 return pwr;
2607}
2608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2610{
2611 unsigned int wakeup_irq;
2612
2613 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2614 host->plat->sdiowakeup_irq :
2615 host->core_irqres->start;
2616
2617 if (!host->irq_wake_enabled) {
2618 enable_irq_wake(wakeup_irq);
2619 host->irq_wake_enabled = true;
2620 }
2621}
2622
2623static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2624{
2625 unsigned int wakeup_irq;
2626
2627 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2628 host->plat->sdiowakeup_irq :
2629 host->core_irqres->start;
2630
2631 if (host->irq_wake_enabled) {
2632 disable_irq_wake(wakeup_irq);
2633 host->irq_wake_enabled = false;
2634 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302635}
2636
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302637/* Returns required bandwidth in Bytes per Sec */
2638static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2639 struct mmc_ios *ios)
2640{
2641 unsigned int bw;
2642
2643 bw = host->clk_rate;
2644 /*
2645 * For DDR mode, SDCC controller clock will be at
2646 * the double rate than the actual clock that goes to card.
2647 */
2648 if (ios->bus_width == MMC_BUS_WIDTH_4)
2649 bw /= 2;
2650 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2651 bw /= 8;
2652
2653 return bw;
2654}
2655
2656static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2657 unsigned int bw)
2658{
2659 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2660 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2661 int i;
2662
2663 if (host->msm_bus_vote.is_max_bw_needed && bw)
2664 return host->msm_bus_vote.max_bw_vote;
2665
2666 for (i = 0; i < size; i++) {
2667 if (bw <= table[i])
2668 break;
2669 }
2670
2671 if (i && (i == size))
2672 i--;
2673
2674 return i;
2675}
2676
2677static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2678{
2679 int rc = 0;
2680 struct msm_bus_scale_pdata *use_cases;
2681
2682 if (host->plat->msm_bus_voting_data &&
2683 host->plat->msm_bus_voting_data->use_cases &&
2684 host->plat->msm_bus_voting_data->bw_vecs &&
2685 host->plat->msm_bus_voting_data->bw_vecs_size) {
2686 use_cases = host->plat->msm_bus_voting_data->use_cases;
2687 host->msm_bus_vote.client_handle =
2688 msm_bus_scale_register_client(use_cases);
2689 } else {
2690 return 0;
2691 }
2692
2693 if (!host->msm_bus_vote.client_handle) {
2694 pr_err("%s: msm_bus_scale_register_client() failed\n",
2695 mmc_hostname(host->mmc));
2696 rc = -EFAULT;
2697 } else {
2698 /* cache the vote index for minimum and maximum bandwidth */
2699 host->msm_bus_vote.min_bw_vote =
2700 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2701 host->msm_bus_vote.max_bw_vote =
2702 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2703 }
2704
2705 return rc;
2706}
2707
2708static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2709{
2710 if (host->msm_bus_vote.client_handle)
2711 msm_bus_scale_unregister_client(
2712 host->msm_bus_vote.client_handle);
2713}
2714
2715/*
2716 * This function must be called with host lock acquired.
2717 * Caller of this function should also ensure that msm bus client
2718 * handle is not null.
2719 */
2720static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2721 int vote,
2722 unsigned long flags)
2723{
2724 int rc = 0;
2725
2726 if (vote != host->msm_bus_vote.curr_vote) {
2727 spin_unlock_irqrestore(&host->lock, flags);
2728 rc = msm_bus_scale_client_update_request(
2729 host->msm_bus_vote.client_handle, vote);
2730 if (rc)
2731 pr_err("%s: msm_bus_scale_client_update_request() failed."
2732 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2733 mmc_hostname(host->mmc),
2734 host->msm_bus_vote.client_handle, vote, rc);
2735 spin_lock_irqsave(&host->lock, flags);
2736 if (!rc)
2737 host->msm_bus_vote.curr_vote = vote;
2738 }
2739
2740 return rc;
2741}
2742
2743/*
2744 * Internal work. Work to set 0 bandwidth for msm bus.
2745 */
2746static void msmsdcc_msm_bus_work(struct work_struct *work)
2747{
2748 struct msmsdcc_host *host = container_of(work,
2749 struct msmsdcc_host,
2750 msm_bus_vote.vote_work.work);
2751 unsigned long flags;
2752
2753 if (!host->msm_bus_vote.client_handle)
2754 return;
2755
2756 spin_lock_irqsave(&host->lock, flags);
2757 /* don't vote for 0 bandwidth if any request is in progress */
2758 if (!host->curr.mrq)
2759 msmsdcc_msm_bus_set_vote(host,
2760 host->msm_bus_vote.min_bw_vote, flags);
2761 else
2762 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2763 " bus voting to 0 bandwidth\n",
2764 mmc_hostname(host->mmc), __func__);
2765 spin_unlock_irqrestore(&host->lock, flags);
2766}
2767
2768/*
2769 * This function cancels any scheduled delayed work
2770 * and sets the bus vote based on ios argument.
2771 * If "ios" argument is NULL, bandwidth required is 0 else
2772 * calculate the bandwidth based on ios parameters.
2773 */
2774static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2775 struct msmsdcc_host *host,
2776 struct mmc_ios *ios)
2777{
2778 unsigned long flags;
2779 unsigned int bw;
2780 int vote;
2781
2782 if (!host->msm_bus_vote.client_handle)
2783 return;
2784
2785 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2786
2787 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2788 spin_lock_irqsave(&host->lock, flags);
2789 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2790 msmsdcc_msm_bus_set_vote(host, vote, flags);
2791 spin_unlock_irqrestore(&host->lock, flags);
2792}
2793
2794/* This function queues a work which will set the bandwidth requiement to 0 */
2795static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2796{
2797 unsigned long flags;
2798
2799 if (!host->msm_bus_vote.client_handle)
2800 return;
2801
2802 spin_lock_irqsave(&host->lock, flags);
2803 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2804 queue_delayed_work(system_nrt_wq,
2805 &host->msm_bus_vote.vote_work,
2806 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2807 spin_unlock_irqrestore(&host->lock, flags);
2808}
2809
San Mehat9d2bd732009-09-22 16:44:22 -07002810static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302811msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2812{
2813 struct mmc_host *mmc = host->mmc;
2814
2815 /*
2816 * SDIO_AL clients has different mechanism of handling LPM through
2817 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2818 * part of that. Here, we are interested only in clients like WLAN.
2819 */
2820 if (!(mmc->card && mmc_card_sdio(mmc->card))
2821 || host->plat->is_sdio_al_client)
2822 goto out;
2823
2824 if (!host->sdcc_suspended) {
2825 /*
2826 * When MSM is not in power collapse and we
2827 * are disabling clocks, enable bit 22 in MASK0
2828 * to handle asynchronous SDIO interrupts.
2829 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302830 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302831 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302832 mb();
2833 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302834 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302835 msmsdcc_sync_reg_wr(host);
2836 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302837 goto out;
2838 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2839 /*
2840 * Wakeup MSM only if SDIO function drivers set
2841 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2842 */
2843 goto out;
2844 }
2845
2846 if (enable_wakeup_irq) {
2847 if (!host->plat->sdiowakeup_irq) {
2848 /*
2849 * When there is no gpio line that can be configured
2850 * as wakeup interrupt handle it by configuring
2851 * asynchronous sdio interrupts and DAT1 line.
2852 */
2853 writel_relaxed(MCI_SDIOINTMASK,
2854 host->base + MMCIMASK0);
2855 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302856 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302857 /* configure sdcc core interrupt as wakeup interrupt */
2858 msmsdcc_enable_irq_wake(host);
2859 } else {
2860 /* Let gpio line handle wakeup interrupt */
2861 writel_relaxed(0, host->base + MMCIMASK0);
2862 mb();
2863 if (host->sdio_wakeupirq_disabled) {
2864 host->sdio_wakeupirq_disabled = 0;
2865 /* configure gpio line as wakeup interrupt */
2866 msmsdcc_enable_irq_wake(host);
2867 enable_irq(host->plat->sdiowakeup_irq);
2868 }
2869 }
2870 } else {
2871 if (!host->plat->sdiowakeup_irq) {
2872 /*
2873 * We may not have cleared bit 22 in the interrupt
2874 * handler as the clocks might be off at that time.
2875 */
2876 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302877 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302878 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302879 msmsdcc_disable_irq_wake(host);
2880 } else if (!host->sdio_wakeupirq_disabled) {
2881 disable_irq_nosync(host->plat->sdiowakeup_irq);
2882 msmsdcc_disable_irq_wake(host);
2883 host->sdio_wakeupirq_disabled = 1;
2884 }
2885 }
2886out:
2887 return;
2888}
2889
2890static void
San Mehat9d2bd732009-09-22 16:44:22 -07002891msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2892{
2893 struct msmsdcc_host *host = mmc_priv(mmc);
2894 u32 clk = 0, pwr = 0;
2895 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002896 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002897 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002898
Sahitya Tummala7a892482011-01-18 11:22:49 +05302899
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302900 /*
2901 * Disable SDCC core interrupt until set_ios is completed.
2902 * This avoids any race conditions with interrupt raised
2903 * when turning on/off the clocks. One possible
2904 * scenario is SDIO operational interrupt while the clock
2905 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302906 * host->lock is being released intermittently below.
2907 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302908 */
2909
Asutosh Dasf5298c32012-04-03 14:51:47 +05302910 mutex_lock(&host->clk_mutex);
2911 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302912 spin_lock_irqsave(&host->lock, flags);
2913 if (!host->sdcc_irq_disabled) {
2914 spin_unlock_irqrestore(&host->lock, flags);
2915 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302917 host->sdcc_irq_disabled = 1;
2918 }
2919 spin_unlock_irqrestore(&host->lock, flags);
2920
2921 pwr = msmsdcc_setup_pwr(host, ios);
2922
2923 spin_lock_irqsave(&host->lock, flags);
2924 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002925 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302926 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302928 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302930 writel_relaxed(host->mci_irqenable,
2931 host->base + MMCIMASK0);
2932 mb();
2933 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002934 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935
2936 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2937 /*
2938 * For DDR50 mode, controller needs clock rate to be
2939 * double than what is required on the SD card CLK pin.
2940 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302941 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 /*
2943 * Make sure that we don't double the clock if
2944 * doubled clock rate is already set
2945 */
2946 if (!host->ddr_doubled_clk_rate ||
2947 (host->ddr_doubled_clk_rate &&
2948 (host->ddr_doubled_clk_rate != ios->clock))) {
2949 host->ddr_doubled_clk_rate =
2950 msmsdcc_get_sup_clk_rate(
2951 host, (ios->clock * 2));
2952 clock = host->ddr_doubled_clk_rate;
2953 }
2954 } else {
2955 host->ddr_doubled_clk_rate = 0;
2956 }
2957
2958 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302959 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002960 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302961 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002962 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302963 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964 mmc_hostname(mmc), clock);
2965 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302966 host->reg_write_delay =
2967 (1 + ((3 * USEC_PER_SEC) /
2968 (host->clk_rate ? host->clk_rate :
2969 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002970 }
2971 /*
2972 * give atleast 2 MCLK cycles delay for clocks
2973 * and SDCC core to stabilize
2974 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302975 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002977 clk |= MCI_CLK_ENABLE;
2978 }
2979
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980 if (ios->bus_width == MMC_BUS_WIDTH_8)
2981 clk |= MCI_CLK_WIDEBUS_8;
2982 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2983 clk |= MCI_CLK_WIDEBUS_4;
2984 else
2985 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987 if (msmsdcc_is_pwrsave(host))
2988 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992 host->tuning_needed = 0;
2993 /*
2994 * Select the controller timing mode according
2995 * to current bus speed mode
2996 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302997 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2998 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999 clk |= (4 << 14);
3000 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05303001 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002 clk |= (3 << 14);
3003 } else {
3004 clk |= (2 << 14); /* feedback clock */
3005 }
3006
3007 /* Select free running MCLK as input clock of cm_dll_sdc4 */
3008 clk |= (2 << 23);
3009
Subhash Jadavani00083572012-02-15 16:18:01 +05303010 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
3011 if (!ios->vdd)
3012 host->io_pad_pwr_switch = 0;
3013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 if (host->io_pad_pwr_switch)
3015 clk |= IO_PAD_PWR_SWITCH;
3016
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303017 /* Don't write into registers if clocks are disabled */
3018 if (host->clks_on) {
3019 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3020 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303021 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303023 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3024 host->pwr = pwr;
3025 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303026 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 }
3029
3030 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303031 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303032 spin_unlock_irqrestore(&host->lock, flags);
3033 /*
3034 * May get a wake-up interrupt the instant we disable the
3035 * clocks. This would disable the wake-up interrupt.
3036 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303038 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003039 host->clks_on = 0;
3040 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303041
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303042 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303043 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303044 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303045
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303046 /* Let interrupts be disabled if the host is powered off */
3047 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3048 enable_irq(host->core_irqres->start);
3049 host->sdcc_irq_disabled = 0;
3050 }
3051
San Mehat4adbbcc2009-11-08 13:00:37 -08003052 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303053 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003054}
3055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3057{
3058 struct msmsdcc_host *host = mmc_priv(mmc);
3059 u32 clk;
3060
3061 clk = readl_relaxed(host->base + MMCICLOCK);
3062 pr_debug("Changing to pwr_save=%d", pwrsave);
3063 if (pwrsave && msmsdcc_is_pwrsave(host))
3064 clk |= MCI_CLK_PWRSAVE;
3065 else
3066 clk &= ~MCI_CLK_PWRSAVE;
3067 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303068 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069
3070 return 0;
3071}
3072
3073static int msmsdcc_get_ro(struct mmc_host *mmc)
3074{
3075 int status = -ENOSYS;
3076 struct msmsdcc_host *host = mmc_priv(mmc);
3077
3078 if (host->plat->wpswitch) {
3079 status = host->plat->wpswitch(mmc_dev(mmc));
3080 } else if (host->plat->wpswitch_gpio) {
3081 status = gpio_request(host->plat->wpswitch_gpio,
3082 "SD_WP_Switch");
3083 if (status) {
3084 pr_err("%s: %s: Failed to request GPIO %d\n",
3085 mmc_hostname(mmc), __func__,
3086 host->plat->wpswitch_gpio);
3087 } else {
3088 status = gpio_direction_input(
3089 host->plat->wpswitch_gpio);
3090 if (!status) {
3091 /*
3092 * Wait for atleast 300ms as debounce
3093 * time for GPIO input to stabilize.
3094 */
3095 msleep(300);
3096 status = gpio_get_value_cansleep(
3097 host->plat->wpswitch_gpio);
3098 status ^= !host->plat->wpswitch_polarity;
3099 }
3100 gpio_free(host->plat->wpswitch_gpio);
3101 }
3102 }
3103
3104 if (status < 0)
3105 status = -ENOSYS;
3106 pr_debug("%s: Card read-only status %d\n", __func__, status);
3107
3108 return status;
3109}
3110
San Mehat9d2bd732009-09-22 16:44:22 -07003111static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3112{
3113 struct msmsdcc_host *host = mmc_priv(mmc);
3114 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303116 /*
3117 * We may come here with clocks turned off in that case don't
3118 * attempt to write into MASK0 register. While turning on the
3119 * clocks mci_irqenable will be written to MASK0 register.
3120 */
3121
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303122 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303125 if (host->clks_on) {
3126 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303128 mb();
3129 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003130 } else {
3131 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303132 if (host->clks_on) {
3133 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303135 mb();
3136 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 }
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303138 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003139}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140
3141#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303142static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
3143{
3144 struct device *dev = mmc_dev(host->mmc);
3145
3146 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3147 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3148 " request_pending=%d, request=%d\n",
3149 mmc_hostname(host->mmc), dev->power.runtime_status,
3150 atomic_read(&dev->power.usage_count),
3151 dev->power.is_suspended, dev->power.disable_depth,
3152 dev->power.runtime_error, dev->power.request_pending,
3153 dev->power.request);
3154}
3155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003156static int msmsdcc_enable(struct mmc_host *mmc)
3157{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003158 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003159 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303160 struct msmsdcc_host *host = mmc_priv(mmc);
3161
3162 msmsdcc_pm_qos_update_latency(host, 1);
3163
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003164 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303165 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003166
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003167 if (host->sdcc_suspended && host->pending_resume &&
3168 !pm_runtime_suspended(dev)) {
3169 host->pending_resume = false;
3170 pm_runtime_get_noresume(dev);
3171 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303172 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003173 }
3174
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303175 if (dev->power.runtime_status == RPM_SUSPENDING) {
3176 if (mmc->suspend_task == current) {
3177 pm_runtime_get_noresume(dev);
3178 goto out;
3179 }
3180 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303182 rc = pm_runtime_get_sync(dev);
3183
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303184skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303185 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3187 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303188 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303189 return rc;
3190 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303191out:
3192 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303193 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194}
3195
3196static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3197{
3198 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303199 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303201 msmsdcc_pm_qos_update_latency(host, 0);
3202
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303203 if (mmc->card && mmc_card_sdio(mmc->card)) {
3204 rc = 0;
3205 goto out;
3206 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303207
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303208 if (host->plat->disable_runtime_pm)
3209 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003210
3211 rc = pm_runtime_put_sync(mmc->parent);
3212
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003213 /*
3214 * Ignore -EAGAIN as that is not fatal, it means that
3215 * either runtime usage count is non-zero or the runtime
3216 * pm itself is disabled or not in proper state to process
3217 * idle notification.
3218 */
3219 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3221 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303222 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003223 return rc;
3224 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303225
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303226out:
3227 msmsdcc_msm_bus_queue_work(host);
3228 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229}
3230#else
subhashj245831e2012-04-30 18:46:17 +05303231static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3232
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303233static int msmsdcc_enable(struct mmc_host *mmc)
3234{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003235 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303236 struct msmsdcc_host *host = mmc_priv(mmc);
3237 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303238 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303239
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303240 msmsdcc_pm_qos_update_latency(host, 1);
3241
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303242 if (mmc->card && mmc_card_sdio(mmc->card)) {
3243 rc = 0;
3244 goto out;
3245 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003246
3247 if (host->sdcc_suspended && host->pending_resume) {
3248 host->pending_resume = false;
3249 rc = msmsdcc_runtime_resume(dev);
3250 goto out;
3251 }
3252
Asutosh Dasf5298c32012-04-03 14:51:47 +05303253 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303254 spin_lock_irqsave(&host->lock, flags);
3255 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303256 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303257 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303258 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303259 host->clks_on = 1;
3260 }
3261 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303262 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303263
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003264out:
3265 if (rc < 0) {
3266 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3267 __func__, rc);
3268 return rc;
3269 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303270 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303271 return 0;
3272}
3273
3274static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3275{
3276 struct msmsdcc_host *host = mmc_priv(mmc);
3277 unsigned long flags;
3278
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303279 msmsdcc_pm_qos_update_latency(host, 0);
3280
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303281 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303282 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303283
Asutosh Dasf5298c32012-04-03 14:51:47 +05303284 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303285 spin_lock_irqsave(&host->lock, flags);
3286 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303287 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303288 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303289 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303290 host->clks_on = 0;
3291 }
3292 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303293 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303294
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303295out:
3296 msmsdcc_msm_bus_queue_work(host);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303297 return 0;
3298}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003299#endif
3300
3301static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3302 struct mmc_ios *ios)
3303{
3304 struct msmsdcc_host *host = mmc_priv(mmc);
3305 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303306 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307
Subhash Jadavani00083572012-02-15 16:18:01 +05303308 spin_lock_irqsave(&host->lock, flags);
3309 host->io_pad_pwr_switch = 0;
3310 spin_unlock_irqrestore(&host->lock, flags);
3311
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303312 /*
3313 * For eMMC cards, VccQ voltage range must be changed
3314 * only if it operates in HS200 SDR 1.2V mode or in
3315 * DDR 1.2V mode.
3316 */
3317 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3318 rc = msmsdcc_set_vccq_vol(host, 1200000);
3319 goto out;
3320 }
3321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3323 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303324 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 goto out;
3326 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3327 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303328 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003329 goto out;
3330 }
San Mehat9d2bd732009-09-22 16:44:22 -07003331
3332 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003333 /*
3334 * If we are here means voltage switch from high voltage to
3335 * low voltage is required
3336 */
3337
3338 /*
3339 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3340 * register until they become all zeros.
3341 */
3342 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303343 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3345 mmc_hostname(mmc), __func__);
3346 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003347 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003348
3349 /* Stop SD CLK output. */
3350 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3351 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303352 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003353 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354
3355 /*
3356 * Switch VDDPX from high voltage to low voltage
3357 * to change the VDD of the SD IO pads.
3358 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303359 rc = msmsdcc_set_vddp_low_vol(host);
3360 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003362
3363 spin_lock_irqsave(&host->lock, flags);
3364 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3365 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303366 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003367 host->io_pad_pwr_switch = 1;
3368 spin_unlock_irqrestore(&host->lock, flags);
3369
3370 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3371 usleep_range(5000, 5500);
3372
3373 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303374 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3376 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303377 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 spin_unlock_irqrestore(&host->lock, flags);
3379
3380 /*
3381 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3382 * don't become all ones within 1 ms then a Voltage Switch
3383 * sequence has failed and a power cycle to the card is required.
3384 * Otherwise Voltage Switch sequence is completed successfully.
3385 */
3386 usleep_range(1000, 1500);
3387
3388 spin_lock_irqsave(&host->lock, flags);
3389 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3390 != (0xF << 1)) {
3391 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3392 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303393 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394 goto out_unlock;
3395 }
3396
3397out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303398 /* Enable PWRSAVE */
3399 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3400 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303401 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402 spin_unlock_irqrestore(&host->lock, flags);
3403out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303404 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405}
3406
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303407static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410
3411 /* Program the MCLK value to MCLK_FREQ bit field */
3412 if (host->clk_rate <= 112000000)
3413 mclk_freq = 0;
3414 else if (host->clk_rate <= 125000000)
3415 mclk_freq = 1;
3416 else if (host->clk_rate <= 137000000)
3417 mclk_freq = 2;
3418 else if (host->clk_rate <= 150000000)
3419 mclk_freq = 3;
3420 else if (host->clk_rate <= 162000000)
3421 mclk_freq = 4;
3422 else if (host->clk_rate <= 175000000)
3423 mclk_freq = 5;
3424 else if (host->clk_rate <= 187000000)
3425 mclk_freq = 6;
3426 else if (host->clk_rate <= 200000000)
3427 mclk_freq = 7;
3428
3429 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3430 & ~(7 << 24)) | (mclk_freq << 24)),
3431 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003432}
3433
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303434/* Initialize the DLL (Programmable Delay Line ) */
3435static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303438 unsigned long flags;
3439 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303441 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003442 /*
3443 * Make sure that clock is always enabled when DLL
3444 * tuning is in progress. Keeping PWRSAVE ON may
3445 * turn off the clock. So let's disable the PWRSAVE
3446 * here and re-enable it once tuning is completed.
3447 */
3448 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3449 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303450 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303451
3452 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3453 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3454 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3455
3456 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3457 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3458 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3459
3460 msmsdcc_cm_sdc4_dll_set_freq(host);
3461
3462 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3463 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3464 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3465
3466 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3467 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3468 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3469
3470 /* Set DLL_EN bit to 1. */
3471 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3472 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3473
3474 /* Set CK_OUT_EN bit to 1. */
3475 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3476 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3477
3478 wait_cnt = 50;
3479 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3480 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3481 /* max. wait for 50us sec for LOCK bit to be set */
3482 if (--wait_cnt == 0) {
3483 pr_err("%s: %s: DLL failed to LOCK\n",
3484 mmc_hostname(host->mmc), __func__);
3485 rc = -ETIMEDOUT;
3486 goto out;
3487 }
3488 /* wait for 1us before polling again */
3489 udelay(1);
3490 }
3491
3492out:
3493 /* re-enable PWRSAVE */
3494 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3495 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303496 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303497 spin_unlock_irqrestore(&host->lock, flags);
3498
3499 return rc;
3500}
3501
3502static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3503 u8 poll)
3504{
3505 int rc = 0;
3506 u32 wait_cnt = 50;
3507 u8 ck_out_en = 0;
3508
3509 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3510 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3511 MCI_CK_OUT_EN);
3512
3513 while (ck_out_en != poll) {
3514 if (--wait_cnt == 0) {
3515 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3516 mmc_hostname(host->mmc), __func__, poll);
3517 rc = -ETIMEDOUT;
3518 goto out;
3519 }
3520 udelay(1);
3521
3522 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3523 MCI_CK_OUT_EN);
3524 }
3525out:
3526 return rc;
3527}
3528
3529/*
3530 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3531 * calibration sequence. This function should be called before
3532 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3533 * commands (CMD17/CMD18).
3534 *
3535 * This function gets called when host spinlock acquired.
3536 */
3537static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3538{
3539 int rc = 0;
3540 u32 config;
3541
3542 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3543 config |= MCI_CDR_EN;
3544 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3545 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3546
3547 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3548 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3549 if (rc)
3550 goto err_out;
3551
3552 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3553 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3554 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3555
3556 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3557 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3558 if (rc)
3559 goto err_out;
3560
3561 goto out;
3562
3563err_out:
3564 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3565out:
3566 return rc;
3567}
3568
3569static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3570 u8 phase)
3571{
3572 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303573 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3574 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3575 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303576 unsigned long flags;
3577 u32 config;
3578
3579 spin_lock_irqsave(&host->lock, flags);
3580
3581 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3582 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3583 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3584 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3585
3586 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3587 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3588 if (rc)
3589 goto err_out;
3590
3591 /*
3592 * Write the selected DLL clock output phase (0 ... 15)
3593 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3594 */
3595 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3596 & ~(0xF << 20))
3597 | (grey_coded_phase_table[phase] << 20)),
3598 host->base + MCI_DLL_CONFIG);
3599
3600 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3601 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3602 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3603
3604 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3605 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3606 if (rc)
3607 goto err_out;
3608
3609 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3610 config |= MCI_CDR_EN;
3611 config &= ~MCI_CDR_EXT_EN;
3612 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3613 goto out;
3614
3615err_out:
3616 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3617 mmc_hostname(host->mmc), __func__, phase);
3618out:
3619 spin_unlock_irqrestore(&host->lock, flags);
3620 return rc;
3621}
3622
3623/*
3624 * Find out the greatest range of consecuitive selected
3625 * DLL clock output phases that can be used as sampling
3626 * setting for SD3.0 UHS-I card read operation (in SDR104
3627 * timing mode) or for eMMC4.5 card read operation (in HS200
3628 * timing mode).
3629 * Select the 3/4 of the range and configure the DLL with the
3630 * selected DLL clock output phase.
3631*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303632static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303633 u8 *phase_table, u8 total_phases)
3634{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303635 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303636 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303637 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3638 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303639 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303640 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3641 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303642
Subhash Jadavani6159c622012-03-15 19:05:55 +05303643 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303644 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3645 mmc_hostname(host->mmc), __func__, total_phases);
3646 return -EINVAL;
3647 }
3648
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303649 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303650 ranges[row_index][col_index] = phase_table[cnt];
3651 phases_per_row[row_index] += 1;
3652 col_index++;
3653
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303654 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303655 continue;
3656 /* check if next phase in phase_table is consecutive or not */
3657 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3658 row_index++;
3659 col_index = 0;
3660 }
3661 }
3662
Subhash Jadavani6159c622012-03-15 19:05:55 +05303663 if (row_index >= MAX_PHASES)
3664 return -EINVAL;
3665
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303666 /* Check if phase-0 is present in first valid window? */
3667 if (!ranges[0][0]) {
3668 phase_0_found = true;
3669 phase_0_raw_index = 0;
3670 /* Check if cycle exist between 2 valid windows */
3671 for (cnt = 1; cnt <= row_index; cnt++) {
3672 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303673 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303674 if (ranges[cnt][i] == 15) {
3675 phase_15_found = true;
3676 phase_15_raw_index = cnt;
3677 break;
3678 }
3679 }
3680 }
3681 }
3682 }
3683
3684 /* If 2 valid windows form cycle then merge them as single window */
3685 if (phase_0_found && phase_15_found) {
3686 /* number of phases in raw where phase 0 is present */
3687 u8 phases_0 = phases_per_row[phase_0_raw_index];
3688 /* number of phases in raw where phase 15 is present */
3689 u8 phases_15 = phases_per_row[phase_15_raw_index];
3690
Subhash Jadavani6159c622012-03-15 19:05:55 +05303691 if (phases_0 + phases_15 >= MAX_PHASES)
3692 /*
3693 * If there are more than 1 phase windows then total
3694 * number of phases in both the windows should not be
3695 * more than or equal to MAX_PHASES.
3696 */
3697 return -EINVAL;
3698
3699 /* Merge 2 cyclic windows */
3700 i = phases_15;
3701 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303702 ranges[phase_15_raw_index][i] =
3703 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303704 if (++i >= MAX_PHASES)
3705 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303706 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303707
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303708 phases_per_row[phase_0_raw_index] = 0;
3709 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3710 }
3711
3712 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303713 if (phases_per_row[cnt] > curr_max) {
3714 curr_max = phases_per_row[cnt];
3715 selected_row_index = cnt;
3716 }
3717 }
3718
Subhash Jadavani6159c622012-03-15 19:05:55 +05303719 i = ((curr_max * 3) / 4);
3720 if (i)
3721 i--;
3722
Subhash Jadavani34187042012-03-02 10:59:49 +05303723 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303724
Subhash Jadavani6159c622012-03-15 19:05:55 +05303725 if (ret >= MAX_PHASES) {
3726 ret = -EINVAL;
3727 pr_err("%s: %s: invalid phase selected=%d\n",
3728 mmc_hostname(host->mmc), __func__, ret);
3729 }
3730
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303731 return ret;
3732}
3733
Girish K Sa3f41692012-02-29 12:00:09 +05303734static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303735{
3736 int rc = 0;
3737 struct msmsdcc_host *host = mmc_priv(mmc);
3738 unsigned long flags;
3739 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303740 const u32 *tuning_block_pattern = tuning_block_64;
3741 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303742
3743 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3744
3745 /* Tuning is only required for SDR104 modes */
3746 if (!host->tuning_needed) {
3747 rc = 0;
3748 goto exit;
3749 }
3750
3751 spin_lock_irqsave(&host->lock, flags);
3752 WARN(!host->pwr, "SDCC power is turned off\n");
3753 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3754 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3755
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303756 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303757 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3758 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3759 tuning_block_pattern = tuning_block_128;
3760 size = sizeof(tuning_block_128);
3761 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303762 spin_unlock_irqrestore(&host->lock, flags);
3763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764 /* first of all reset the tuning block */
3765 rc = msmsdcc_init_cm_sdc4_dll(host);
3766 if (rc)
3767 goto out;
3768
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303769 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003770 if (!data_buf) {
3771 rc = -ENOMEM;
3772 goto out;
3773 }
3774
3775 phase = 0;
3776 do {
3777 struct mmc_command cmd = {0};
3778 struct mmc_data data = {0};
3779 struct mmc_request mrq = {
3780 .cmd = &cmd,
3781 .data = &data
3782 };
3783 struct scatterlist sg;
3784
3785 /* set the phase in delay line hw block */
3786 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3787 if (rc)
3788 goto kfree;
3789
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303790 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3792
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303793 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003794 data.blocks = 1;
3795 data.flags = MMC_DATA_READ;
3796 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3797
3798 data.sg = &sg;
3799 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303800 sg_init_one(&sg, data_buf, size);
3801 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802 mmc_wait_for_req(mmc, &mrq);
3803
3804 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303805 !memcmp(data_buf, tuning_block_pattern, size)) {
3806 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303808 pr_debug("%s: %s: found good phase = %d\n",
3809 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 }
3811 } while (++phase < 16);
3812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303814 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303815 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303816 if (rc < 0)
3817 goto kfree;
3818 else
3819 phase = (u8)rc;
3820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821 /*
3822 * Finally set the selected phase in delay
3823 * line hw block.
3824 */
3825 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3826 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303827 goto kfree;
3828 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3829 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 } else {
3831 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303832 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303834 msmsdcc_dump_sdcc_state(host);
3835 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837
3838kfree:
3839 kfree(data_buf);
3840out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303841 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303842 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303843 spin_unlock_irqrestore(&host->lock, flags);
3844exit:
3845 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003847}
3848
3849static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003850 .enable = msmsdcc_enable,
3851 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303852 .pre_req = msmsdcc_pre_req,
3853 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003854 .request = msmsdcc_request,
3855 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003857 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3859 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003860};
3861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862static unsigned int
3863msmsdcc_slot_status(struct msmsdcc_host *host)
3864{
3865 int status;
3866 unsigned int gpio_no = host->plat->status_gpio;
3867
3868 status = gpio_request(gpio_no, "SD_HW_Detect");
3869 if (status) {
3870 pr_err("%s: %s: Failed to request GPIO %d\n",
3871 mmc_hostname(host->mmc), __func__, gpio_no);
3872 } else {
3873 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003874 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003875 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003876 if (host->plat->is_status_gpio_active_low)
3877 status = !status;
3878 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879 gpio_free(gpio_no);
3880 }
3881 return status;
3882}
3883
San Mehat9d2bd732009-09-22 16:44:22 -07003884static void
3885msmsdcc_check_status(unsigned long data)
3886{
3887 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3888 unsigned int status;
3889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003891 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003893 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003894 status = msmsdcc_slot_status(host);
3895
Krishna Konda941604a2012-01-10 17:46:34 -08003896 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003899 if (host->plat->status)
3900 pr_info("%s: Slot status change detected "
3901 "(%d -> %d)\n",
3902 mmc_hostname(host->mmc),
3903 host->oldstat, status);
3904 else if (host->plat->is_status_gpio_active_low)
3905 pr_info("%s: Slot status change detected "
3906 "(%d -> %d) and the card detect GPIO"
3907 " is ACTIVE_LOW\n",
3908 mmc_hostname(host->mmc),
3909 host->oldstat, status);
3910 else
3911 pr_info("%s: Slot status change detected "
3912 "(%d -> %d) and the card detect GPIO"
3913 " is ACTIVE_HIGH\n",
3914 mmc_hostname(host->mmc),
3915 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003916 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 }
3918 host->oldstat = status;
3919 } else {
3920 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003921 }
San Mehat9d2bd732009-09-22 16:44:22 -07003922}
3923
3924static irqreturn_t
3925msmsdcc_platform_status_irq(int irq, void *dev_id)
3926{
3927 struct msmsdcc_host *host = dev_id;
3928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003929 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003930 msmsdcc_check_status((unsigned long) host);
3931 return IRQ_HANDLED;
3932}
3933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934static irqreturn_t
3935msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3936{
3937 struct msmsdcc_host *host = dev_id;
3938
3939 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3940 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303941 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303943 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003944 wake_lock(&host->sdio_wlock);
3945 msmsdcc_disable_irq_wake(host);
3946 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303947 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 }
3949 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003950 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303951 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303952 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303953 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954 }
3955 spin_unlock(&host->lock);
3956
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303957out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003958 return IRQ_HANDLED;
3959}
3960
San Mehat9d2bd732009-09-22 16:44:22 -07003961static void
3962msmsdcc_status_notify_cb(int card_present, void *dev_id)
3963{
3964 struct msmsdcc_host *host = dev_id;
3965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003967 card_present);
3968 msmsdcc_check_status((unsigned long) host);
3969}
3970
San Mehat9d2bd732009-09-22 16:44:22 -07003971static int
3972msmsdcc_init_dma(struct msmsdcc_host *host)
3973{
3974 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3975 host->dma.host = host;
3976 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003977 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003978
3979 if (!host->dmares)
3980 return -ENODEV;
3981
3982 host->dma.nc = dma_alloc_coherent(NULL,
3983 sizeof(struct msmsdcc_nc_dmadata),
3984 &host->dma.nc_busaddr,
3985 GFP_KERNEL);
3986 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003987 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003988 return -ENOMEM;
3989 }
3990 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3991 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3992 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3993 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3994 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003995 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003996
3997 return 0;
3998}
3999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004000#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
4001/**
4002 * Allocate and Connect a SDCC peripheral's SPS endpoint
4003 *
4004 * This function allocates endpoint context and
4005 * connect it with memory endpoint by calling
4006 * appropriate SPS driver APIs.
4007 *
4008 * Also registers a SPS callback function with
4009 * SPS driver
4010 *
4011 * This function should only be called once typically
4012 * during driver probe.
4013 *
4014 * @host - Pointer to sdcc host structure
4015 * @ep - Pointer to sps endpoint data structure
4016 * @is_produce - 1 means Producer endpoint
4017 * 0 means Consumer endpoint
4018 *
4019 * @return - 0 if successful else negative value.
4020 *
4021 */
4022static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4023 struct msmsdcc_sps_ep_conn_data *ep,
4024 bool is_producer)
4025{
4026 int rc = 0;
4027 struct sps_pipe *sps_pipe_handle;
4028 struct sps_connect *sps_config = &ep->config;
4029 struct sps_register_event *sps_event = &ep->event;
4030
4031 /* Allocate endpoint context */
4032 sps_pipe_handle = sps_alloc_endpoint();
4033 if (!sps_pipe_handle) {
4034 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4035 mmc_hostname(host->mmc), is_producer);
4036 rc = -ENOMEM;
4037 goto out;
4038 }
4039
4040 /* Get default connection configuration for an endpoint */
4041 rc = sps_get_config(sps_pipe_handle, sps_config);
4042 if (rc) {
4043 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4044 " rc=%d", mmc_hostname(host->mmc),
4045 (u32)sps_pipe_handle, rc);
4046 goto get_config_err;
4047 }
4048
4049 /* Modify the default connection configuration */
4050 if (is_producer) {
4051 /*
4052 * For SDCC producer transfer, source should be
4053 * SDCC peripheral where as destination should
4054 * be system memory.
4055 */
4056 sps_config->source = host->sps.bam_handle;
4057 sps_config->destination = SPS_DEV_HANDLE_MEM;
4058 /* Producer pipe will handle this connection */
4059 sps_config->mode = SPS_MODE_SRC;
4060 sps_config->options =
4061 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4062 } else {
4063 /*
4064 * For SDCC consumer transfer, source should be
4065 * system memory where as destination should
4066 * SDCC peripheral
4067 */
4068 sps_config->source = SPS_DEV_HANDLE_MEM;
4069 sps_config->destination = host->sps.bam_handle;
4070 sps_config->mode = SPS_MODE_DEST;
4071 sps_config->options =
4072 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4073 }
4074
4075 /* Producer pipe index */
4076 sps_config->src_pipe_index = host->sps.src_pipe_index;
4077 /* Consumer pipe index */
4078 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4079 /*
4080 * This event thresold value is only significant for BAM-to-BAM
4081 * transfer. It's ignored for BAM-to-System mode transfer.
4082 */
4083 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304084
4085 /* Allocate maximum descriptor fifo size */
4086 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4087 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4089 sps_config->desc.size,
4090 &sps_config->desc.phys_base,
4091 GFP_KERNEL);
4092
Pratibhasagar V00b94332011-10-18 14:57:27 +05304093 if (!sps_config->desc.base) {
4094 rc = -ENOMEM;
4095 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4096 , mmc_hostname(host->mmc));
4097 goto get_config_err;
4098 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4100
4101 /* Establish connection between peripheral and memory endpoint */
4102 rc = sps_connect(sps_pipe_handle, sps_config);
4103 if (rc) {
4104 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4105 " rc=%d", mmc_hostname(host->mmc),
4106 (u32)sps_pipe_handle, rc);
4107 goto sps_connect_err;
4108 }
4109
4110 sps_event->mode = SPS_TRIGGER_CALLBACK;
4111 sps_event->options = SPS_O_EOT;
4112 sps_event->callback = msmsdcc_sps_complete_cb;
4113 sps_event->xfer_done = NULL;
4114 sps_event->user = (void *)host;
4115
4116 /* Register callback event for EOT (End of transfer) event. */
4117 rc = sps_register_event(sps_pipe_handle, sps_event);
4118 if (rc) {
4119 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4120 " rc=%d", mmc_hostname(host->mmc),
4121 (u32)sps_pipe_handle, rc);
4122 goto reg_event_err;
4123 }
4124 /* Now save the sps pipe handle */
4125 ep->pipe_handle = sps_pipe_handle;
4126 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4127 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4128 __func__, is_producer ? "READ" : "WRITE",
4129 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4130 goto out;
4131
4132reg_event_err:
4133 sps_disconnect(sps_pipe_handle);
4134sps_connect_err:
4135 dma_free_coherent(mmc_dev(host->mmc),
4136 sps_config->desc.size,
4137 sps_config->desc.base,
4138 sps_config->desc.phys_base);
4139get_config_err:
4140 sps_free_endpoint(sps_pipe_handle);
4141out:
4142 return rc;
4143}
4144
4145/**
4146 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4147 *
4148 * This function disconnect endpoint and deallocates
4149 * endpoint context.
4150 *
4151 * This function should only be called once typically
4152 * during driver remove.
4153 *
4154 * @host - Pointer to sdcc host structure
4155 * @ep - Pointer to sps endpoint data structure
4156 *
4157 */
4158static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4159 struct msmsdcc_sps_ep_conn_data *ep)
4160{
4161 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4162 struct sps_connect *sps_config = &ep->config;
4163 struct sps_register_event *sps_event = &ep->event;
4164
4165 sps_event->xfer_done = NULL;
4166 sps_event->callback = NULL;
4167 sps_register_event(sps_pipe_handle, sps_event);
4168 sps_disconnect(sps_pipe_handle);
4169 dma_free_coherent(mmc_dev(host->mmc),
4170 sps_config->desc.size,
4171 sps_config->desc.base,
4172 sps_config->desc.phys_base);
4173 sps_free_endpoint(sps_pipe_handle);
4174}
4175
4176/**
4177 * Reset SDCC peripheral's SPS endpoint
4178 *
4179 * This function disconnects an endpoint.
4180 *
4181 * This function should be called for reseting
4182 * SPS endpoint when data transfer error is
4183 * encountered during data transfer. This
4184 * can be considered as soft reset to endpoint.
4185 *
4186 * This function should only be called if
4187 * msmsdcc_sps_init() is already called.
4188 *
4189 * @host - Pointer to sdcc host structure
4190 * @ep - Pointer to sps endpoint data structure
4191 *
4192 * @return - 0 if successful else negative value.
4193 */
4194static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4195 struct msmsdcc_sps_ep_conn_data *ep)
4196{
4197 int rc = 0;
4198 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4199
4200 rc = sps_disconnect(sps_pipe_handle);
4201 if (rc) {
4202 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4203 " rc=%d", mmc_hostname(host->mmc), __func__,
4204 (u32)sps_pipe_handle, rc);
4205 goto out;
4206 }
4207 out:
4208 return rc;
4209}
4210
4211/**
4212 * Restore SDCC peripheral's SPS endpoint
4213 *
4214 * This function connects an endpoint.
4215 *
4216 * This function should be called for restoring
4217 * SPS endpoint after data transfer error is
4218 * encountered during data transfer. This
4219 * can be considered as soft reset to endpoint.
4220 *
4221 * This function should only be called if
4222 * msmsdcc_sps_reset_ep() is called before.
4223 *
4224 * @host - Pointer to sdcc host structure
4225 * @ep - Pointer to sps endpoint data structure
4226 *
4227 * @return - 0 if successful else negative value.
4228 */
4229static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4230 struct msmsdcc_sps_ep_conn_data *ep)
4231{
4232 int rc = 0;
4233 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4234 struct sps_connect *sps_config = &ep->config;
4235 struct sps_register_event *sps_event = &ep->event;
4236
4237 /* Establish connection between peripheral and memory endpoint */
4238 rc = sps_connect(sps_pipe_handle, sps_config);
4239 if (rc) {
4240 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4241 " rc=%d", mmc_hostname(host->mmc), __func__,
4242 (u32)sps_pipe_handle, rc);
4243 goto out;
4244 }
4245
4246 /* Register callback event for EOT (End of transfer) event. */
4247 rc = sps_register_event(sps_pipe_handle, sps_event);
4248 if (rc) {
4249 pr_err("%s: %s: sps_register_event() failed!!!"
4250 " pipe_handle=0x%x, rc=%d",
4251 mmc_hostname(host->mmc), __func__,
4252 (u32)sps_pipe_handle, rc);
4253 goto reg_event_err;
4254 }
4255 goto out;
4256
4257reg_event_err:
4258 sps_disconnect(sps_pipe_handle);
4259out:
4260 return rc;
4261}
4262
4263/**
4264 * Initialize SPS HW connected with SDCC core
4265 *
4266 * This function register BAM HW resources with
4267 * SPS driver and then initialize 2 SPS endpoints
4268 *
4269 * This function should only be called once typically
4270 * during driver probe.
4271 *
4272 * @host - Pointer to sdcc host structure
4273 *
4274 * @return - 0 if successful else negative value.
4275 *
4276 */
4277static int msmsdcc_sps_init(struct msmsdcc_host *host)
4278{
4279 int rc = 0;
4280 struct sps_bam_props bam = {0};
4281
4282 host->bam_base = ioremap(host->bam_memres->start,
4283 resource_size(host->bam_memres));
4284 if (!host->bam_base) {
4285 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4286 " size=0x%x", mmc_hostname(host->mmc),
4287 host->bam_memres->start,
4288 (host->bam_memres->end -
4289 host->bam_memres->start));
4290 rc = -ENOMEM;
4291 goto out;
4292 }
4293
4294 bam.phys_addr = host->bam_memres->start;
4295 bam.virt_addr = host->bam_base;
4296 /*
4297 * This event thresold value is only significant for BAM-to-BAM
4298 * transfer. It's ignored for BAM-to-System mode transfer.
4299 */
4300 bam.event_threshold = 0x10; /* Pipe event threshold */
4301 /*
4302 * This threshold controls when the BAM publish
4303 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304304 * SPS HW will be used for data transfer size even
4305 * less than SDCC FIFO size. So let's set BAM summing
4306 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304308 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004309 /* SPS driver wll handle the SDCC BAM IRQ */
4310 bam.irq = (u32)host->bam_irqres->start;
4311 bam.manage = SPS_BAM_MGR_LOCAL;
4312
4313 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4314 (u32)bam.phys_addr);
4315 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4316 (u32)bam.virt_addr);
4317
4318 /* Register SDCC Peripheral BAM device to SPS driver */
4319 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4320 if (rc) {
4321 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4322 mmc_hostname(host->mmc), rc);
4323 goto reg_bam_err;
4324 }
4325 pr_info("%s: BAM device registered. bam_handle=0x%x",
4326 mmc_hostname(host->mmc), host->sps.bam_handle);
4327
4328 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4329 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4330
4331 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4332 SPS_PROD_PERIPHERAL);
4333 if (rc)
4334 goto sps_reset_err;
4335 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4336 SPS_CONS_PERIPHERAL);
4337 if (rc)
4338 goto cons_conn_err;
4339
4340 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4341 mmc_hostname(host->mmc),
4342 (unsigned long long)host->bam_memres->start,
4343 (unsigned int)host->bam_irqres->start);
4344 goto out;
4345
4346cons_conn_err:
4347 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4348sps_reset_err:
4349 sps_deregister_bam_device(host->sps.bam_handle);
4350reg_bam_err:
4351 iounmap(host->bam_base);
4352out:
4353 return rc;
4354}
4355
4356/**
4357 * De-initialize SPS HW connected with SDCC core
4358 *
4359 * This function deinitialize SPS endpoints and then
4360 * deregisters BAM resources from SPS driver.
4361 *
4362 * This function should only be called once typically
4363 * during driver remove.
4364 *
4365 * @host - Pointer to sdcc host structure
4366 *
4367 */
4368static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4369{
4370 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4371 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4372 sps_deregister_bam_device(host->sps.bam_handle);
4373 iounmap(host->bam_base);
4374}
4375#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4376
4377static ssize_t
4378show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4379{
4380 struct mmc_host *mmc = dev_get_drvdata(dev);
4381 struct msmsdcc_host *host = mmc_priv(mmc);
4382 int poll;
4383 unsigned long flags;
4384
4385 spin_lock_irqsave(&host->lock, flags);
4386 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4387 spin_unlock_irqrestore(&host->lock, flags);
4388
4389 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4390}
4391
4392static ssize_t
4393set_polling(struct device *dev, struct device_attribute *attr,
4394 const char *buf, size_t count)
4395{
4396 struct mmc_host *mmc = dev_get_drvdata(dev);
4397 struct msmsdcc_host *host = mmc_priv(mmc);
4398 int value;
4399 unsigned long flags;
4400
4401 sscanf(buf, "%d", &value);
4402
4403 spin_lock_irqsave(&host->lock, flags);
4404 if (value) {
4405 mmc->caps |= MMC_CAP_NEEDS_POLL;
4406 mmc_detect_change(host->mmc, 0);
4407 } else {
4408 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4409 }
4410#ifdef CONFIG_HAS_EARLYSUSPEND
4411 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4412#endif
4413 spin_unlock_irqrestore(&host->lock, flags);
4414 return count;
4415}
4416
4417static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4418 show_polling, set_polling);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304419
4420static ssize_t
4421show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4422 char *buf)
4423{
4424 struct mmc_host *mmc = dev_get_drvdata(dev);
4425 struct msmsdcc_host *host = mmc_priv(mmc);
4426
4427 return snprintf(buf, PAGE_SIZE, "%u\n",
4428 host->msm_bus_vote.is_max_bw_needed);
4429}
4430
4431static ssize_t
4432set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4433 const char *buf, size_t count)
4434{
4435 struct mmc_host *mmc = dev_get_drvdata(dev);
4436 struct msmsdcc_host *host = mmc_priv(mmc);
4437 uint32_t value;
4438 unsigned long flags;
4439
4440 if (!kstrtou32(buf, 0, &value)) {
4441 spin_lock_irqsave(&host->lock, flags);
4442 host->msm_bus_vote.is_max_bw_needed = !!value;
4443 spin_unlock_irqrestore(&host->lock, flags);
4444 }
4445
4446 return count;
4447}
4448
4449static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
4450 show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
4451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004452static struct attribute *dev_attrs[] = {
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304453 &dev_attr_max_bus_bw.attr,
4454 /* if polling is enabled, this will be filled with dev_attr_polling */
4455 NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004456 NULL,
4457};
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304458
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004459static struct attribute_group dev_attr_grp = {
4460 .attrs = dev_attrs,
4461};
4462
4463#ifdef CONFIG_HAS_EARLYSUSPEND
4464static void msmsdcc_early_suspend(struct early_suspend *h)
4465{
4466 struct msmsdcc_host *host =
4467 container_of(h, struct msmsdcc_host, early_suspend);
4468 unsigned long flags;
4469
4470 spin_lock_irqsave(&host->lock, flags);
4471 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4472 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4473 spin_unlock_irqrestore(&host->lock, flags);
4474};
4475static void msmsdcc_late_resume(struct early_suspend *h)
4476{
4477 struct msmsdcc_host *host =
4478 container_of(h, struct msmsdcc_host, early_suspend);
4479 unsigned long flags;
4480
4481 if (host->polling_enabled) {
4482 spin_lock_irqsave(&host->lock, flags);
4483 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4484 mmc_detect_change(host->mmc, 0);
4485 spin_unlock_irqrestore(&host->lock, flags);
4486 }
4487};
4488#endif
4489
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304490static void msmsdcc_print_regs(const char *name, void __iomem *base,
4491 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304492{
4493 unsigned int i;
4494
4495 if (!base)
4496 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304497
4498 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4499 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304500 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304501 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4502 (u32)readl_relaxed(base + i*4),
4503 (u32)readl_relaxed(base + ((i+1)*4)),
4504 (u32)readl_relaxed(base + ((i+2)*4)),
4505 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304506 }
4507}
4508
4509static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4510{
4511 /* Dump current state of SDCC clocks, power and irq */
4512 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304513 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304514 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304515 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4516 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304517 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4518 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4519
4520 /* Now dump SDCC registers. Don't print FIFO registers */
4521 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304522 msmsdcc_print_regs("SDCC-CORE", host->base,
4523 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304524
4525 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304526 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304527 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4528 else if (host->is_dma_mode)
4529 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4530 mmc_hostname(host->mmc), host->dma.busy,
4531 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304532 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304533 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304534 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4535 host->dml_memres->start,
4536 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304537 pr_info("%s: SPS mode: busy=%d\n",
4538 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304539 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304540
4541 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4542 mmc_hostname(host->mmc), host->curr.xfer_size,
4543 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304544 }
4545
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304546 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304547 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4548 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4549 host->curr.got_dataend, host->prog_enable,
4550 host->curr.wait_for_auto_prog_done,
4551 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304552 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304553}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004555static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4556{
4557 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4558 struct mmc_request *mrq;
4559 unsigned long flags;
4560
4561 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004562 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004563 pr_info("%s: %s: dummy CMD52 timeout\n",
4564 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004565 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566 }
4567
4568 mrq = host->curr.mrq;
4569
4570 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304571 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4572 mrq->cmd->opcode);
4573 msmsdcc_dump_sdcc_state(host);
4574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004575 if (!mrq->cmd->error)
4576 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304577 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004578 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004579 if (mrq->data && !mrq->data->error)
4580 mrq->data->error = -ETIMEDOUT;
4581 host->curr.data_xfered = 0;
4582 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004583 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584 } else if (host->sps.sg && host->is_sps_mode) {
4585 /* Stop current SPS transfer */
4586 msmsdcc_sps_exit_curr_xfer(host);
4587 } else {
4588 msmsdcc_reset_and_restore(host);
4589 msmsdcc_stop_data(host);
4590 if (mrq->data && mrq->data->stop)
4591 msmsdcc_start_command(host,
4592 mrq->data->stop, 0);
4593 else
4594 msmsdcc_request_end(host, mrq);
4595 }
4596 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304597 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304598 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004599 msmsdcc_reset_and_restore(host);
4600 msmsdcc_request_end(host, mrq);
4601 }
4602 }
4603 spin_unlock_irqrestore(&host->lock, flags);
4604}
4605
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304606static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4607{
4608 int i, ret;
4609 struct mmc_platform_data *pdata;
4610 struct device_node *np = dev->of_node;
4611 u32 bus_width = 0;
4612 u32 *clk_table;
4613 int clk_table_len;
4614 u32 *sup_voltages;
4615 int sup_volt_len;
4616
4617 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4618 if (!pdata) {
4619 dev_err(dev, "could not allocate memory for platform data\n");
4620 goto err;
4621 }
4622
4623 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4624 if (bus_width == 8) {
4625 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4626 } else if (bus_width == 4) {
4627 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4628 } else {
4629 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4630 pdata->mmc_bus_width = 0;
4631 }
4632
4633 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4634 size_t sz;
4635 sz = sup_volt_len / sizeof(*sup_voltages);
4636 if (sz > 0) {
4637 sup_voltages = devm_kzalloc(dev,
4638 sz * sizeof(*sup_voltages), GFP_KERNEL);
4639 if (!sup_voltages) {
4640 dev_err(dev, "No memory for supported voltage\n");
4641 goto err;
4642 }
4643
4644 ret = of_property_read_u32_array(np,
4645 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4646 if (ret < 0) {
4647 dev_err(dev, "error while reading voltage"
4648 "ranges %d\n", ret);
4649 goto err;
4650 }
4651 } else {
4652 dev_err(dev, "No supported voltages\n");
4653 goto err;
4654 }
4655 for (i = 0; i < sz; i += 2) {
4656 u32 mask;
4657
4658 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4659 sup_voltages[i + 1]);
4660 if (!mask)
4661 dev_err(dev, "Invalide voltage range %d\n", i);
4662 pdata->ocr_mask |= mask;
4663 }
4664 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4665 } else {
4666 dev_err(dev, "Supported voltage range not specified\n");
4667 }
4668
4669 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4670 size_t sz;
4671 sz = clk_table_len / sizeof(*clk_table);
4672
4673 if (sz > 0) {
4674 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4675 GFP_KERNEL);
4676 if (!clk_table) {
4677 dev_err(dev, "No memory for clock table\n");
4678 goto err;
4679 }
4680
4681 ret = of_property_read_u32_array(np,
4682 "qcom,sdcc-clk-rates", clk_table, sz);
4683 if (ret < 0) {
4684 dev_err(dev, "error while reading clk"
4685 "table %d\n", ret);
4686 goto err;
4687 }
4688 } else {
4689 dev_err(dev, "clk_table not specified\n");
4690 goto err;
4691 }
4692 pdata->sup_clk_table = clk_table;
4693 pdata->sup_clk_cnt = sz;
4694 } else {
4695 dev_err(dev, "Supported clock rates not specified\n");
4696 }
4697
4698 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4699 pdata->nonremovable = true;
4700 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4701 pdata->disable_cmd23 = true;
4702
4703 return pdata;
4704err:
4705 return NULL;
4706}
4707
San Mehat9d2bd732009-09-22 16:44:22 -07004708static int
4709msmsdcc_probe(struct platform_device *pdev)
4710{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304711 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004712 struct msmsdcc_host *host;
4713 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004714 unsigned long flags;
4715 struct resource *core_irqres = NULL;
4716 struct resource *bam_irqres = NULL;
4717 struct resource *core_memres = NULL;
4718 struct resource *dml_memres = NULL;
4719 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004720 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004721 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304722 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004723 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004724
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304725 if (pdev->dev.of_node) {
4726 plat = msmsdcc_populate_pdata(&pdev->dev);
4727 of_property_read_u32((&pdev->dev)->of_node,
4728 "cell-index", &pdev->id);
4729 } else {
4730 plat = pdev->dev.platform_data;
4731 }
4732
San Mehat9d2bd732009-09-22 16:44:22 -07004733 /* must have platform data */
4734 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004735 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004736 ret = -EINVAL;
4737 goto out;
4738 }
4739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004741 return -EINVAL;
4742
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304743 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4744 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4745 return -EINVAL;
4746 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004747
San Mehat9d2bd732009-09-22 16:44:22 -07004748 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004749 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004750 return -ENXIO;
4751 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304752 if (pdev->dev.of_node) {
4753 /*
4754 * Device tree iomem resources are only accessible by index.
4755 * index = 0 -> SDCC register interface
4756 * index = 1 -> DML register interface
4757 * index = 2 -> BAM register interface
4758 * IRQ resources:
4759 * index = 0 -> SDCC IRQ
4760 * index = 1 -> BAM IRQ
4761 */
4762 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4763 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4764 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4765 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4766 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4767 } else {
4768 for (i = 0; i < pdev->num_resources; i++) {
4769 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4770 if (!strncmp(pdev->resource[i].name,
4771 "sdcc_dml_addr",
4772 sizeof("sdcc_dml_addr")))
4773 dml_memres = &pdev->resource[i];
4774 else if (!strncmp(pdev->resource[i].name,
4775 "sdcc_bam_addr",
4776 sizeof("sdcc_bam_addr")))
4777 bam_memres = &pdev->resource[i];
4778 else
4779 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004780
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304781 }
4782 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4783 if (!strncmp(pdev->resource[i].name,
4784 "sdcc_bam_irq",
4785 sizeof("sdcc_bam_irq")))
4786 bam_irqres = &pdev->resource[i];
4787 else
4788 core_irqres = &pdev->resource[i];
4789 }
4790 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4791 if (!strncmp(pdev->resource[i].name,
4792 "sdcc_dma_chnl",
4793 sizeof("sdcc_dma_chnl")))
4794 dmares = &pdev->resource[i];
4795 else if (!strncmp(pdev->resource[i].name,
4796 "sdcc_dma_crci",
4797 sizeof("sdcc_dma_crci")))
4798 dma_crci_res = &pdev->resource[i];
4799 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004800 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004801 }
4802
4803 if (!core_irqres || !core_memres) {
4804 pr_err("%s: Invalid sdcc core resource\n", __func__);
4805 return -ENXIO;
4806 }
4807
4808 /*
4809 * Both BAM and DML memory resource should be preset.
4810 * BAM IRQ resource should also be present.
4811 */
4812 if ((bam_memres && !dml_memres) ||
4813 (!bam_memres && dml_memres) ||
4814 ((bam_memres && dml_memres) && !bam_irqres)) {
4815 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004816 return -ENXIO;
4817 }
4818
4819 /*
4820 * Setup our host structure
4821 */
San Mehat9d2bd732009-09-22 16:44:22 -07004822 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4823 if (!mmc) {
4824 ret = -ENOMEM;
4825 goto out;
4826 }
4827
4828 host = mmc_priv(mmc);
4829 host->pdev_id = pdev->id;
4830 host->plat = plat;
4831 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004832 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304833
4834 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004835 host->is_sps_mode = 1;
4836 else if (dmares)
4837 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004839 host->base = ioremap(core_memres->start,
4840 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004841 if (!host->base) {
4842 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004843 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004844 }
4845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004846 host->core_irqres = core_irqres;
4847 host->bam_irqres = bam_irqres;
4848 host->core_memres = core_memres;
4849 host->dml_memres = dml_memres;
4850 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004851 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004852 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004853 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304854 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004856#ifdef CONFIG_MMC_EMBEDDED_SDIO
4857 if (plat->embedded_sdio)
4858 mmc_set_embedded_sdio_data(mmc,
4859 &plat->embedded_sdio->cis,
4860 &plat->embedded_sdio->cccr,
4861 plat->embedded_sdio->funcs,
4862 plat->embedded_sdio->num_funcs);
4863#endif
4864
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304865 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4866 (unsigned long)host);
4867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004868 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4869 (unsigned long)host);
4870 if (host->is_dma_mode) {
4871 /* Setup DMA */
4872 ret = msmsdcc_init_dma(host);
4873 if (ret)
4874 goto ioremap_free;
4875 } else {
4876 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004877 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004878 }
4879
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004880 /*
4881 * Setup SDCC clock if derived from Dayatona
4882 * fabric core clock.
4883 */
4884 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004885 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004886 if (!IS_ERR(host->dfab_pclk)) {
4887 /* Set the clock rate to 64MHz for max. performance */
4888 ret = clk_set_rate(host->dfab_pclk, 64000000);
4889 if (ret)
4890 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304891 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004892 if (ret)
4893 goto dfab_pclk_put;
4894 } else
4895 goto dma_free;
4896 }
4897
4898 /*
4899 * Setup main peripheral bus clock
4900 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004901 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004902 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304903 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004904 if (ret)
4905 goto pclk_put;
4906
4907 host->pclk_rate = clk_get_rate(host->pclk);
4908 }
4909
4910 /*
4911 * Setup SDC MMC clock
4912 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004913 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004914 if (IS_ERR(host->clk)) {
4915 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004916 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004917 }
4918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004919 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4920 if (ret) {
4921 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4922 goto clk_put;
4923 }
4924
Asutosh Dasf5298c32012-04-03 14:51:47 +05304925 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004926 if (ret)
4927 goto clk_put;
4928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004929 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304930 if (!host->clk_rate)
4931 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304932
4933 /*
4934 * Lookup the Controller Version, to identify the supported features
4935 * Version number read as 0 would indicate SDCC3 or earlier versions
4936 */
4937 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4938 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4939 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304940 /*
4941 * Set the register write delay according to min. clock frequency
4942 * supported and update later when the host->clk_rate changes.
4943 */
4944 host->reg_write_delay =
4945 (1 + ((3 * USEC_PER_SEC) /
4946 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947
4948 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304949 /* Apply Hard reset to SDCC to put it in power on default state */
4950 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004952#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304953 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004954 if (host->plat->cpu_dma_latency)
4955 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4956 else
4957 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4958 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304959 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4960
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304961 ret = msmsdcc_msm_bus_register(host);
4962 if (ret)
4963 goto pm_qos_remove;
4964
4965 if (host->msm_bus_vote.client_handle)
4966 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4967 msmsdcc_msm_bus_work);
4968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004969 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004970 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004971 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004972 goto clk_disable;
4973 }
4974
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004975
4976 /* Clocks has to be running before accessing SPS/DML HW blocks */
4977 if (host->is_sps_mode) {
4978 /* Initialize SPS */
4979 ret = msmsdcc_sps_init(host);
4980 if (ret)
4981 goto vreg_deinit;
4982 /* Initialize DML */
4983 ret = msmsdcc_dml_init(host);
4984 if (ret)
4985 goto sps_exit;
4986 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304987 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004988
San Mehat9d2bd732009-09-22 16:44:22 -07004989 /*
4990 * Setup MMC host structure
4991 */
4992 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004993 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4994 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004995 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004996 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4997 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004998
San Mehat9d2bd732009-09-22 16:44:22 -07004999 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05305000 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305001
5002 /*
5003 * If we send the CMD23 before multi block write/read command
5004 * then we need not to send CMD12 at the end of the transfer.
5005 * If we don't send the CMD12 then only way to detect the PROG_DONE
5006 * status is to use the AUTO_PROG_DONE status provided by SDCC4
5007 * controller. So let's enable the CMD23 for SDCC4 only.
5008 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05305009 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05305010 mmc->caps |= MMC_CAP_CMD23;
5011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005012 mmc->caps |= plat->uhs_caps;
5013 /*
5014 * XPC controls the maximum current in the default speed mode of SDXC
5015 * card. XPC=0 means 100mA (max.) but speed class is not supported.
5016 * XPC=1 means 150mA (max.) and speed class is supported.
5017 */
5018 if (plat->xpc_cap)
5019 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5020 MMC_CAP_SET_XPC_180);
5021
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305022 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05305023 if (pdev->dev.of_node) {
5024 if (of_get_property((&pdev->dev)->of_node,
5025 "qcom,sdcc-hs200", NULL))
5026 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5027 }
5028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005029 if (plat->nonremovable)
5030 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005031 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005032
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005033 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035 if (plat->is_sdio_al_client)
5036 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005037
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305038 mmc->max_segs = msmsdcc_get_nr_sg(host);
5039 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5040 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005041
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305042 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05305043 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07005044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005045 writel_relaxed(0, host->base + MMCIMASK0);
5046 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305047 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005049 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5050 mb();
5051 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005053 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5054 DRIVER_NAME " (cmd)", host);
5055 if (ret)
5056 goto dml_exit;
5057
5058 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5059 DRIVER_NAME " (pio)", host);
5060 if (ret)
5061 goto irq_free;
5062
5063 /*
5064 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5065 * IRQ is un-necessarily being monitored by MPM (Modem power
5066 * management block) during idle-power collapse. The MPM will be
5067 * configured to monitor the DATA1 GPIO line with level-low trigger
5068 * and thus depending on the GPIO status, it prevents TCXO shutdown
5069 * during idle-power collapse.
5070 */
5071 disable_irq(core_irqres->start);
5072 host->sdcc_irq_disabled = 1;
5073
5074 if (plat->sdiowakeup_irq) {
5075 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5076 mmc_hostname(mmc));
5077 ret = request_irq(plat->sdiowakeup_irq,
5078 msmsdcc_platform_sdiowakeup_irq,
5079 IRQF_SHARED | IRQF_TRIGGER_LOW,
5080 DRIVER_NAME "sdiowakeup", host);
5081 if (ret) {
5082 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5083 plat->sdiowakeup_irq, ret);
5084 goto pio_irq_free;
5085 } else {
5086 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305087 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305089 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005090 }
5091 spin_unlock_irqrestore(&host->lock, flags);
5092 }
5093 }
5094
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305095 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005096 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5097 mmc_hostname(mmc));
5098 }
5099
5100 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5101 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005102 /*
5103 * Setup card detect change
5104 */
5105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005106 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005107 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005108 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005109 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005110 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08005111
Krishna Konda941604a2012-01-10 17:46:34 -08005112 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005113 }
San Mehat9d2bd732009-09-22 16:44:22 -07005114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005115 if (plat->status_irq) {
5116 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005117 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005118 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005119 DRIVER_NAME " (slot)",
5120 host);
5121 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005122 pr_err("Unable to get slot IRQ %d (%d)\n",
5123 plat->status_irq, ret);
5124 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005125 }
5126 } else if (plat->register_status_notify) {
5127 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5128 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005129 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005130 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005131
5132 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005133
5134 ret = pm_runtime_set_active(&(pdev)->dev);
5135 if (ret < 0)
5136 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5137 __func__, ret);
5138 /*
5139 * There is no notion of suspend/resume for SD/MMC/SDIO
5140 * cards. So host can be suspended/resumed with out
5141 * worrying about its children.
5142 */
5143 pm_suspend_ignore_children(&(pdev)->dev, true);
5144
5145 /*
5146 * MMC/SD/SDIO bus suspend/resume operations are defined
5147 * only for the slots that will be used for non-removable
5148 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5149 * defined. Otherwise, they simply become card removal and
5150 * insertion events during suspend and resume respectively.
5151 * Hence, enable run-time PM only for slots for which bus
5152 * suspend/resume operations are defined.
5153 */
5154#ifdef CONFIG_MMC_UNSAFE_RESUME
5155 /*
5156 * If this capability is set, MMC core will enable/disable host
5157 * for every claim/release operation on a host. We use this
5158 * notification to increment/decrement runtime pm usage count.
5159 */
5160 mmc->caps |= MMC_CAP_DISABLE;
5161 pm_runtime_enable(&(pdev)->dev);
5162#else
5163 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
5164 mmc->caps |= MMC_CAP_DISABLE;
5165 pm_runtime_enable(&(pdev)->dev);
5166 }
5167#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05305168#ifndef CONFIG_PM_RUNTIME
5169 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
5170#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005171 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5172 (unsigned long)host);
5173
San Mehat9d2bd732009-09-22 16:44:22 -07005174 mmc_add_host(mmc);
5175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005176#ifdef CONFIG_HAS_EARLYSUSPEND
5177 host->early_suspend.suspend = msmsdcc_early_suspend;
5178 host->early_suspend.resume = msmsdcc_late_resume;
5179 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5180 register_early_suspend(&host->early_suspend);
5181#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005182
Krishna Konda25786ec2011-07-25 16:21:36 -07005183 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5184 " dmacrcri %d\n", mmc_hostname(mmc),
5185 (unsigned long long)core_memres->start,
5186 (unsigned int) core_irqres->start,
5187 (unsigned int) plat->status_irq, host->dma.channel,
5188 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189
5190 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5191 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5192 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5193 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5194 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5195 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5196 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5197 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5198 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5199 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5200 host->eject);
5201 pr_info("%s: Power save feature enable = %d\n",
5202 mmc_hostname(mmc), msmsdcc_pwrsave);
5203
Krishna Konda25786ec2011-07-25 16:21:36 -07005204 if (host->is_dma_mode && host->dma.channel != -1
5205 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005206 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005207 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005208 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005209 mmc_hostname(mmc), host->dma.cmd_busaddr,
5210 host->dma.cmdptr_busaddr);
5211 } else if (host->is_sps_mode) {
5212 pr_info("%s: SPS-BAM data transfer mode available\n",
5213 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005214 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005215 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005217#if defined(CONFIG_DEBUG_FS)
5218 msmsdcc_dbg_createhost(host);
5219#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305220 if (!plat->status_irq)
5221 dev_attrs[1] = &dev_attr_polling.attr;
5222
5223 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
5224 if (ret)
5225 goto platform_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005226 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005227
5228 platform_irq_free:
5229 del_timer_sync(&host->req_tout_timer);
5230 pm_runtime_disable(&(pdev)->dev);
5231 pm_runtime_set_suspended(&(pdev)->dev);
5232
5233 if (plat->status_irq)
5234 free_irq(plat->status_irq, host);
5235 sdiowakeup_irq_free:
5236 wake_lock_destroy(&host->sdio_suspend_wlock);
5237 if (plat->sdiowakeup_irq)
5238 free_irq(plat->sdiowakeup_irq, host);
5239 pio_irq_free:
5240 if (plat->sdiowakeup_irq)
5241 wake_lock_destroy(&host->sdio_wlock);
5242 free_irq(core_irqres->start, host);
5243 irq_free:
5244 free_irq(core_irqres->start, host);
5245 dml_exit:
5246 if (host->is_sps_mode)
5247 msmsdcc_dml_exit(host);
5248 sps_exit:
5249 if (host->is_sps_mode)
5250 msmsdcc_sps_exit(host);
5251 vreg_deinit:
5252 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005253 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005254 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305255 msmsdcc_msm_bus_unregister(host);
5256 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005257 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305258 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005259 clk_put:
5260 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005261 pclk_disable:
5262 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305263 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005264 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005265 if (!IS_ERR(host->pclk))
5266 clk_put(host->pclk);
5267 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305268 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005269 dfab_pclk_put:
5270 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5271 clk_put(host->dfab_pclk);
5272 dma_free:
5273 if (host->is_dma_mode) {
5274 if (host->dmares)
5275 dma_free_coherent(NULL,
5276 sizeof(struct msmsdcc_nc_dmadata),
5277 host->dma.nc, host->dma.nc_busaddr);
5278 }
5279 ioremap_free:
5280 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005281 host_free:
5282 mmc_free_host(mmc);
5283 out:
5284 return ret;
5285}
5286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005287static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005288{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005289 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5290 struct mmc_platform_data *plat;
5291 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005293 if (!mmc)
5294 return -ENXIO;
5295
5296 if (pm_runtime_suspended(&(pdev)->dev))
5297 pm_runtime_resume(&(pdev)->dev);
5298
5299 host = mmc_priv(mmc);
5300
5301 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5302 plat = host->plat;
5303
5304 if (!plat->status_irq)
5305 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
5306
5307 del_timer_sync(&host->req_tout_timer);
5308 tasklet_kill(&host->dma_tlet);
5309 tasklet_kill(&host->sps.tlet);
5310 mmc_remove_host(mmc);
5311
5312 if (plat->status_irq)
5313 free_irq(plat->status_irq, host);
5314
5315 wake_lock_destroy(&host->sdio_suspend_wlock);
5316 if (plat->sdiowakeup_irq) {
5317 wake_lock_destroy(&host->sdio_wlock);
5318 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5319 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005320 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005321
5322 free_irq(host->core_irqres->start, host);
5323 free_irq(host->core_irqres->start, host);
5324
5325 clk_put(host->clk);
5326 if (!IS_ERR(host->pclk))
5327 clk_put(host->pclk);
5328 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5329 clk_put(host->dfab_pclk);
5330
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005331 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305332 pm_qos_remove_request(&host->pm_qos_req_dma);
5333
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305334 if (host->msm_bus_vote.client_handle) {
5335 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5336 msmsdcc_msm_bus_unregister(host);
5337 }
5338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005339 msmsdcc_vreg_init(host, false);
5340
5341 if (host->is_dma_mode) {
5342 if (host->dmares)
5343 dma_free_coherent(NULL,
5344 sizeof(struct msmsdcc_nc_dmadata),
5345 host->dma.nc, host->dma.nc_busaddr);
5346 }
5347
5348 if (host->is_sps_mode) {
5349 msmsdcc_dml_exit(host);
5350 msmsdcc_sps_exit(host);
5351 }
5352
5353 iounmap(host->base);
5354 mmc_free_host(mmc);
5355
5356#ifdef CONFIG_HAS_EARLYSUSPEND
5357 unregister_early_suspend(&host->early_suspend);
5358#endif
5359 pm_runtime_disable(&(pdev)->dev);
5360 pm_runtime_set_suspended(&(pdev)->dev);
5361
5362 return 0;
5363}
5364
5365#ifdef CONFIG_MSM_SDIO_AL
5366int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5367{
5368 struct msmsdcc_host *host = mmc_priv(mmc);
5369 unsigned long flags;
5370
Asutosh Dasf5298c32012-04-03 14:51:47 +05305371 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005372 spin_lock_irqsave(&host->lock, flags);
5373 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5374 enable ? "En" : "Dis");
5375
5376 if (enable) {
5377 if (!host->sdcc_irq_disabled) {
5378 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305379 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005380 host->sdcc_irq_disabled = 1;
5381 }
5382
5383 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305384 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005385 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305386 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005387 host->clks_on = 0;
5388 }
5389
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305390 if (host->plat->sdio_lpm_gpio_setup &&
5391 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005392 spin_unlock_irqrestore(&host->lock, flags);
5393 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5394 spin_lock_irqsave(&host->lock, flags);
5395 host->sdio_gpio_lpm = 1;
5396 }
5397
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305398 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005399 msmsdcc_enable_irq_wake(host);
5400 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305401 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005402 }
5403 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305404 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005405 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305406 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005407 msmsdcc_disable_irq_wake(host);
5408 }
5409
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305410 if (host->plat->sdio_lpm_gpio_setup &&
5411 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005412 spin_unlock_irqrestore(&host->lock, flags);
5413 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5414 spin_lock_irqsave(&host->lock, flags);
5415 host->sdio_gpio_lpm = 0;
5416 }
5417
5418 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305419 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005420 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305421 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005422 host->clks_on = 1;
5423 }
5424
5425 if (host->sdcc_irq_disabled) {
5426 writel_relaxed(host->mci_irqenable,
5427 host->base + MMCIMASK0);
5428 mb();
5429 enable_irq(host->core_irqres->start);
5430 host->sdcc_irq_disabled = 0;
5431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005432 }
5433 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305434 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005435 return 0;
5436}
5437#else
5438int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5439{
5440 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005441}
5442#endif
5443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005444#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005445static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005446msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005447{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005448 struct mmc_host *mmc = dev_get_drvdata(dev);
5449 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005450 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305451 unsigned long flags;
5452
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305453 if (host->plat->is_sdio_al_client) {
5454 rc = 0;
5455 goto out;
5456 }
San Mehat9d2bd732009-09-22 16:44:22 -07005457
Sahitya Tummala7661a452011-07-18 13:28:35 +05305458 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005459 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005460 host->sdcc_suspending = 1;
5461 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005463 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005464 * MMC core thinks that host is disabled by now since
5465 * runtime suspend is scheduled after msmsdcc_disable()
5466 * is called. Thus, MMC core will try to enable the host
5467 * while suspending it. This results in a synchronous
5468 * runtime resume request while in runtime suspending
5469 * context and hence inorder to complete this resume
5470 * requet, it will wait for suspend to be complete,
5471 * but runtime suspend also can not proceed further
5472 * until the host is resumed. Thus, it leads to a hang.
5473 * Hence, increase the pm usage count before suspending
5474 * the host so that any resume requests after this will
5475 * simple become pm usage counter increment operations.
5476 */
5477 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305478 /* If there is pending detect work abort runtime suspend */
5479 if (unlikely(work_busy(&mmc->detect.work)))
5480 rc = -EAGAIN;
5481 else
5482 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005483 pm_runtime_put_noidle(dev);
5484
5485 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305486 spin_lock_irqsave(&host->lock, flags);
5487 host->sdcc_suspended = true;
5488 spin_unlock_irqrestore(&host->lock, flags);
5489 if (mmc->card && mmc_card_sdio(mmc->card) &&
5490 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005491 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305492 * If SDIO function driver doesn't want
5493 * to power off the card, atleast turn off
5494 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005495 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305496 mmc_host_clk_hold(mmc);
5497 spin_lock_irqsave(&mmc->clk_lock, flags);
5498 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005499 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305500 mmc->clk_gated = true;
5501 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5502 mmc_set_ios(mmc);
5503 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005504 }
5505 }
5506 host->sdcc_suspending = 0;
5507 mmc->suspend_task = NULL;
5508 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5509 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005510 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305511 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305512out:
5513 /* set bus bandwidth to 0 immediately */
5514 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005515 return rc;
5516}
5517
5518static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005519msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005520{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005521 struct mmc_host *mmc = dev_get_drvdata(dev);
5522 struct msmsdcc_host *host = mmc_priv(mmc);
5523 unsigned long flags;
5524
5525 if (host->plat->is_sdio_al_client)
5526 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005527
Sahitya Tummala7661a452011-07-18 13:28:35 +05305528 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005529 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305530 if (mmc->card && mmc_card_sdio(mmc->card) &&
5531 mmc_card_keep_power(mmc)) {
5532 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305533 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305534 mmc_set_ios(mmc);
5535 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305536 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005537
5538 mmc_resume_host(mmc);
5539
5540 /*
5541 * FIXME: Clearing of flags must be handled in clients
5542 * resume handler.
5543 */
5544 spin_lock_irqsave(&host->lock, flags);
5545 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305546 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005547 spin_unlock_irqrestore(&host->lock, flags);
5548
5549 /*
5550 * After resuming the host wait for sometime so that
5551 * the SDIO work will be processed.
5552 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305553 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305554 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005555 host->plat->sdiowakeup_irq) &&
5556 wake_lock_active(&host->sdio_wlock))
5557 wake_lock_timeout(&host->sdio_wlock, 1);
5558 }
5559
5560 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005561 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305562 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005563 return 0;
5564}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005565
5566static int msmsdcc_runtime_idle(struct device *dev)
5567{
5568 struct mmc_host *mmc = dev_get_drvdata(dev);
5569 struct msmsdcc_host *host = mmc_priv(mmc);
5570
5571 if (host->plat->is_sdio_al_client)
5572 return 0;
5573
5574 /* Idle timeout is not configurable for now */
5575 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5576
5577 return -EAGAIN;
5578}
5579
5580static int msmsdcc_pm_suspend(struct device *dev)
5581{
5582 struct mmc_host *mmc = dev_get_drvdata(dev);
5583 struct msmsdcc_host *host = mmc_priv(mmc);
5584 int rc = 0;
5585
5586 if (host->plat->is_sdio_al_client)
5587 return 0;
5588
5589
5590 if (host->plat->status_irq)
5591 disable_irq(host->plat->status_irq);
5592
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005593 if (!pm_runtime_suspended(dev))
5594 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005595
5596 return rc;
5597}
5598
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305599static int msmsdcc_suspend_noirq(struct device *dev)
5600{
5601 struct mmc_host *mmc = dev_get_drvdata(dev);
5602 struct msmsdcc_host *host = mmc_priv(mmc);
5603 int rc = 0;
5604
5605 /*
5606 * After platform suspend there may be active request
5607 * which might have enabled clocks. For example, in SDIO
5608 * case, ksdioirq thread might have scheduled after sdcc
5609 * suspend but before system freeze. In that case abort
5610 * suspend and retry instead of keeping the clocks on
5611 * during suspend and not allowing TCXO.
5612 */
5613
Asutosh Dasf5298c32012-04-03 14:51:47 +05305614 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305615 pr_warn("%s: clocks are on after suspend, aborting system "
5616 "suspend\n", mmc_hostname(mmc));
5617 rc = -EAGAIN;
5618 }
5619
5620 return rc;
5621}
5622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005623static int msmsdcc_pm_resume(struct device *dev)
5624{
5625 struct mmc_host *mmc = dev_get_drvdata(dev);
5626 struct msmsdcc_host *host = mmc_priv(mmc);
5627 int rc = 0;
5628
5629 if (host->plat->is_sdio_al_client)
5630 return 0;
5631
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005632 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305633 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005634 else
5635 host->pending_resume = true;
5636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005637 if (host->plat->status_irq) {
5638 msmsdcc_check_status((unsigned long)host);
5639 enable_irq(host->plat->status_irq);
5640 }
5641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005642 return rc;
5643}
5644
Daniel Walker08ecfde2010-06-23 12:32:20 -07005645#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005646static int msmsdcc_runtime_suspend(struct device *dev)
5647{
5648 return 0;
5649}
5650static int msmsdcc_runtime_idle(struct device *dev)
5651{
5652 return 0;
5653}
5654static int msmsdcc_pm_suspend(struct device *dev)
5655{
5656 return 0;
5657}
5658static int msmsdcc_pm_resume(struct device *dev)
5659{
5660 return 0;
5661}
5662static int msmsdcc_suspend_noirq(struct device *dev)
5663{
5664 return 0;
5665}
5666static int msmsdcc_runtime_resume(struct device *dev)
5667{
5668 return 0;
5669}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005670#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005672static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5673 .runtime_suspend = msmsdcc_runtime_suspend,
5674 .runtime_resume = msmsdcc_runtime_resume,
5675 .runtime_idle = msmsdcc_runtime_idle,
5676 .suspend = msmsdcc_pm_suspend,
5677 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305678 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005679};
5680
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305681static const struct of_device_id msmsdcc_dt_match[] = {
5682 {.compatible = "qcom,msm-sdcc"},
5683
5684};
5685MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5686
San Mehat9d2bd732009-09-22 16:44:22 -07005687static struct platform_driver msmsdcc_driver = {
5688 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005689 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005690 .driver = {
5691 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005692 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305693 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005694 },
5695};
5696
5697static int __init msmsdcc_init(void)
5698{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005699#if defined(CONFIG_DEBUG_FS)
5700 int ret = 0;
5701 ret = msmsdcc_dbg_init();
5702 if (ret) {
5703 pr_err("Failed to create debug fs dir \n");
5704 return ret;
5705 }
5706#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005707 return platform_driver_register(&msmsdcc_driver);
5708}
5709
5710static void __exit msmsdcc_exit(void)
5711{
5712 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005713
5714#if defined(CONFIG_DEBUG_FS)
5715 debugfs_remove(debugfs_file);
5716 debugfs_remove(debugfs_dir);
5717#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005718}
5719
5720module_init(msmsdcc_init);
5721module_exit(msmsdcc_exit);
5722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005723MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005724MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005725
5726#if defined(CONFIG_DEBUG_FS)
5727
5728static int
5729msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5730{
5731 file->private_data = inode->i_private;
5732 return 0;
5733}
5734
5735static ssize_t
5736msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5737 size_t count, loff_t *ppos)
5738{
5739 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005740 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005741 int max, i;
5742
5743 i = 0;
5744 max = sizeof(buf) - 1;
5745
5746 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5747 host->curr.cmd, host->curr.data);
5748 if (host->curr.cmd) {
5749 struct mmc_command *cmd = host->curr.cmd;
5750
5751 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5752 cmd->opcode, cmd->arg, cmd->flags);
5753 }
5754 if (host->curr.data) {
5755 struct mmc_data *data = host->curr.data;
5756 i += scnprintf(buf + i, max - i,
5757 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5758 data->timeout_ns, data->timeout_clks,
5759 data->blksz, data->blocks, data->error,
5760 data->flags);
5761 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5762 host->curr.xfer_size, host->curr.xfer_remain,
5763 host->curr.data_xfered, host->dma.sg);
5764 }
5765
5766 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5767}
5768
5769static const struct file_operations msmsdcc_dbg_state_ops = {
5770 .read = msmsdcc_dbg_state_read,
5771 .open = msmsdcc_dbg_state_open,
5772};
5773
5774static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5775{
5776 if (debugfs_dir) {
5777 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5778 0644, debugfs_dir, host,
5779 &msmsdcc_dbg_state_ops);
5780 }
5781}
5782
5783static int __init msmsdcc_dbg_init(void)
5784{
5785 int err;
5786
5787 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5788 if (IS_ERR(debugfs_dir)) {
5789 err = PTR_ERR(debugfs_dir);
5790 debugfs_dir = NULL;
5791 return err;
5792 }
5793
5794 return 0;
5795}
5796#endif