blob: 4967c4e5e7cf575f52bbdaf4b9fa5d5c69b4dd58 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
Subhash Jadavani933e6a62011-12-26 18:05:04 +053046#include <linux/pm_qos_params.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/sdio_al.h>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053057#include <mach/mpm.h>
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053058#include <mach/msm_bus.h>
San Mehat9d2bd732009-09-22 16:44:22 -070059
San Mehat9d2bd732009-09-22 16:44:22 -070060#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070062
63#define DRIVER_NAME "msm-sdcc"
64
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065#define DBG(host, fmt, args...) \
66 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
67
68#define IRQ_DEBUG 0
69#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
70#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
71#define SPS_CONS_PERIPHERAL 0
72#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053073/* Use SPS only if transfer size is more than this macro */
74#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075
Subhash Jadavanibcd435f2012-04-24 18:26:49 +053076#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
77
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078#if defined(CONFIG_DEBUG_FS)
79static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
80static struct dentry *debugfs_dir;
81static struct dentry *debugfs_file;
82static int msmsdcc_dbg_init(void);
83#endif
84
Asutosh Dasaccacd42012-03-08 14:33:17 +053085static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
86 *data);
87
Subhash Jadavani8766e352011-11-30 11:30:32 +053088static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070089static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091static struct mmc_command dummy52cmd;
92static struct mmc_request dummy52mrq = {
93 .cmd = &dummy52cmd,
94 .data = NULL,
95 .stop = NULL,
96};
97static struct mmc_command dummy52cmd = {
98 .opcode = SD_IO_RW_DIRECT,
99 .flags = MMC_RSP_PRESENT,
100 .data = NULL,
101 .mrq = &dummy52mrq,
102};
103/*
104 * An array holding the Tuning pattern to compare with when
105 * executing a tuning cycle.
106 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530107static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
109 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
110 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
111 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
112};
San Mehat865c8062009-11-13 13:42:06 -0800113
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530114static const u32 tuning_block_128[] = {
115 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
116 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
117 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
118 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
119 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
120 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
121 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
122 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
123};
124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125#if IRQ_DEBUG == 1
126static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
127 "dattimeout", "txunderrun", "rxoverrun",
128 "cmdrespend", "cmdsent", "dataend", NULL,
129 "datablkend", "cmdactive", "txactive",
130 "rxactive", "txhalfempty", "rxhalffull",
131 "txfifofull", "rxfifofull", "txfifoempty",
132 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
133 "sdiointr", "progdone", "atacmdcompl",
134 "sdiointrope", "ccstimeout", NULL, NULL,
135 NULL, NULL, NULL };
136
137static void
138msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800139{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
143 for (i = 0; i < 32; i++) {
144 if (status & (1 << i))
145 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800148}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149#endif
San Mehat865c8062009-11-13 13:42:06 -0800150
San Mehat9d2bd732009-09-22 16:44:22 -0700151static void
152msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
153 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530154static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530155static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530156static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800157static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800158static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700159static int msmsdcc_runtime_resume(struct device *dev);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530160
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530161static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
162{
163 unsigned short ret = NR_SG;
164
165 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530166 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530167 } else { /* DMA or PIO mode */
168 if (NR_SG > MAX_NR_SG_DMA_PIO)
169 ret = MAX_NR_SG_DMA_PIO;
170 }
171
172 return ret;
173}
174
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530175/* Prevent idle power collapse(pc) while operating in peripheral mode */
176static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
177{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700178 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530179 return;
180
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530181 if (vote)
182 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700183 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530184 else
185 pm_qos_update_request(&host->pm_qos_req_dma,
186 PM_QOS_DEFAULT_VALUE);
187}
188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
190static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
191 struct msmsdcc_sps_ep_conn_data *ep);
192static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep);
194#else
195static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep,
197 bool is_producer) { return 0; }
198static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
199 struct msmsdcc_sps_ep_conn_data *ep) { }
200static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
201 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530202{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 return 0;
204}
205static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
206 struct msmsdcc_sps_ep_conn_data *ep)
207{
208 return 0;
209}
210static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
211static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
212#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530215 * Apply soft reset to all SDCC BAM pipes
216 *
217 * This function applies soft reset to SDCC BAM pipe.
218 *
219 * This function should be called to recover from error
220 * conditions encountered during CMD/DATA tranfsers with card.
221 *
222 * @host - Pointer to driver's host structure
223 *
224 */
225static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
226{
227 int rc;
228
229 /* Reset all SDCC BAM pipes */
230 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
231 if (rc)
232 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
233 mmc_hostname(host->mmc), rc);
234 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
235 if (rc)
236 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
237 mmc_hostname(host->mmc), rc);
238
239 /* Restore all BAM pipes connections */
240 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
241 if (rc)
242 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
243 mmc_hostname(host->mmc), rc);
244 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
245 if (rc)
246 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
247 mmc_hostname(host->mmc), rc);
248}
249
250/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 * Apply soft reset
252 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530253 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 *
255 * This function should be called to recover from error
256 * conditions encountered with CMD/DATA tranfsers with card.
257 *
258 * Soft reset should only be used with SDCC controller v4.
259 *
260 * @host - Pointer to driver's host structure
261 *
262 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530263static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 /*
266 * Reset SDCC controller's DPSM (data path state machine
267 * and CPSM (command path state machine).
268 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530270 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530272 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530273}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530274
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530275static void msmsdcc_hard_reset(struct msmsdcc_host *host)
276{
277 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530278
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530279 /* Reset the controller */
280 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
281 if (ret)
282 pr_err("%s: Clock assert failed at %u Hz"
283 " with err %d\n", mmc_hostname(host->mmc),
284 host->clk_rate, ret);
285
286 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
287 if (ret)
288 pr_err("%s: Clock deassert failed at %u Hz"
289 " with err %d\n", mmc_hostname(host->mmc),
290 host->clk_rate, ret);
291
Subhash Jadavanidd432952012-03-28 11:25:56 +0530292 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530293 /* Give some delay for clock reset to propogate to controller */
294 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530295}
296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
298{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530299 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530300 if (host->is_sps_mode) {
301 /* Reset DML first */
302 msmsdcc_dml_reset(host);
303 /*
304 * delay the SPS pipe reset in thread context as
305 * sps_connect/sps_disconnect APIs can be called
306 * only from non-atomic context.
307 */
308 host->sps.pipe_reset_pending = true;
309 }
310 mb();
311 msmsdcc_soft_reset(host);
312
313 pr_debug("%s: Applied soft reset to Controller\n",
314 mmc_hostname(host->mmc));
315
316 if (host->is_sps_mode)
317 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 } else {
319 /* Give Clock reset (hard reset) to controller */
320 u32 mci_clk = 0;
321 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322
323 /* Save the controller state */
324 mci_clk = readl_relaxed(host->base + MMCICLOCK);
325 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530326 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530329 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 pr_debug("%s: Controller has been reinitialized\n",
331 mmc_hostname(host->mmc));
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 /* Restore the contoller state */
334 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530335 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530337 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530339 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530341
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700342 if (host->dummy_52_needed)
343 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344}
345
346static int
San Mehat9d2bd732009-09-22 16:44:22 -0700347msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
348{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 int retval = 0;
350
San Mehat9d2bd732009-09-22 16:44:22 -0700351 BUG_ON(host->curr.data);
352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 del_timer(&host->req_tout_timer);
354
San Mehat9d2bd732009-09-22 16:44:22 -0700355 if (mrq->data)
356 mrq->data->bytes_xfered = host->curr.data_xfered;
357 if (mrq->cmd->error == -ETIMEDOUT)
358 mdelay(5);
359
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530360 /* Clear current request information as current request has ended */
361 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
362
San Mehat9d2bd732009-09-22 16:44:22 -0700363 /*
364 * Need to drop the host lock here; mmc_request_done may call
365 * back into the driver...
366 */
367 spin_unlock(&host->lock);
368 mmc_request_done(host->mmc, mrq);
369 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370
371 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700372}
373
374static void
375msmsdcc_stop_data(struct msmsdcc_host *host)
376{
San Mehat9d2bd732009-09-22 16:44:22 -0700377 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530378 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530379 host->curr.wait_for_auto_prog_done = 0;
380 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700381 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
382 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530383 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700384}
385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700387{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 return host->core_memres->start + MMCIFIFO;
389}
390
391static inline unsigned int msmsdcc_get_min_sup_clk_rate(
392 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530393
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395{
396 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530397 if (!host->sdcc_version)
398 udelay(host->reg_write_delay);
399 else if (readl_relaxed(host->base + MCI_STATUS2) &
400 MCI_MCLK_REG_WR_ACTIVE) {
401 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530402
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530403 start = ktime_get();
404 while (readl_relaxed(host->base + MCI_STATUS2) &
405 MCI_MCLK_REG_WR_ACTIVE) {
406 diff = ktime_sub(ktime_get(), start);
407 /* poll for max. 1 ms */
408 if (ktime_to_us(diff) > 1000) {
409 pr_warning("%s: previous reg. write is"
410 " still active\n",
411 mmc_hostname(host->mmc));
412 break;
413 }
414 }
415 }
San Mehat9d2bd732009-09-22 16:44:22 -0700416}
417
Subhash Jadavanidd432952012-03-28 11:25:56 +0530418static inline void msmsdcc_delay(struct msmsdcc_host *host)
419{
420 udelay(host->reg_write_delay);
421
422}
423
San Mehat56a8b5b2009-11-21 12:29:46 -0800424static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
426{
427 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530429 /*
430 * As after sending the command, we don't write any of the
431 * controller registers and just wait for the
432 * CMD_RESPOND_END/CMD_SENT/Command failure notication
433 * from Controller.
434 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800436}
437
438static void
439msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
440{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
444 writel_relaxed((unsigned int)host->curr.xfer_size,
445 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530447 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800448
San Mehat6ac9ea62009-12-02 17:24:58 -0800449 if (host->cmd_cmd) {
450 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800452 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800453}
454
San Mehat9d2bd732009-09-22 16:44:22 -0700455static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530456msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700457{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700459 unsigned long flags;
460 struct mmc_request *mrq;
461
462 spin_lock_irqsave(&host->lock, flags);
463 mrq = host->curr.mrq;
464 BUG_ON(!mrq);
465
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530466 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700467 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700468 goto out;
469 }
470
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530471 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700472 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700474 } else {
475 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530476 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700477 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530478 mmc_hostname(host->mmc), host->dma.result);
479 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700480 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530481 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530482 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 host->dma.err.flush[0], host->dma.err.flush[1],
484 host->dma.err.flush[2], host->dma.err.flush[3],
485 host->dma.err.flush[4],
486 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530487 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700488 if (!mrq->data->error)
489 mrq->data->error = -EIO;
490 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530491 if (!mrq->data->host_cookie)
492 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
493 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 if (host->curr.user_pages) {
496 struct scatterlist *sg = host->dma.sg;
497 int i;
498
499 for (i = 0; i < host->dma.num_ents; i++, sg++)
500 flush_dcache_page(sg_page(sg));
501 }
502
San Mehat9d2bd732009-09-22 16:44:22 -0700503 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800504 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700505
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530506 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
507 (host->curr.wait_for_auto_prog_done &&
508 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700509 /*
510 * If we've already gotten our DATAEND / DATABLKEND
511 * for this request, then complete it through here.
512 */
San Mehat9d2bd732009-09-22 16:44:22 -0700513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700515 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516 host->curr.xfer_remain -= host->curr.xfer_size;
517 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700518 if (host->dummy_52_needed) {
519 mrq->data->bytes_xfered = host->curr.data_xfered;
520 host->dummy_52_sent = 1;
521 msmsdcc_start_command(host, &dummy52cmd,
522 MCI_CPSM_PROGENA);
523 goto out;
524 }
525 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530526 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530527 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700528 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530530 /*
531 * Clear current request information as current
532 * request has ended
533 */
534 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700535 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536
San Mehat9d2bd732009-09-22 16:44:22 -0700537 mmc_request_done(host->mmc, mrq);
538 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530539 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
540 || !mrq->sbc)) {
541 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530542 }
San Mehat9d2bd732009-09-22 16:44:22 -0700543 }
544
545out:
546 spin_unlock_irqrestore(&host->lock, flags);
547 return;
548}
549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
551/**
552 * Callback notification from SPS driver
553 *
554 * This callback function gets triggered called from
555 * SPS driver when requested SPS data transfer is
556 * completed.
557 *
558 * SPS driver invokes this callback in BAM irq context so
559 * SDCC driver schedule a tasklet for further processing
560 * this callback notification at later point of time in
561 * tasklet context and immediately returns control back
562 * to SPS driver.
563 *
564 * @nofity - Pointer to sps event notify sturcture
565 *
566 */
567static void
568msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
569{
570 struct msmsdcc_host *host =
571 (struct msmsdcc_host *)
572 ((struct sps_event_notify *)notify)->user;
573
574 host->sps.notify = *notify;
575 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
576 mmc_hostname(host->mmc), __func__, notify->event_id,
577 notify->data.transfer.iovec.addr,
578 notify->data.transfer.iovec.size,
579 notify->data.transfer.iovec.flags);
580 /* Schedule a tasklet for completing data transfer */
581 tasklet_schedule(&host->sps.tlet);
582}
583
584/**
585 * Tasklet handler for processing SPS callback event
586 *
587 * This function processing SPS event notification and
588 * checks if the SPS transfer is completed or not and
589 * then accordingly notifies status to MMC core layer.
590 *
591 * This function is called in tasklet context.
592 *
593 * @data - Pointer to sdcc driver data
594 *
595 */
596static void msmsdcc_sps_complete_tlet(unsigned long data)
597{
598 unsigned long flags;
599 int i, rc;
600 u32 data_xfered = 0;
601 struct mmc_request *mrq;
602 struct sps_iovec iovec;
603 struct sps_pipe *sps_pipe_handle;
604 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
605 struct sps_event_notify *notify = &host->sps.notify;
606
607 spin_lock_irqsave(&host->lock, flags);
608 if (host->sps.dir == DMA_FROM_DEVICE)
609 sps_pipe_handle = host->sps.prod.pipe_handle;
610 else
611 sps_pipe_handle = host->sps.cons.pipe_handle;
612 mrq = host->curr.mrq;
613
614 if (!mrq) {
615 spin_unlock_irqrestore(&host->lock, flags);
616 return;
617 }
618
619 pr_debug("%s: %s: sps event_id=%d\n",
620 mmc_hostname(host->mmc), __func__,
621 notify->event_id);
622
623 if (msmsdcc_is_dml_busy(host)) {
624 /* oops !!! this should never happen. */
625 pr_err("%s: %s: Received SPS EOT event"
626 " but DML HW is still busy !!!\n",
627 mmc_hostname(host->mmc), __func__);
628 }
629 /*
630 * Got End of transfer event!!! Check if all of the data
631 * has been transferred?
632 */
633 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
634 rc = sps_get_iovec(sps_pipe_handle, &iovec);
635 if (rc) {
636 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
637 mmc_hostname(host->mmc), __func__, rc, i);
638 break;
639 }
640 data_xfered += iovec.size;
641 }
642
643 if (data_xfered == host->curr.xfer_size) {
644 host->curr.data_xfered = host->curr.xfer_size;
645 host->curr.xfer_remain -= host->curr.xfer_size;
646 pr_debug("%s: Data xfer success. data_xfered=0x%x",
647 mmc_hostname(host->mmc),
648 host->curr.xfer_size);
649 } else {
650 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
651 " xfer_size=%d", mmc_hostname(host->mmc),
652 data_xfered, host->curr.xfer_size);
653 msmsdcc_reset_and_restore(host);
654 if (!mrq->data->error)
655 mrq->data->error = -EIO;
656 }
657
658 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530659 if (!mrq->data->host_cookie)
660 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
661 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662 host->sps.sg = NULL;
663 host->sps.busy = 0;
664
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530665 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
666 (host->curr.wait_for_auto_prog_done &&
667 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668 /*
669 * If we've already gotten our DATAEND / DATABLKEND
670 * for this request, then complete it through here.
671 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672
673 if (!mrq->data->error) {
674 host->curr.data_xfered = host->curr.xfer_size;
675 host->curr.xfer_remain -= host->curr.xfer_size;
676 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700677 if (host->dummy_52_needed) {
678 mrq->data->bytes_xfered = host->curr.data_xfered;
679 host->dummy_52_sent = 1;
680 msmsdcc_start_command(host, &dummy52cmd,
681 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700682 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700683 return;
684 }
685 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530686 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530687 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 mrq->data->bytes_xfered = host->curr.data_xfered;
689 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530690 /*
691 * Clear current request information as current
692 * request has ended
693 */
694 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 spin_unlock_irqrestore(&host->lock, flags);
696
697 mmc_request_done(host->mmc, mrq);
698 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530699 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
700 || !mrq->sbc)) {
701 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 }
703 }
704 spin_unlock_irqrestore(&host->lock, flags);
705}
706
707/**
708 * Exit from current SPS data transfer
709 *
710 * This function exits from current SPS data transfer.
711 *
712 * This function should be called when error condition
713 * is encountered during data transfer.
714 *
715 * @host - Pointer to sdcc host structure
716 *
717 */
718static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
719{
720 struct mmc_request *mrq;
721
722 mrq = host->curr.mrq;
723 BUG_ON(!mrq);
724
725 msmsdcc_reset_and_restore(host);
726 if (!mrq->data->error)
727 mrq->data->error = -EIO;
728
729 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530730 if (!mrq->data->host_cookie)
731 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
732 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733
734 host->sps.sg = NULL;
735 host->sps.busy = 0;
736 if (host->curr.data)
737 msmsdcc_stop_data(host);
738
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530739 if (!mrq->data->stop || mrq->cmd->error ||
740 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530742 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
743 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 msmsdcc_start_command(host, mrq->data->stop, 0);
745
746}
747#else
748static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
749static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
750static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
751#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
752
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530753static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530755static void
756msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
757 unsigned int result,
758 struct msm_dmov_errdata *err)
759{
760 struct msmsdcc_dma_data *dma_data =
761 container_of(cmd, struct msmsdcc_dma_data, hdr);
762 struct msmsdcc_host *host = dma_data->host;
763
764 dma_data->result = result;
765 if (err)
766 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
767
768 tasklet_schedule(&host->dma_tlet);
769}
770
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530771static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
772 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700773{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530774 bool ret = true;
775 u32 xfer_size = data->blksz * data->blocks;
776
777 if (host->is_sps_mode) {
778 /*
779 * BAM Mode: Fall back on PIO if size is less
780 * than or equal to SPS_MIN_XFER_SIZE bytes.
781 */
782 if (xfer_size <= SPS_MIN_XFER_SIZE)
783 ret = false;
784 } else if (host->is_dma_mode) {
785 /*
786 * ADM Mode: Fall back on PIO if size is less than FIFO size
787 * or not integer multiple of FIFO size
788 */
789 if (xfer_size % MCI_FIFOSIZE)
790 ret = false;
791 } else {
792 /* PIO Mode */
793 ret = false;
794 }
795
796 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700797}
798
799static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
800{
801 struct msmsdcc_nc_dmadata *nc;
802 dmov_box *box;
803 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700804 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530805 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700806 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530807 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700808
Krishna Konda25786ec2011-07-25 16:21:36 -0700809 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700811
Krishna Konda25786ec2011-07-25 16:21:36 -0700812 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
813
San Mehat9d2bd732009-09-22 16:44:22 -0700814 host->dma.sg = data->sg;
815 host->dma.num_ents = data->sg_len;
816
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530817 /* Prevent memory corruption */
818 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800819
San Mehat9d2bd732009-09-22 16:44:22 -0700820 nc = host->dma.nc;
821
San Mehat9d2bd732009-09-22 16:44:22 -0700822 if (data->flags & MMC_DATA_READ)
823 host->dma.dir = DMA_FROM_DEVICE;
824 else
825 host->dma.dir = DMA_TO_DEVICE;
826
Asutosh Dasaccacd42012-03-08 14:33:17 +0530827 if (!data->host_cookie) {
828 n = msmsdcc_prep_xfer(host, data);
829 if (unlikely(n < 0)) {
830 host->dma.sg = NULL;
831 host->dma.num_ents = 0;
832 return -ENOMEM;
833 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800834 }
San Mehat9d2bd732009-09-22 16:44:22 -0700835
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530836 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
837 host->curr.user_pages = 0;
838 box = &nc->cmd[0];
839 for (i = 0; i < host->dma.num_ents; i++) {
840 len = sg_dma_len(sg);
841 offset = 0;
842
843 do {
844 /* Check if we can do DMA */
845 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
846 err = -ENOTSUPP;
847 goto unmap;
848 }
849
850 box->cmd = CMD_MODE_BOX;
851
852 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
853 len = MMC_MAX_DMA_BOX_LENGTH;
854 len -= len % data->blksz;
855 }
856 rows = (len % MCI_FIFOSIZE) ?
857 (len / MCI_FIFOSIZE) + 1 :
858 (len / MCI_FIFOSIZE);
859
860 if (data->flags & MMC_DATA_READ) {
861 box->src_row_addr = msmsdcc_fifo_addr(host);
862 box->dst_row_addr = sg_dma_address(sg) + offset;
863 box->src_dst_len = (MCI_FIFOSIZE << 16) |
864 (MCI_FIFOSIZE);
865 box->row_offset = MCI_FIFOSIZE;
866 box->num_rows = rows * ((1 << 16) + 1);
867 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
868 } else {
869 box->src_row_addr = sg_dma_address(sg) + offset;
870 box->dst_row_addr = msmsdcc_fifo_addr(host);
871 box->src_dst_len = (MCI_FIFOSIZE << 16) |
872 (MCI_FIFOSIZE);
873 box->row_offset = (MCI_FIFOSIZE << 16);
874 box->num_rows = rows * ((1 << 16) + 1);
875 box->cmd |= CMD_DST_CRCI(host->dma.crci);
876 }
877
878 offset += len;
879 len = sg_dma_len(sg) - offset;
880 box++;
881 box_cmd_cnt++;
882 } while (len);
883 sg++;
884 }
885 /* Mark last command */
886 box--;
887 box->cmd |= CMD_LC;
888
889 /* location of command block must be 64 bit aligned */
890 BUG_ON(host->dma.cmd_busaddr & 0x07);
891
892 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
893 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
894 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
895 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
896
897 /* Flush all data to memory before starting dma */
898 mb();
899
900unmap:
901 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530902 if (!data->host_cookie)
903 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
904 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530905 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
906 mmc_hostname(host->mmc), err);
907 }
908
909 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700910}
911
Asutosh Dasaccacd42012-03-08 14:33:17 +0530912static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
913 struct mmc_data *data)
914{
915 int rc = 0;
916 unsigned int dir;
917
918 /* Prevent memory corruption */
919 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
920
921 if (data->flags & MMC_DATA_READ)
922 dir = DMA_FROM_DEVICE;
923 else
924 dir = DMA_TO_DEVICE;
925
926 /* Make sg buffers DMA ready */
927 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
928 dir);
929
930 if (unlikely(rc != data->sg_len)) {
931 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
932 mmc_hostname(host->mmc), rc);
933 rc = -ENOMEM;
934 goto dma_map_err;
935 }
936
937 pr_debug("%s: %s: %s: sg_len=%d\n",
938 mmc_hostname(host->mmc), __func__,
939 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
940 data->sg_len);
941
942 goto out;
943
944dma_map_err:
945 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
946 data->flags);
947out:
948 return rc;
949}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
951/**
952 * Submits data transfer request to SPS driver
953 *
954 * This function make sg (scatter gather) data buffers
955 * DMA ready and then submits them to SPS driver for
956 * transfer.
957 *
958 * @host - Pointer to sdcc host structure
959 * @data - Pointer to mmc_data structure
960 *
961 * @return 0 if success else negative value
962 */
963static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +0530964 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800965{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 int rc = 0;
967 u32 flags;
968 int i;
969 u32 addr, len, data_cnt;
970 struct scatterlist *sg = data->sg;
971 struct sps_pipe *sps_pipe_handle;
972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 host->sps.sg = data->sg;
974 host->sps.num_ents = data->sg_len;
975 host->sps.xfer_req_cnt = 0;
976 if (data->flags & MMC_DATA_READ) {
977 host->sps.dir = DMA_FROM_DEVICE;
978 sps_pipe_handle = host->sps.prod.pipe_handle;
979 } else {
980 host->sps.dir = DMA_TO_DEVICE;
981 sps_pipe_handle = host->sps.cons.pipe_handle;
982 }
983
Asutosh Dasaccacd42012-03-08 14:33:17 +0530984 if (!data->host_cookie) {
985 rc = msmsdcc_prep_xfer(host, data);
986 if (unlikely(rc < 0)) {
987 host->dma.sg = NULL;
988 host->dma.num_ents = 0;
989 goto out;
990 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 }
992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 for (i = 0; i < data->sg_len; i++) {
994 /*
995 * Check if this is the last buffer to transfer?
996 * If yes then set the INT and EOT flags.
997 */
998 len = sg_dma_len(sg);
999 addr = sg_dma_address(sg);
1000 flags = 0;
1001 while (len > 0) {
1002 if (len > SPS_MAX_DESC_SIZE) {
1003 data_cnt = SPS_MAX_DESC_SIZE;
1004 } else {
1005 data_cnt = len;
1006 if (i == data->sg_len - 1)
1007 flags = SPS_IOVEC_FLAG_INT |
1008 SPS_IOVEC_FLAG_EOT;
1009 }
1010 rc = sps_transfer_one(sps_pipe_handle, addr,
1011 data_cnt, host, flags);
1012 if (rc) {
1013 pr_err("%s: sps_transfer_one() error! rc=%d,"
1014 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1015 mmc_hostname(host->mmc), rc,
1016 (u32)sps_pipe_handle, (u32)sg, i);
1017 goto dma_map_err;
1018 }
1019 addr += data_cnt;
1020 len -= data_cnt;
1021 host->sps.xfer_req_cnt++;
1022 }
1023 sg++;
1024 }
1025 goto out;
1026
1027dma_map_err:
1028 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301029 if (!data->host_cookie)
1030 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1031 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032out:
1033 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001034}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035#else
1036static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1037 struct mmc_data *data) { return 0; }
1038#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001039
1040static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001041msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1042 struct mmc_command *cmd, u32 *c)
1043{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301044 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 cmd->opcode, cmd->arg, cmd->flags);
1046
San Mehat56a8b5b2009-11-21 12:29:46 -08001047 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1048
1049 if (cmd->flags & MMC_RSP_PRESENT) {
1050 if (cmd->flags & MMC_RSP_136)
1051 *c |= MCI_CPSM_LONGRSP;
1052 *c |= MCI_CPSM_RESPONSE;
1053 }
1054
1055 if (/*interrupt*/0)
1056 *c |= MCI_CPSM_INTERRUPT;
1057
Asutosh Das05049132012-05-09 12:38:15 +05301058 /* DAT_CMD bit should be set for all ADTC */
1059 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001060 *c |= MCI_CSPM_DATCMD;
1061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301063 if (host->tuning_needed &&
1064 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1065
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301066 /*
1067 * For open ended block read operation (without CMD23),
1068 * AUTO_CMD19 bit should be set while sending the READ command.
1069 * For close ended block read operation (with CMD23),
1070 * AUTO_CMD19 bit should be set while sending CMD23.
1071 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301072 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1073 host->curr.mrq->cmd->opcode ==
1074 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301075 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301076 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1077 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301078 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1079 *c |= MCI_CSPM_AUTO_CMD19;
1080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 }
1082
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301083 /* Clear CDR_EN bit for write operations */
1084 if (host->tuning_needed && cmd->mrq->data &&
1085 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1086 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1087 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1088
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301089 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301090 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301092 }
1093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 if (cmd == cmd->mrq->stop)
1095 *c |= MCI_CSPM_MCIABORT;
1096
San Mehat56a8b5b2009-11-21 12:29:46 -08001097 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 pr_err("%s: Overlapping command requests\n",
1099 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001100 }
1101 host->curr.cmd = cmd;
1102}
1103
1104static void
1105msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1106 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001107{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301108 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001109 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001111 unsigned int pio_irqmask = 0;
1112
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301113 BUG_ON(!data->sg);
1114 BUG_ON(!data->sg_len);
1115
San Mehat9d2bd732009-09-22 16:44:22 -07001116 host->curr.data = data;
1117 host->curr.xfer_size = data->blksz * data->blocks;
1118 host->curr.xfer_remain = host->curr.xfer_size;
1119 host->curr.data_xfered = 0;
1120 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301121 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001122
San Mehat9d2bd732009-09-22 16:44:22 -07001123 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1124
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301125 if (host->curr.wait_for_auto_prog_done)
1126 datactrl |= MCI_AUTO_PROG_DONE;
1127
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301128 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1130 datactrl |= MCI_DPSM_DMAENABLE;
1131 } else if (host->is_sps_mode) {
1132 if (!msmsdcc_is_dml_busy(host)) {
1133 if (!msmsdcc_sps_start_xfer(host, data)) {
1134 /* Now kick start DML transfer */
1135 mb();
1136 msmsdcc_dml_start_xfer(host, data);
1137 datactrl |= MCI_DPSM_DMAENABLE;
1138 host->sps.busy = 1;
1139 }
1140 } else {
1141 /*
1142 * Can't proceed with new transfer as
1143 * previous trasnfer is already in progress.
1144 * There is no point of going into PIO mode
1145 * as well. Is this a time to do kernel panic?
1146 */
1147 pr_err("%s: %s: DML HW is busy!!!"
1148 " Can't perform new SPS transfers"
1149 " now\n", mmc_hostname(host->mmc),
1150 __func__);
1151 }
1152 }
1153 }
1154
1155 /* Is data transfer in PIO mode required? */
1156 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001157 if (data->flags & MMC_DATA_READ) {
1158 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1159 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1160 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001161 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1163 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001164
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001165 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001166 }
1167
1168 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301169 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
Subhash Jadavanif5277752011-10-12 16:47:52 +05301170 else if (host->curr.use_wr_data_pend)
1171 datactrl |= MCI_DATA_PEND;
San Mehat9d2bd732009-09-22 16:44:22 -07001172
San Mehat56a8b5b2009-11-21 12:29:46 -08001173 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001175 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1178 /* Use ADM (Application Data Mover) HW for Data transfer */
1179 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001180 host->cmd_timeout = timeout;
1181 host->cmd_pio_irqmask = pio_irqmask;
1182 host->cmd_datactrl = datactrl;
1183 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1186 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001187 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001188
1189 if (cmd) {
1190 msmsdcc_start_command_deferred(host, cmd, &c);
1191 host->cmd_c = c;
1192 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1194 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1195 host->base + MMCIMASK0);
1196 mb();
1197 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001198 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1205 (~(MCI_IRQ_PIO))) | pio_irqmask,
1206 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001208
1209 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301210 /* Delay between data/command */
1211 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001212 /* Daisy-chain the command if requested */
1213 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301214 } else {
1215 /*
1216 * We don't need delay after writing to DATA_CTRL
1217 * register if we are not writing to CMD register
1218 * immediately after this. As we already have delay
1219 * before sending the command, we just need mb() here.
1220 */
1221 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001222 }
San Mehat9d2bd732009-09-22 16:44:22 -07001223 }
1224}
1225
1226static void
1227msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1228{
San Mehat56a8b5b2009-11-21 12:29:46 -08001229 msmsdcc_start_command_deferred(host, cmd, &c);
1230 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001231}
1232
1233static void
1234msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1235 unsigned int status)
1236{
1237 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301239 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1240 || data->mrq->cmd->opcode ==
1241 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 pr_err("%s: Data CRC error\n",
1243 mmc_hostname(host->mmc));
1244 pr_err("%s: opcode 0x%.8x\n", __func__,
1245 data->mrq->cmd->opcode);
1246 pr_err("%s: blksz %d, blocks %d\n", __func__,
1247 data->blksz, data->blocks);
1248 data->error = -EILSEQ;
1249 }
San Mehat9d2bd732009-09-22 16:44:22 -07001250 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 /* CRC is optional for the bus test commands, not all
1252 * cards respond back with CRC. However controller
1253 * waits for the CRC and times out. Hence ignore the
1254 * data timeouts during the Bustest.
1255 */
1256 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1257 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301258 pr_err("%s: CMD%d: Data timeout\n",
1259 mmc_hostname(host->mmc),
1260 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301262 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 }
San Mehat9d2bd732009-09-22 16:44:22 -07001264 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001265 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001266 data->error = -EIO;
1267 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001268 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001269 data->error = -EIO;
1270 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001271 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001273 data->error = -EIO;
1274 }
San Mehat9d2bd732009-09-22 16:44:22 -07001275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001277 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 host->dummy_52_needed = 0;
1279}
San Mehat9d2bd732009-09-22 16:44:22 -07001280
1281static int
1282msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1283{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001285 uint32_t *ptr = (uint32_t *) buffer;
1286 int count = 0;
1287
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301288 if (remain % 4)
1289 remain = ((remain >> 2) + 1) << 2;
1290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1292
1293 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001294 ptr++;
1295 count += sizeof(uint32_t);
1296
1297 remain -= sizeof(uint32_t);
1298 if (remain == 0)
1299 break;
1300 }
1301 return count;
1302}
1303
1304static int
1305msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001307{
1308 void __iomem *base = host->base;
1309 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 while (readl_relaxed(base + MMCISTATUS) &
1313 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1314 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001315
San Mehat9d2bd732009-09-22 16:44:22 -07001316 count = min(remain, maxcnt);
1317
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301318 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1319 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001320 ptr += count;
1321 remain -= count;
1322
1323 if (remain == 0)
1324 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 }
1326 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001327
1328 return ptr - buffer;
1329}
1330
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001331/*
1332 * Copy up to a word (4 bytes) between a scatterlist
1333 * and a temporary bounce buffer when the word lies across
1334 * two pages. The temporary buffer can then be read to/
1335 * written from the FIFO once.
1336 */
1337static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1338{
1339 struct msmsdcc_pio_data *pio = &host->pio;
1340 unsigned int bytes_avail;
1341
1342 if (host->curr.data->flags & MMC_DATA_READ)
1343 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1344 pio->bounce_buf_len);
1345 else
1346 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1347 pio->bounce_buf_len);
1348
1349 while (pio->bounce_buf_len != 4) {
1350 if (!sg_miter_next(&pio->sg_miter))
1351 break;
1352 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1353 4 - pio->bounce_buf_len);
1354 if (host->curr.data->flags & MMC_DATA_READ)
1355 memcpy(pio->sg_miter.addr,
1356 &pio->bounce_buf[pio->bounce_buf_len],
1357 bytes_avail);
1358 else
1359 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1360 pio->sg_miter.addr, bytes_avail);
1361
1362 pio->sg_miter.consumed = bytes_avail;
1363 pio->bounce_buf_len += bytes_avail;
1364 }
1365}
1366
1367/*
1368 * Use sg_miter_next to return as many 4-byte aligned
1369 * chunks as possible, using a temporary 4 byte buffer
1370 * for alignment if necessary
1371 */
1372static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1373{
1374 struct msmsdcc_pio_data *pio = &host->pio;
1375 unsigned int length, rlength;
1376 char *buffer;
1377
1378 if (!sg_miter_next(&pio->sg_miter))
1379 return 0;
1380
1381 buffer = pio->sg_miter.addr;
1382 length = pio->sg_miter.length;
1383
1384 if (length < host->curr.xfer_remain) {
1385 rlength = round_down(length, 4);
1386 if (rlength) {
1387 /*
1388 * We have a 4-byte aligned chunk.
1389 * The rounding will be reflected by
1390 * a call to msmsdcc_sg_consumed
1391 */
1392 length = rlength;
1393 goto sg_next_end;
1394 }
1395 /*
1396 * We have a length less than 4 bytes. Check to
1397 * see if more buffer is available, and combine
1398 * to make 4 bytes if possible.
1399 */
1400 pio->bounce_buf_len = length;
1401 memset(pio->bounce_buf, 0, 4);
1402
1403 /*
1404 * On a read, get 4 bytes from FIFO, and distribute
1405 * (4-bouce_buf_len) bytes into consecutive
1406 * sgl buffers when msmsdcc_sg_consumed is called
1407 */
1408 if (host->curr.data->flags & MMC_DATA_READ) {
1409 buffer = pio->bounce_buf;
1410 length = 4;
1411 goto sg_next_end;
1412 } else {
1413 _msmsdcc_sg_consume_word(host);
1414 buffer = pio->bounce_buf;
1415 length = pio->bounce_buf_len;
1416 }
1417 }
1418
1419sg_next_end:
1420 *buf = buffer;
1421 *len = length;
1422 return 1;
1423}
1424
1425/*
1426 * Update sg_miter.consumed based on how many bytes were
1427 * consumed. If the bounce buffer was used to read from FIFO,
1428 * redistribute into sgls.
1429 */
1430static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1431 unsigned int length)
1432{
1433 struct msmsdcc_pio_data *pio = &host->pio;
1434
1435 if (host->curr.data->flags & MMC_DATA_READ) {
1436 if (length > pio->sg_miter.consumed)
1437 /*
1438 * consumed 4 bytes, but sgl
1439 * describes < 4 bytes
1440 */
1441 _msmsdcc_sg_consume_word(host);
1442 else
1443 pio->sg_miter.consumed = length;
1444 } else
1445 if (length < pio->sg_miter.consumed)
1446 pio->sg_miter.consumed = length;
1447}
1448
1449static void msmsdcc_sg_start(struct msmsdcc_host *host)
1450{
1451 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1452
1453 host->pio.bounce_buf_len = 0;
1454
1455 if (host->curr.data->flags & MMC_DATA_READ)
1456 sg_miter_flags |= SG_MITER_TO_SG;
1457 else
1458 sg_miter_flags |= SG_MITER_FROM_SG;
1459
1460 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1461 host->curr.data->sg_len, sg_miter_flags);
1462}
1463
1464static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1465{
1466 sg_miter_stop(&host->pio.sg_miter);
1467}
1468
San Mehat1cd22962010-02-03 12:59:29 -08001469static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001470msmsdcc_pio_irq(int irq, void *dev_id)
1471{
1472 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001474 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001475 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001476 unsigned int remain;
1477 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001478
Murali Palnati36448a42011-09-02 15:06:18 +05301479 spin_lock(&host->lock);
1480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301484 (MCI_IRQ_PIO)) == 0) {
1485 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488#if IRQ_DEBUG
1489 msmsdcc_print_status(host, "irq1-r", status);
1490#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001491 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001493 do {
1494 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1497 | MCI_RXDATAAVLBL)))
1498 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001499
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001500 if (!msmsdcc_sg_next(host, &buffer, &remain))
1501 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502
San Mehat9d2bd732009-09-22 16:44:22 -07001503 len = 0;
1504 if (status & MCI_RXACTIVE)
1505 len = msmsdcc_pio_read(host, buffer, remain);
1506 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001508
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301509 /* len might have aligned to 32bits above */
1510 if (len > remain)
1511 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001512
San Mehat9d2bd732009-09-22 16:44:22 -07001513 host->curr.xfer_remain -= len;
1514 host->curr.data_xfered += len;
1515 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001516 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 if (remain) /* Done with this page? */
1519 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001522 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001523
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001524 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001525 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1528 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1529 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1530 host->base + MMCIMASK0);
1531 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301532 /*
1533 * back to back write to MASK0 register don't need
1534 * synchronization delay.
1535 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1537 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1538 }
1539 mb();
1540 } else if (!host->curr.xfer_remain) {
1541 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1542 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1543 mb();
1544 }
San Mehat9d2bd732009-09-22 16:44:22 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001547
1548 return IRQ_HANDLED;
1549}
1550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551static void
1552msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1553
1554static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1555 struct mmc_data *data)
1556{
1557 u32 loop_cnt = 0;
1558
1559 /*
1560 * For read commands with data less than fifo size, it is possible to
1561 * get DATAEND first and RXDATA_AVAIL might be set later because of
1562 * synchronization delay through the asynchronous RX FIFO. Thus, for
1563 * such cases, even after DATAEND interrupt is received software
1564 * should poll for RXDATA_AVAIL until the requested data is read out
1565 * of FIFO. This change is needed to get around this abnormal but
1566 * sometimes expected behavior of SDCC3 controller.
1567 *
1568 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1569 * after the data is loaded into RX FIFO. This would amount to less
1570 * than a microsecond and thus looping for 1000 times is good enough
1571 * for that delay.
1572 */
1573 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1574 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1575 spin_unlock(&host->lock);
1576 msmsdcc_pio_irq(1, host);
1577 spin_lock(&host->lock);
1578 }
1579 }
1580 if (loop_cnt == 1000) {
1581 pr_info("%s: Timed out while polling for Rx Data\n",
1582 mmc_hostname(host->mmc));
1583 data->error = -ETIMEDOUT;
1584 msmsdcc_reset_and_restore(host);
1585 }
1586}
1587
San Mehat9d2bd732009-09-22 16:44:22 -07001588static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1589{
1590 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001591
1592 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301593 if (mmc_resp_type(cmd))
1594 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1595 /*
1596 * Read rest of the response registers only if
1597 * long response is expected for this command
1598 */
1599 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1600 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1601 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1602 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1603 }
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301606 pr_debug("%s: CMD%d: Command timeout\n",
1607 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001608 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301610 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301611 pr_err("%s: CMD%d: Command CRC error\n",
1612 mmc_hostname(host->mmc), cmd->opcode);
1613 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001614 cmd->error = -EILSEQ;
1615 }
1616
1617 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 if (host->curr.data && host->dma.sg &&
1619 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001620 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 else if (host->curr.data && host->sps.sg &&
1622 host->is_sps_mode){
1623 /* Stop current SPS transfer */
1624 msmsdcc_sps_exit_curr_xfer(host);
1625 }
San Mehat9d2bd732009-09-22 16:44:22 -07001626 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301627 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001628 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301629 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301630 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301631 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301632 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301634 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301636 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301637 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301638 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301639 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001640 if (host->dummy_52_needed)
1641 host->dummy_52_needed = 0;
1642 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301644 msmsdcc_request_end(host, cmd->mrq);
1645 }
1646 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301647 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301648 if (cmd == host->curr.mrq->sbc)
1649 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1650 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1651 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301652 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001653 }
1654}
1655
San Mehat9d2bd732009-09-22 16:44:22 -07001656static irqreturn_t
1657msmsdcc_irq(int irq, void *dev_id)
1658{
1659 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001660 u32 status;
1661 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001663
1664 spin_lock(&host->lock);
1665
1666 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 struct mmc_command *cmd;
1668 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 if (timer) {
1671 timer = 0;
1672 msmsdcc_delay(host);
1673 }
San Mehat865c8062009-11-13 13:42:06 -08001674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 if (!host->clks_on) {
1676 pr_debug("%s: %s: SDIO async irq received\n",
1677 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301678
1679 /*
1680 * Only async interrupt can come when clocks are off,
1681 * disable further interrupts and enable them when
1682 * clocks are on.
1683 */
1684 if (!host->sdcc_irq_disabled) {
1685 disable_irq_nosync(irq);
1686 host->sdcc_irq_disabled = 1;
1687 }
1688
1689 /*
1690 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1691 * will take care of signaling sdio irq during
1692 * mmc_sdio_resume().
1693 */
1694 if (host->sdcc_suspended)
1695 /*
1696 * This is a wakeup interrupt so hold wakelock
1697 * until SDCC resume is handled.
1698 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301700 else
1701 mmc_signal_sdio_irq(host->mmc);
1702 ret = 1;
1703 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704 }
1705
1706 status = readl_relaxed(host->base + MMCISTATUS);
1707
1708 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1709 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001710 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712#if IRQ_DEBUG
1713 msmsdcc_print_status(host, "irq0-r", status);
1714#endif
1715 status &= readl_relaxed(host->base + MMCIMASK0);
1716 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301717 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301718 if (host->clk_rate <=
1719 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301720 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721#if IRQ_DEBUG
1722 msmsdcc_print_status(host, "irq0-p", status);
1723#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 if (status & MCI_SDIOINTROPE) {
1726 if (host->sdcc_suspending)
1727 wake_lock(&host->sdio_suspend_wlock);
1728 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001729 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001730 data = host->curr.data;
1731
1732 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1734 MCI_CMDTIMEOUT)) {
1735 if (status & MCI_CMDTIMEOUT)
1736 pr_debug("%s: dummy CMD52 timeout\n",
1737 mmc_hostname(host->mmc));
1738 if (status & MCI_CMDCRCFAIL)
1739 pr_debug("%s: dummy CMD52 CRC failed\n",
1740 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001741 host->dummy_52_sent = 0;
1742 host->dummy_52_needed = 0;
1743 if (data) {
1744 msmsdcc_stop_data(host);
1745 msmsdcc_request_end(host, data->mrq);
1746 }
1747 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 spin_unlock(&host->lock);
1749 return IRQ_HANDLED;
1750 }
1751 break;
1752 }
1753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 /*
1755 * Check for proper command response
1756 */
1757 cmd = host->curr.cmd;
1758 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1759 MCI_CMDTIMEOUT | MCI_PROGDONE |
1760 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1761 msmsdcc_do_cmdirq(host, status);
1762 }
1763
Sathish Ambley081d7842011-11-29 11:19:41 -08001764 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 /* Check for data errors */
1766 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1767 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1768 msmsdcc_data_err(host, data, status);
1769 host->curr.data_xfered = 0;
1770 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001771 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 else if (host->sps.sg && host->is_sps_mode) {
1773 /* Stop current SPS transfer */
1774 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301775 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 msmsdcc_reset_and_restore(host);
1777 if (host->curr.data)
1778 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301779 if (!data->stop || (host->curr.mrq->sbc
1780 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 timer |=
1782 msmsdcc_request_end(host,
1783 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301784 else if ((host->curr.mrq->sbc
1785 && data->error) ||
1786 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 msmsdcc_start_command(host,
1788 data->stop,
1789 0);
1790 timer = 1;
1791 }
1792 }
1793 }
1794
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301795 /* Check for prog done */
1796 if (host->curr.wait_for_auto_prog_done &&
1797 (status & MCI_PROGDONE))
1798 host->curr.got_auto_prog_done = 1;
1799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 /* Check for data done */
1801 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1802 host->curr.got_dataend = 1;
1803
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301804 if (host->curr.got_dataend &&
1805 (!host->curr.wait_for_auto_prog_done ||
1806 (host->curr.wait_for_auto_prog_done &&
1807 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808 /*
1809 * If DMA is still in progress, we complete
1810 * via the completion handler
1811 */
1812 if (!host->dma.busy && !host->sps.busy) {
1813 /*
1814 * There appears to be an issue in the
1815 * controller where if you request a
1816 * small block transfer (< fifo size),
1817 * you may get your DATAEND/DATABLKEND
1818 * irq without the PIO data irq.
1819 *
1820 * Check to see if theres still data
1821 * to be read, and simulate a PIO irq.
1822 */
1823 if (data->flags & MMC_DATA_READ)
1824 msmsdcc_wait_for_rxdata(host,
1825 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 if (!data->error) {
1827 host->curr.data_xfered =
1828 host->curr.xfer_size;
1829 host->curr.xfer_remain -=
1830 host->curr.xfer_size;
1831 }
1832
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001833 if (!host->dummy_52_needed) {
1834 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301835 if (!data->stop ||
1836 (host->curr.mrq->sbc
1837 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001838 msmsdcc_request_end(
1839 host,
1840 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301841 else if ((host->curr.mrq->sbc
1842 && data->error) ||
1843 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001844 msmsdcc_start_command(
1845 host,
1846 data->stop, 0);
1847 timer = 1;
1848 }
1849 } else {
1850 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001852 &dummy52cmd,
1853 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854 }
1855 }
1856 }
1857 }
1858
San Mehat9d2bd732009-09-22 16:44:22 -07001859 ret = 1;
1860 } while (status);
1861
1862 spin_unlock(&host->lock);
1863
San Mehat9d2bd732009-09-22 16:44:22 -07001864 return IRQ_RETVAL(ret);
1865}
1866
1867static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301868msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1869 bool is_first_request)
1870{
1871 struct msmsdcc_host *host = mmc_priv(mmc);
1872 struct mmc_data *data = mrq->data;
1873 int rc = 0;
1874
1875 if (unlikely(!data)) {
1876 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1877 __func__);
1878 return;
1879 }
1880 if (unlikely(data->host_cookie)) {
1881 /* Very wrong */
1882 data->host_cookie = 0;
1883 pr_err("%s: %s Request reposted for prepare\n",
1884 mmc_hostname(mmc), __func__);
1885 return;
1886 }
1887
1888 if (!msmsdcc_is_dma_possible(host, data))
1889 return;
1890
1891 rc = msmsdcc_prep_xfer(host, data);
1892 if (unlikely(rc < 0)) {
1893 data->host_cookie = 0;
1894 return;
1895 }
1896
1897 data->host_cookie = 1;
1898}
1899
1900static void
1901msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1902{
1903 struct msmsdcc_host *host = mmc_priv(mmc);
1904 unsigned int dir;
1905 struct mmc_data *data = mrq->data;
1906
1907 if (unlikely(!data)) {
1908 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1909 __func__);
1910 return;
1911 }
1912 if (data->flags & MMC_DATA_READ)
1913 dir = DMA_FROM_DEVICE;
1914 else
1915 dir = DMA_TO_DEVICE;
1916
1917 if (data->host_cookie)
1918 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1919 data->sg_len, dir);
1920
1921 data->host_cookie = 0;
1922}
1923
1924static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1926{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301927 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301929 if ((mrq->data->flags & MMC_DATA_READ) ||
1930 host->curr.use_wr_data_pend)
1931 msmsdcc_start_data(host, mrq->data,
1932 mrq->sbc ? mrq->sbc : mrq->cmd,
1933 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301934 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301935 msmsdcc_start_command(host,
1936 mrq->sbc ? mrq->sbc : mrq->cmd,
1937 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001938 } else {
1939 msmsdcc_start_command(host, mrq->cmd, 0);
1940 }
1941}
1942
1943static void
San Mehat9d2bd732009-09-22 16:44:22 -07001944msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1945{
1946 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301947 unsigned long flags, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001948
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949 /*
1950 * Get the SDIO AL client out of LPM.
1951 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001952 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 if (host->plat->is_sdio_al_client)
1954 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001955
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301956 /* check if sps pipe reset is pending? */
1957 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1958 msmsdcc_sps_pipes_reset_and_restore(host);
1959 host->sps.pipe_reset_pending = false;
1960 }
1961
San Mehat9d2bd732009-09-22 16:44:22 -07001962 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001963
1964 if (host->eject) {
1965 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1966 mrq->cmd->error = 0;
1967 mrq->data->bytes_xfered = mrq->data->blksz *
1968 mrq->data->blocks;
1969 } else
1970 mrq->cmd->error = -ENOMEDIUM;
1971
1972 spin_unlock_irqrestore(&host->lock, flags);
1973 mmc_request_done(mmc, mrq);
1974 return;
1975 }
1976
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301977 /*
subhashjf181c292012-05-02 13:07:40 +05301978 * Don't start the request if SDCC is not in proper state to handle it
1979 */
1980 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1981 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1982 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1983 __func__, mrq->cmd->opcode);
1984 msmsdcc_dump_sdcc_state(host);
1985 mrq->cmd->error = -EIO;
1986 if (mrq->data) {
1987 mrq->data->error = -EIO;
1988 mrq->data->bytes_xfered = 0;
1989 }
1990 spin_unlock_irqrestore(&host->lock, flags);
1991 mmc_request_done(mmc, mrq);
1992 return;
1993 }
1994
1995 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
1996 " other request (CMD%d) is in progress\n",
1997 mmc_hostname(host->mmc), __func__,
1998 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
1999
2000 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302001 * Set timeout value to 10 secs (or more in case of buggy cards)
2002 */
2003 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
2004 timeout = 20000;
2005 else
2006 timeout = MSM_MMC_REQ_TIMEOUT;
2007 /*
2008 * Kick the software request timeout timer here with the timeout
2009 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302010 */
2011 mod_timer(&host->req_tout_timer,
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302012 (jiffies + msecs_to_jiffies(timeout)));
San Mehat9d2bd732009-09-22 16:44:22 -07002013
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302014 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302015 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302016 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
2017 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05302018 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302020 else
2021 /*
2022 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
2023 * write operations using CMD53 and CMD54.
2024 * Setting this bit with CMD53 would
2025 * automatically triggers PROG_DONE interrupt
2026 * without the need of sending dummy CMD52.
2027 */
2028 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05302029 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
2030 host->sdcc_version) {
2031 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302033 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2034 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2035 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002036 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302037
Pratibhasagar V00b94332011-10-18 14:57:27 +05302038 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302039 mrq->sbc->mrq = mrq;
2040 mrq->sbc->data = mrq->data;
Subhash Jadavanif5277752011-10-12 16:47:52 +05302041 if (mrq->data->flags & MMC_DATA_WRITE)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302042 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302043 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302044 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302045
San Mehat9d2bd732009-09-22 16:44:22 -07002046 spin_unlock_irqrestore(&host->lock, flags);
2047}
2048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002049static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2050 int min_uV, int max_uV)
2051{
2052 int rc = 0;
2053
2054 if (vreg->set_voltage_sup) {
2055 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2056 if (rc) {
2057 pr_err("%s: regulator_set_voltage(%s) failed."
2058 " min_uV=%d, max_uV=%d, rc=%d\n",
2059 __func__, vreg->name, min_uV, max_uV, rc);
2060 }
2061 }
2062
2063 return rc;
2064}
2065
2066static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2067 int uA_load)
2068{
2069 int rc = 0;
2070
Krishna Kondafea60182011-11-01 16:01:34 -07002071 /* regulators that do not support regulator_set_voltage also
2072 do not support regulator_set_optimum_mode */
2073 if (vreg->set_voltage_sup) {
2074 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2075 if (rc < 0)
2076 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2077 "uA_load=%d) failed. rc=%d\n", __func__,
2078 vreg->name, uA_load, rc);
2079 else
2080 /* regulator_set_optimum_mode() can return non zero
2081 * value even for success case.
2082 */
2083 rc = 0;
2084 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085
2086 return rc;
2087}
2088
2089static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2090 struct device *dev)
2091{
2092 int rc = 0;
2093
2094 /* check if regulator is already initialized? */
2095 if (vreg->reg)
2096 goto out;
2097
2098 /* Get the regulator handle */
2099 vreg->reg = regulator_get(dev, vreg->name);
2100 if (IS_ERR(vreg->reg)) {
2101 rc = PTR_ERR(vreg->reg);
2102 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2103 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002104 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002106
2107 if (regulator_count_voltages(vreg->reg) > 0)
2108 vreg->set_voltage_sup = 1;
2109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002110out:
2111 return rc;
2112}
2113
2114static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2115{
2116 if (vreg->reg)
2117 regulator_put(vreg->reg);
2118}
2119
2120/* This init function should be called only once for each SDCC slot */
2121static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2122{
2123 int rc = 0;
2124 struct msm_mmc_slot_reg_data *curr_slot;
2125 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2126 struct device *dev = mmc_dev(host->mmc);
2127
2128 curr_slot = host->plat->vreg_data;
2129 if (!curr_slot)
2130 goto out;
2131
2132 curr_vdd_reg = curr_slot->vdd_data;
2133 curr_vccq_reg = curr_slot->vccq_data;
2134 curr_vddp_reg = curr_slot->vddp_data;
2135
2136 if (is_init) {
2137 /*
2138 * Get the regulator handle from voltage regulator framework
2139 * and then try to set the voltage level for the regulator
2140 */
2141 if (curr_vdd_reg) {
2142 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2143 if (rc)
2144 goto out;
2145 }
2146 if (curr_vccq_reg) {
2147 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2148 if (rc)
2149 goto vdd_reg_deinit;
2150 }
2151 if (curr_vddp_reg) {
2152 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2153 if (rc)
2154 goto vccq_reg_deinit;
2155 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002156 rc = msmsdcc_vreg_reset(host);
2157 if (rc)
2158 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2159 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160 goto out;
2161 } else {
2162 /* Deregister all regulators from regulator framework */
2163 goto vddp_reg_deinit;
2164 }
2165vddp_reg_deinit:
2166 if (curr_vddp_reg)
2167 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2168vccq_reg_deinit:
2169 if (curr_vccq_reg)
2170 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2171vdd_reg_deinit:
2172 if (curr_vdd_reg)
2173 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2174out:
2175 return rc;
2176}
2177
2178static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2179{
2180 int rc = 0;
2181
Subhash Jadavanicc922692011-08-01 23:05:01 +05302182 /* Put regulator in HPM (high power mode) */
2183 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2184 if (rc < 0)
2185 goto out;
2186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187 if (!vreg->is_enabled) {
2188 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302189 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2190 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002191 if (rc)
2192 goto out;
2193
2194 rc = regulator_enable(vreg->reg);
2195 if (rc) {
2196 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2197 __func__, vreg->name, rc);
2198 goto out;
2199 }
2200 vreg->is_enabled = true;
2201 }
2202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002203out:
2204 return rc;
2205}
2206
2207static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2208{
2209 int rc = 0;
2210
2211 /* Never disable regulator marked as always_on */
2212 if (vreg->is_enabled && !vreg->always_on) {
2213 rc = regulator_disable(vreg->reg);
2214 if (rc) {
2215 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2216 __func__, vreg->name, rc);
2217 goto out;
2218 }
2219 vreg->is_enabled = false;
2220
2221 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2222 if (rc < 0)
2223 goto out;
2224
2225 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302226 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 if (rc)
2228 goto out;
2229 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2230 /* Put always_on regulator in LPM (low power mode) */
2231 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2232 if (rc < 0)
2233 goto out;
2234 }
2235out:
2236 return rc;
2237}
2238
2239static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2240{
2241 int rc = 0, i;
2242 struct msm_mmc_slot_reg_data *curr_slot;
2243 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2244 struct msm_mmc_reg_data *vreg_table[3];
2245
2246 curr_slot = host->plat->vreg_data;
2247 if (!curr_slot)
2248 goto out;
2249
2250 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2251 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2252 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2253
2254 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2255 if (vreg_table[i]) {
2256 if (enable)
2257 rc = msmsdcc_vreg_enable(vreg_table[i]);
2258 else
2259 rc = msmsdcc_vreg_disable(vreg_table[i]);
2260 if (rc)
2261 goto out;
2262 }
2263 }
2264out:
2265 return rc;
2266}
2267
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002268/*
2269 * Reset vreg by ensuring it is off during probe. A call
2270 * to enable vreg is needed to balance disable vreg
2271 */
2272static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2273{
2274 int rc;
2275
2276 rc = msmsdcc_setup_vreg(host, 1);
2277 if (rc)
2278 return rc;
2279 rc = msmsdcc_setup_vreg(host, 0);
2280 return rc;
2281}
2282
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302283static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284{
2285 int rc = 0;
2286
2287 if (host->plat->vreg_data) {
2288 struct msm_mmc_reg_data *vddp_reg =
2289 host->plat->vreg_data->vddp_data;
2290
2291 if (vddp_reg && vddp_reg->is_enabled)
2292 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2293 }
2294
2295 return rc;
2296}
2297
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302298static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2299{
2300 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2301 int rc = 0;
2302
2303 if (curr_slot && curr_slot->vddp_data) {
2304 rc = msmsdcc_set_vddp_level(host,
2305 curr_slot->vddp_data->low_vol_level);
2306
2307 if (rc)
2308 pr_err("%s: %s: failed to change vddp level to %d",
2309 mmc_hostname(host->mmc), __func__,
2310 curr_slot->vddp_data->low_vol_level);
2311 }
2312
2313 return rc;
2314}
2315
2316static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2317{
2318 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2319 int rc = 0;
2320
2321 if (curr_slot && curr_slot->vddp_data) {
2322 rc = msmsdcc_set_vddp_level(host,
2323 curr_slot->vddp_data->high_vol_level);
2324
2325 if (rc)
2326 pr_err("%s: %s: failed to change vddp level to %d",
2327 mmc_hostname(host->mmc), __func__,
2328 curr_slot->vddp_data->high_vol_level);
2329 }
2330
2331 return rc;
2332}
2333
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302334static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2335{
2336 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2337 int rc = 0;
2338
2339 if (curr_slot && curr_slot->vccq_data) {
2340 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2341 level, level);
2342 if (rc)
2343 pr_err("%s: %s: failed to change vccq level to %d",
2344 mmc_hostname(host->mmc), __func__, level);
2345 }
2346
2347 return rc;
2348}
2349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2351{
2352 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2353 return 1;
2354 return 0;
2355}
2356
Asutosh Dasf5298c32012-04-03 14:51:47 +05302357/*
2358 * Any function calling msmsdcc_setup_clocks must
2359 * acquire clk_mutex. May sleep.
2360 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2362{
2363 if (enable) {
2364 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302365 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302367 clk_prepare_enable(host->pclk);
2368 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302369 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302370 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302372 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302373 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302374 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302376 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302378 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379 }
2380}
2381
2382static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2383 unsigned int req_clk)
2384{
2385 unsigned int sel_clk = -1;
2386
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302387 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2388 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2389 goto out;
2390 }
2391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2393 unsigned char cnt;
2394
2395 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2396 if (host->plat->sup_clk_table[cnt] > req_clk)
2397 break;
2398 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2399 sel_clk = host->plat->sup_clk_table[cnt];
2400 break;
2401 } else
2402 sel_clk = host->plat->sup_clk_table[cnt];
2403 }
2404 } else {
2405 if ((req_clk < host->plat->msmsdcc_fmax) &&
2406 (req_clk > host->plat->msmsdcc_fmid))
2407 sel_clk = host->plat->msmsdcc_fmid;
2408 else
2409 sel_clk = req_clk;
2410 }
2411
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302412out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413 return sel_clk;
2414}
2415
2416static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2417 struct msmsdcc_host *host)
2418{
2419 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2420 return host->plat->sup_clk_table[0];
2421 else
2422 return host->plat->msmsdcc_fmin;
2423}
2424
2425static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2426 struct msmsdcc_host *host)
2427{
2428 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2429 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2430 else
2431 return host->plat->msmsdcc_fmax;
2432}
2433
2434static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302435{
2436 struct msm_mmc_gpio_data *curr;
2437 int i, rc = 0;
2438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302440 for (i = 0; i < curr->size; i++) {
2441 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 if (curr->gpio[i].is_always_on &&
2443 curr->gpio[i].is_enabled)
2444 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302445 rc = gpio_request(curr->gpio[i].no,
2446 curr->gpio[i].name);
2447 if (rc) {
2448 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2449 mmc_hostname(host->mmc),
2450 curr->gpio[i].no,
2451 curr->gpio[i].name, rc);
2452 goto free_gpios;
2453 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302455 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 if (curr->gpio[i].is_always_on)
2457 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302458 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302460 }
2461 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302463
2464free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302466 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 curr->gpio[i].is_enabled = false;
2468 }
2469out:
2470 return rc;
2471}
2472
2473static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2474{
2475 struct msm_mmc_pad_data *curr;
2476 int i;
2477
2478 curr = host->plat->pin_data->pad_data;
2479 for (i = 0; i < curr->drv->size; i++) {
2480 if (enable)
2481 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2482 curr->drv->on[i].val);
2483 else
2484 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2485 curr->drv->off[i].val);
2486 }
2487
2488 for (i = 0; i < curr->pull->size; i++) {
2489 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002490 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 curr->pull->on[i].val);
2492 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002493 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 curr->pull->off[i].val);
2495 }
2496
2497 return 0;
2498}
2499
2500static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2501{
2502 int rc = 0;
2503
2504 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2505 return 0;
2506
2507 if (host->plat->pin_data->is_gpio)
2508 rc = msmsdcc_setup_gpio(host, enable);
2509 else
2510 rc = msmsdcc_setup_pad(host, enable);
2511
2512 if (!rc)
2513 host->plat->pin_data->cfg_sts = enable;
2514
2515 return rc;
2516}
2517
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302518static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2519 unsigned mode)
2520{
2521 int ret = 0;
2522 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2523
2524 if (!pin)
2525 return 0;
2526
2527 switch (mode) {
2528 case SDC_DAT1_DISABLE:
2529 ret = msm_mpm_enable_pin(pin, 0);
2530 break;
2531 case SDC_DAT1_ENABLE:
2532 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2533 ret = msm_mpm_enable_pin(pin, 1);
2534 break;
2535 case SDC_DAT1_ENWAKE:
2536 ret = msm_mpm_set_pin_wake(pin, 1);
2537 break;
2538 case SDC_DAT1_DISWAKE:
2539 ret = msm_mpm_set_pin_wake(pin, 0);
2540 break;
2541 default:
2542 ret = -EINVAL;
2543 break;
2544 }
2545
2546 return ret;
2547}
2548
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302549static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2550{
2551 u32 pwr = 0;
2552 int ret = 0;
2553 struct mmc_host *mmc = host->mmc;
2554
2555 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2556 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2557 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2558 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2559
2560 if (ret) {
2561 pr_err("%s: Failed to setup voltage regulators\n",
2562 mmc_hostname(host->mmc));
2563 goto out;
2564 }
2565
2566 switch (ios->power_mode) {
2567 case MMC_POWER_OFF:
2568 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302569 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302570 /*
2571 * As VDD pad rail is always on, set low voltage for VDD
2572 * pad rail when slot is unused (when card is not present
2573 * or during system suspend).
2574 */
2575 msmsdcc_set_vddp_low_vol(host);
2576 msmsdcc_setup_pins(host, false);
2577 break;
2578 case MMC_POWER_UP:
2579 /* writing PWR_UP bit is redundant */
2580 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302581 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302582
2583 msmsdcc_set_vddp_high_vol(host);
2584 msmsdcc_setup_pins(host, true);
2585 break;
2586 case MMC_POWER_ON:
2587 pwr = MCI_PWR_ON;
2588 break;
2589 }
2590
2591out:
2592 return pwr;
2593}
2594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2596{
2597 unsigned int wakeup_irq;
2598
2599 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2600 host->plat->sdiowakeup_irq :
2601 host->core_irqres->start;
2602
2603 if (!host->irq_wake_enabled) {
2604 enable_irq_wake(wakeup_irq);
2605 host->irq_wake_enabled = true;
2606 }
2607}
2608
2609static void msmsdcc_disable_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 disable_irq_wake(wakeup_irq);
2619 host->irq_wake_enabled = false;
2620 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302621}
2622
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302623/* Returns required bandwidth in Bytes per Sec */
2624static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2625 struct mmc_ios *ios)
2626{
2627 unsigned int bw;
2628
2629 bw = host->clk_rate;
2630 /*
2631 * For DDR mode, SDCC controller clock will be at
2632 * the double rate than the actual clock that goes to card.
2633 */
2634 if (ios->bus_width == MMC_BUS_WIDTH_4)
2635 bw /= 2;
2636 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2637 bw /= 8;
2638
2639 return bw;
2640}
2641
2642static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2643 unsigned int bw)
2644{
2645 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2646 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2647 int i;
2648
2649 if (host->msm_bus_vote.is_max_bw_needed && bw)
2650 return host->msm_bus_vote.max_bw_vote;
2651
2652 for (i = 0; i < size; i++) {
2653 if (bw <= table[i])
2654 break;
2655 }
2656
2657 if (i && (i == size))
2658 i--;
2659
2660 return i;
2661}
2662
2663static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2664{
2665 int rc = 0;
2666 struct msm_bus_scale_pdata *use_cases;
2667
2668 if (host->plat->msm_bus_voting_data &&
2669 host->plat->msm_bus_voting_data->use_cases &&
2670 host->plat->msm_bus_voting_data->bw_vecs &&
2671 host->plat->msm_bus_voting_data->bw_vecs_size) {
2672 use_cases = host->plat->msm_bus_voting_data->use_cases;
2673 host->msm_bus_vote.client_handle =
2674 msm_bus_scale_register_client(use_cases);
2675 } else {
2676 return 0;
2677 }
2678
2679 if (!host->msm_bus_vote.client_handle) {
2680 pr_err("%s: msm_bus_scale_register_client() failed\n",
2681 mmc_hostname(host->mmc));
2682 rc = -EFAULT;
2683 } else {
2684 /* cache the vote index for minimum and maximum bandwidth */
2685 host->msm_bus_vote.min_bw_vote =
2686 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2687 host->msm_bus_vote.max_bw_vote =
2688 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2689 }
2690
2691 return rc;
2692}
2693
2694static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2695{
2696 if (host->msm_bus_vote.client_handle)
2697 msm_bus_scale_unregister_client(
2698 host->msm_bus_vote.client_handle);
2699}
2700
2701/*
2702 * This function must be called with host lock acquired.
2703 * Caller of this function should also ensure that msm bus client
2704 * handle is not null.
2705 */
2706static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2707 int vote,
2708 unsigned long flags)
2709{
2710 int rc = 0;
2711
2712 if (vote != host->msm_bus_vote.curr_vote) {
2713 spin_unlock_irqrestore(&host->lock, flags);
2714 rc = msm_bus_scale_client_update_request(
2715 host->msm_bus_vote.client_handle, vote);
2716 if (rc)
2717 pr_err("%s: msm_bus_scale_client_update_request() failed."
2718 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2719 mmc_hostname(host->mmc),
2720 host->msm_bus_vote.client_handle, vote, rc);
2721 spin_lock_irqsave(&host->lock, flags);
2722 if (!rc)
2723 host->msm_bus_vote.curr_vote = vote;
2724 }
2725
2726 return rc;
2727}
2728
2729/*
2730 * Internal work. Work to set 0 bandwidth for msm bus.
2731 */
2732static void msmsdcc_msm_bus_work(struct work_struct *work)
2733{
2734 struct msmsdcc_host *host = container_of(work,
2735 struct msmsdcc_host,
2736 msm_bus_vote.vote_work.work);
2737 unsigned long flags;
2738
2739 if (!host->msm_bus_vote.client_handle)
2740 return;
2741
2742 spin_lock_irqsave(&host->lock, flags);
2743 /* don't vote for 0 bandwidth if any request is in progress */
2744 if (!host->curr.mrq)
2745 msmsdcc_msm_bus_set_vote(host,
2746 host->msm_bus_vote.min_bw_vote, flags);
2747 else
2748 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2749 " bus voting to 0 bandwidth\n",
2750 mmc_hostname(host->mmc), __func__);
2751 spin_unlock_irqrestore(&host->lock, flags);
2752}
2753
2754/*
2755 * This function cancels any scheduled delayed work
2756 * and sets the bus vote based on ios argument.
2757 * If "ios" argument is NULL, bandwidth required is 0 else
2758 * calculate the bandwidth based on ios parameters.
2759 */
2760static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2761 struct msmsdcc_host *host,
2762 struct mmc_ios *ios)
2763{
2764 unsigned long flags;
2765 unsigned int bw;
2766 int vote;
2767
2768 if (!host->msm_bus_vote.client_handle)
2769 return;
2770
2771 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2772
2773 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2774 spin_lock_irqsave(&host->lock, flags);
2775 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2776 msmsdcc_msm_bus_set_vote(host, vote, flags);
2777 spin_unlock_irqrestore(&host->lock, flags);
2778}
2779
2780/* This function queues a work which will set the bandwidth requiement to 0 */
2781static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2782{
2783 unsigned long flags;
2784
2785 if (!host->msm_bus_vote.client_handle)
2786 return;
2787
2788 spin_lock_irqsave(&host->lock, flags);
2789 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2790 queue_delayed_work(system_nrt_wq,
2791 &host->msm_bus_vote.vote_work,
2792 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2793 spin_unlock_irqrestore(&host->lock, flags);
2794}
2795
San Mehat9d2bd732009-09-22 16:44:22 -07002796static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302797msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2798{
2799 struct mmc_host *mmc = host->mmc;
2800
2801 /*
2802 * SDIO_AL clients has different mechanism of handling LPM through
2803 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2804 * part of that. Here, we are interested only in clients like WLAN.
2805 */
2806 if (!(mmc->card && mmc_card_sdio(mmc->card))
2807 || host->plat->is_sdio_al_client)
2808 goto out;
2809
2810 if (!host->sdcc_suspended) {
2811 /*
2812 * When MSM is not in power collapse and we
2813 * are disabling clocks, enable bit 22 in MASK0
2814 * to handle asynchronous SDIO interrupts.
2815 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302816 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302817 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302818 mb();
2819 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302820 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302821 msmsdcc_sync_reg_wr(host);
2822 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302823 goto out;
2824 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2825 /*
2826 * Wakeup MSM only if SDIO function drivers set
2827 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2828 */
2829 goto out;
2830 }
2831
2832 if (enable_wakeup_irq) {
2833 if (!host->plat->sdiowakeup_irq) {
2834 /*
2835 * When there is no gpio line that can be configured
2836 * as wakeup interrupt handle it by configuring
2837 * asynchronous sdio interrupts and DAT1 line.
2838 */
2839 writel_relaxed(MCI_SDIOINTMASK,
2840 host->base + MMCIMASK0);
2841 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302842 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302843 /* configure sdcc core interrupt as wakeup interrupt */
2844 msmsdcc_enable_irq_wake(host);
2845 } else {
2846 /* Let gpio line handle wakeup interrupt */
2847 writel_relaxed(0, host->base + MMCIMASK0);
2848 mb();
2849 if (host->sdio_wakeupirq_disabled) {
2850 host->sdio_wakeupirq_disabled = 0;
2851 /* configure gpio line as wakeup interrupt */
2852 msmsdcc_enable_irq_wake(host);
2853 enable_irq(host->plat->sdiowakeup_irq);
2854 }
2855 }
2856 } else {
2857 if (!host->plat->sdiowakeup_irq) {
2858 /*
2859 * We may not have cleared bit 22 in the interrupt
2860 * handler as the clocks might be off at that time.
2861 */
2862 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302863 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302864 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302865 msmsdcc_disable_irq_wake(host);
2866 } else if (!host->sdio_wakeupirq_disabled) {
2867 disable_irq_nosync(host->plat->sdiowakeup_irq);
2868 msmsdcc_disable_irq_wake(host);
2869 host->sdio_wakeupirq_disabled = 1;
2870 }
2871 }
2872out:
2873 return;
2874}
2875
2876static void
San Mehat9d2bd732009-09-22 16:44:22 -07002877msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2878{
2879 struct msmsdcc_host *host = mmc_priv(mmc);
2880 u32 clk = 0, pwr = 0;
2881 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002882 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002884
Sahitya Tummala7a892482011-01-18 11:22:49 +05302885
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302886 /*
2887 * Disable SDCC core interrupt until set_ios is completed.
2888 * This avoids any race conditions with interrupt raised
2889 * when turning on/off the clocks. One possible
2890 * scenario is SDIO operational interrupt while the clock
2891 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302892 * host->lock is being released intermittently below.
2893 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302894 */
2895
Asutosh Dasf5298c32012-04-03 14:51:47 +05302896 mutex_lock(&host->clk_mutex);
2897 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302898 spin_lock_irqsave(&host->lock, flags);
2899 if (!host->sdcc_irq_disabled) {
2900 spin_unlock_irqrestore(&host->lock, flags);
2901 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302903 host->sdcc_irq_disabled = 1;
2904 }
2905 spin_unlock_irqrestore(&host->lock, flags);
2906
2907 pwr = msmsdcc_setup_pwr(host, ios);
2908
2909 spin_lock_irqsave(&host->lock, flags);
2910 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302912 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302914 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302916 writel_relaxed(host->mci_irqenable,
2917 host->base + MMCIMASK0);
2918 mb();
2919 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002920 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002921
2922 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2923 /*
2924 * For DDR50 mode, controller needs clock rate to be
2925 * double than what is required on the SD card CLK pin.
2926 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302927 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 /*
2929 * Make sure that we don't double the clock if
2930 * doubled clock rate is already set
2931 */
2932 if (!host->ddr_doubled_clk_rate ||
2933 (host->ddr_doubled_clk_rate &&
2934 (host->ddr_doubled_clk_rate != ios->clock))) {
2935 host->ddr_doubled_clk_rate =
2936 msmsdcc_get_sup_clk_rate(
2937 host, (ios->clock * 2));
2938 clock = host->ddr_doubled_clk_rate;
2939 }
2940 } else {
2941 host->ddr_doubled_clk_rate = 0;
2942 }
2943
2944 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302945 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002946 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302947 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302949 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002950 mmc_hostname(mmc), clock);
2951 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302952 host->reg_write_delay =
2953 (1 + ((3 * USEC_PER_SEC) /
2954 (host->clk_rate ? host->clk_rate :
2955 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002956 }
2957 /*
2958 * give atleast 2 MCLK cycles delay for clocks
2959 * and SDCC core to stabilize
2960 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302961 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002962 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002963 clk |= MCI_CLK_ENABLE;
2964 }
2965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966 if (ios->bus_width == MMC_BUS_WIDTH_8)
2967 clk |= MCI_CLK_WIDEBUS_8;
2968 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2969 clk |= MCI_CLK_WIDEBUS_4;
2970 else
2971 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973 if (msmsdcc_is_pwrsave(host))
2974 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 host->tuning_needed = 0;
2979 /*
2980 * Select the controller timing mode according
2981 * to current bus speed mode
2982 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302983 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2984 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002985 clk |= (4 << 14);
2986 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302987 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 clk |= (3 << 14);
2989 } else {
2990 clk |= (2 << 14); /* feedback clock */
2991 }
2992
2993 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2994 clk |= (2 << 23);
2995
Subhash Jadavani00083572012-02-15 16:18:01 +05302996 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2997 if (!ios->vdd)
2998 host->io_pad_pwr_switch = 0;
2999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 if (host->io_pad_pwr_switch)
3001 clk |= IO_PAD_PWR_SWITCH;
3002
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303003 /* Don't write into registers if clocks are disabled */
3004 if (host->clks_on) {
3005 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
3006 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303007 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303009 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
3010 host->pwr = pwr;
3011 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303012 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 }
3015
3016 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303017 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303018 spin_unlock_irqrestore(&host->lock, flags);
3019 /*
3020 * May get a wake-up interrupt the instant we disable the
3021 * clocks. This would disable the wake-up interrupt.
3022 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303024 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 host->clks_on = 0;
3026 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303027
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303028 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303029 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303030 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303031
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303032 /* Let interrupts be disabled if the host is powered off */
3033 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3034 enable_irq(host->core_irqres->start);
3035 host->sdcc_irq_disabled = 0;
3036 }
3037
San Mehat4adbbcc2009-11-08 13:00:37 -08003038 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303039 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003040}
3041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3043{
3044 struct msmsdcc_host *host = mmc_priv(mmc);
3045 u32 clk;
3046
3047 clk = readl_relaxed(host->base + MMCICLOCK);
3048 pr_debug("Changing to pwr_save=%d", pwrsave);
3049 if (pwrsave && msmsdcc_is_pwrsave(host))
3050 clk |= MCI_CLK_PWRSAVE;
3051 else
3052 clk &= ~MCI_CLK_PWRSAVE;
3053 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303054 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055
3056 return 0;
3057}
3058
3059static int msmsdcc_get_ro(struct mmc_host *mmc)
3060{
3061 int status = -ENOSYS;
3062 struct msmsdcc_host *host = mmc_priv(mmc);
3063
3064 if (host->plat->wpswitch) {
3065 status = host->plat->wpswitch(mmc_dev(mmc));
3066 } else if (host->plat->wpswitch_gpio) {
3067 status = gpio_request(host->plat->wpswitch_gpio,
3068 "SD_WP_Switch");
3069 if (status) {
3070 pr_err("%s: %s: Failed to request GPIO %d\n",
3071 mmc_hostname(mmc), __func__,
3072 host->plat->wpswitch_gpio);
3073 } else {
3074 status = gpio_direction_input(
3075 host->plat->wpswitch_gpio);
3076 if (!status) {
3077 /*
3078 * Wait for atleast 300ms as debounce
3079 * time for GPIO input to stabilize.
3080 */
3081 msleep(300);
3082 status = gpio_get_value_cansleep(
3083 host->plat->wpswitch_gpio);
3084 status ^= !host->plat->wpswitch_polarity;
3085 }
3086 gpio_free(host->plat->wpswitch_gpio);
3087 }
3088 }
3089
3090 if (status < 0)
3091 status = -ENOSYS;
3092 pr_debug("%s: Card read-only status %d\n", __func__, status);
3093
3094 return status;
3095}
3096
San Mehat9d2bd732009-09-22 16:44:22 -07003097static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3098{
3099 struct msmsdcc_host *host = mmc_priv(mmc);
3100 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303102 /*
3103 * We may come here with clocks turned off in that case don't
3104 * attempt to write into MASK0 register. While turning on the
3105 * clocks mci_irqenable will be written to MASK0 register.
3106 */
3107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108 if (enable) {
3109 spin_lock_irqsave(&host->lock, flags);
3110 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303111 if (host->clks_on) {
3112 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303114 mb();
3115 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 spin_unlock_irqrestore(&host->lock, flags);
3117 } else {
3118 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303119 if (host->clks_on) {
3120 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003121 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303122 mb();
3123 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126
3127#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303128static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
3129{
3130 struct device *dev = mmc_dev(host->mmc);
3131
3132 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3133 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3134 " request_pending=%d, request=%d\n",
3135 mmc_hostname(host->mmc), dev->power.runtime_status,
3136 atomic_read(&dev->power.usage_count),
3137 dev->power.is_suspended, dev->power.disable_depth,
3138 dev->power.runtime_error, dev->power.request_pending,
3139 dev->power.request);
3140}
3141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003142static int msmsdcc_enable(struct mmc_host *mmc)
3143{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003144 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303146 struct msmsdcc_host *host = mmc_priv(mmc);
3147
3148 msmsdcc_pm_qos_update_latency(host, 1);
3149
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003150 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303151 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003153 if (host->sdcc_suspended && host->pending_resume &&
3154 !pm_runtime_suspended(dev)) {
3155 host->pending_resume = false;
3156 pm_runtime_get_noresume(dev);
3157 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303158 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003159 }
3160
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303161 if (dev->power.runtime_status == RPM_SUSPENDING) {
3162 if (mmc->suspend_task == current) {
3163 pm_runtime_get_noresume(dev);
3164 goto out;
3165 }
3166 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303168 rc = pm_runtime_get_sync(dev);
3169
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303170skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303171 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3173 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303174 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303175 return rc;
3176 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303177out:
3178 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303179 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180}
3181
3182static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3183{
3184 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303185 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303187 msmsdcc_pm_qos_update_latency(host, 0);
3188
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303189 if (mmc->card && mmc_card_sdio(mmc->card)) {
3190 rc = 0;
3191 goto out;
3192 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303193
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303194 if (host->plat->disable_runtime_pm)
3195 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196
3197 rc = pm_runtime_put_sync(mmc->parent);
3198
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003199 /*
3200 * Ignore -EAGAIN as that is not fatal, it means that
3201 * either runtime usage count is non-zero or the runtime
3202 * pm itself is disabled or not in proper state to process
3203 * idle notification.
3204 */
3205 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3207 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303208 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003209 return rc;
3210 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303211
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303212out:
3213 msmsdcc_msm_bus_queue_work(host);
3214 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215}
3216#else
subhashj245831e2012-04-30 18:46:17 +05303217static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3218
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303219static int msmsdcc_enable(struct mmc_host *mmc)
3220{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003221 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303222 struct msmsdcc_host *host = mmc_priv(mmc);
3223 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303224 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303225
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303226 msmsdcc_pm_qos_update_latency(host, 1);
3227
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303228 if (mmc->card && mmc_card_sdio(mmc->card)) {
3229 rc = 0;
3230 goto out;
3231 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003232
3233 if (host->sdcc_suspended && host->pending_resume) {
3234 host->pending_resume = false;
3235 rc = msmsdcc_runtime_resume(dev);
3236 goto out;
3237 }
3238
Asutosh Dasf5298c32012-04-03 14:51:47 +05303239 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303240 spin_lock_irqsave(&host->lock, flags);
3241 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303242 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303243 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303244 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303245 host->clks_on = 1;
3246 }
3247 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303248 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303249
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003250out:
3251 if (rc < 0) {
3252 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3253 __func__, rc);
3254 return rc;
3255 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303256 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303257 return 0;
3258}
3259
3260static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3261{
3262 struct msmsdcc_host *host = mmc_priv(mmc);
3263 unsigned long flags;
3264
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303265 msmsdcc_pm_qos_update_latency(host, 0);
3266
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303267 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303268 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303269
Asutosh Dasf5298c32012-04-03 14:51:47 +05303270 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303271 spin_lock_irqsave(&host->lock, flags);
3272 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303273 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303274 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303275 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303276 host->clks_on = 0;
3277 }
3278 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303279 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303280
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303281out:
3282 msmsdcc_msm_bus_queue_work(host);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303283 return 0;
3284}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285#endif
3286
3287static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3288 struct mmc_ios *ios)
3289{
3290 struct msmsdcc_host *host = mmc_priv(mmc);
3291 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303292 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003293
Subhash Jadavani00083572012-02-15 16:18:01 +05303294 spin_lock_irqsave(&host->lock, flags);
3295 host->io_pad_pwr_switch = 0;
3296 spin_unlock_irqrestore(&host->lock, flags);
3297
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303298 /*
3299 * For eMMC cards, VccQ voltage range must be changed
3300 * only if it operates in HS200 SDR 1.2V mode or in
3301 * DDR 1.2V mode.
3302 */
3303 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3304 rc = msmsdcc_set_vccq_vol(host, 1200000);
3305 goto out;
3306 }
3307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003308 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3309 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303310 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 goto out;
3312 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3313 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303314 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003315 goto out;
3316 }
San Mehat9d2bd732009-09-22 16:44:22 -07003317
3318 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003319 /*
3320 * If we are here means voltage switch from high voltage to
3321 * low voltage is required
3322 */
3323
3324 /*
3325 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3326 * register until they become all zeros.
3327 */
3328 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303329 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3331 mmc_hostname(mmc), __func__);
3332 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003333 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334
3335 /* Stop SD CLK output. */
3336 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3337 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303338 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003339 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003340
3341 /*
3342 * Switch VDDPX from high voltage to low voltage
3343 * to change the VDD of the SD IO pads.
3344 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303345 rc = msmsdcc_set_vddp_low_vol(host);
3346 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003348
3349 spin_lock_irqsave(&host->lock, flags);
3350 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3351 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303352 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 host->io_pad_pwr_switch = 1;
3354 spin_unlock_irqrestore(&host->lock, flags);
3355
3356 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3357 usleep_range(5000, 5500);
3358
3359 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303360 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3362 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303363 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364 spin_unlock_irqrestore(&host->lock, flags);
3365
3366 /*
3367 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3368 * don't become all ones within 1 ms then a Voltage Switch
3369 * sequence has failed and a power cycle to the card is required.
3370 * Otherwise Voltage Switch sequence is completed successfully.
3371 */
3372 usleep_range(1000, 1500);
3373
3374 spin_lock_irqsave(&host->lock, flags);
3375 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3376 != (0xF << 1)) {
3377 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3378 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303379 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003380 goto out_unlock;
3381 }
3382
3383out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303384 /* Enable PWRSAVE */
3385 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3386 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303387 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003388 spin_unlock_irqrestore(&host->lock, flags);
3389out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303390 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391}
3392
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303393static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003395 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396
3397 /* Program the MCLK value to MCLK_FREQ bit field */
3398 if (host->clk_rate <= 112000000)
3399 mclk_freq = 0;
3400 else if (host->clk_rate <= 125000000)
3401 mclk_freq = 1;
3402 else if (host->clk_rate <= 137000000)
3403 mclk_freq = 2;
3404 else if (host->clk_rate <= 150000000)
3405 mclk_freq = 3;
3406 else if (host->clk_rate <= 162000000)
3407 mclk_freq = 4;
3408 else if (host->clk_rate <= 175000000)
3409 mclk_freq = 5;
3410 else if (host->clk_rate <= 187000000)
3411 mclk_freq = 6;
3412 else if (host->clk_rate <= 200000000)
3413 mclk_freq = 7;
3414
3415 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3416 & ~(7 << 24)) | (mclk_freq << 24)),
3417 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003418}
3419
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303420/* Initialize the DLL (Programmable Delay Line ) */
3421static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303424 unsigned long flags;
3425 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003426
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303427 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 /*
3429 * Make sure that clock is always enabled when DLL
3430 * tuning is in progress. Keeping PWRSAVE ON may
3431 * turn off the clock. So let's disable the PWRSAVE
3432 * here and re-enable it once tuning is completed.
3433 */
3434 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3435 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303436 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303437
3438 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3439 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3440 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3441
3442 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3443 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3444 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3445
3446 msmsdcc_cm_sdc4_dll_set_freq(host);
3447
3448 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3449 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3450 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3451
3452 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3453 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3454 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3455
3456 /* Set DLL_EN bit to 1. */
3457 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3458 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3459
3460 /* Set CK_OUT_EN bit to 1. */
3461 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3462 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3463
3464 wait_cnt = 50;
3465 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3466 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3467 /* max. wait for 50us sec for LOCK bit to be set */
3468 if (--wait_cnt == 0) {
3469 pr_err("%s: %s: DLL failed to LOCK\n",
3470 mmc_hostname(host->mmc), __func__);
3471 rc = -ETIMEDOUT;
3472 goto out;
3473 }
3474 /* wait for 1us before polling again */
3475 udelay(1);
3476 }
3477
3478out:
3479 /* re-enable PWRSAVE */
3480 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3481 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303482 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303483 spin_unlock_irqrestore(&host->lock, flags);
3484
3485 return rc;
3486}
3487
3488static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3489 u8 poll)
3490{
3491 int rc = 0;
3492 u32 wait_cnt = 50;
3493 u8 ck_out_en = 0;
3494
3495 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3496 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3497 MCI_CK_OUT_EN);
3498
3499 while (ck_out_en != poll) {
3500 if (--wait_cnt == 0) {
3501 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3502 mmc_hostname(host->mmc), __func__, poll);
3503 rc = -ETIMEDOUT;
3504 goto out;
3505 }
3506 udelay(1);
3507
3508 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3509 MCI_CK_OUT_EN);
3510 }
3511out:
3512 return rc;
3513}
3514
3515/*
3516 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3517 * calibration sequence. This function should be called before
3518 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3519 * commands (CMD17/CMD18).
3520 *
3521 * This function gets called when host spinlock acquired.
3522 */
3523static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3524{
3525 int rc = 0;
3526 u32 config;
3527
3528 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3529 config |= MCI_CDR_EN;
3530 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3531 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3532
3533 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3534 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3535 if (rc)
3536 goto err_out;
3537
3538 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3539 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3540 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3541
3542 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3543 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3544 if (rc)
3545 goto err_out;
3546
3547 goto out;
3548
3549err_out:
3550 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3551out:
3552 return rc;
3553}
3554
3555static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3556 u8 phase)
3557{
3558 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303559 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3560 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3561 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303562 unsigned long flags;
3563 u32 config;
3564
3565 spin_lock_irqsave(&host->lock, flags);
3566
3567 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3568 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3569 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3570 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3571
3572 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3573 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3574 if (rc)
3575 goto err_out;
3576
3577 /*
3578 * Write the selected DLL clock output phase (0 ... 15)
3579 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3580 */
3581 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3582 & ~(0xF << 20))
3583 | (grey_coded_phase_table[phase] << 20)),
3584 host->base + MCI_DLL_CONFIG);
3585
3586 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3587 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3588 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3589
3590 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3591 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3592 if (rc)
3593 goto err_out;
3594
3595 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3596 config |= MCI_CDR_EN;
3597 config &= ~MCI_CDR_EXT_EN;
3598 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3599 goto out;
3600
3601err_out:
3602 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3603 mmc_hostname(host->mmc), __func__, phase);
3604out:
3605 spin_unlock_irqrestore(&host->lock, flags);
3606 return rc;
3607}
3608
3609/*
3610 * Find out the greatest range of consecuitive selected
3611 * DLL clock output phases that can be used as sampling
3612 * setting for SD3.0 UHS-I card read operation (in SDR104
3613 * timing mode) or for eMMC4.5 card read operation (in HS200
3614 * timing mode).
3615 * Select the 3/4 of the range and configure the DLL with the
3616 * selected DLL clock output phase.
3617*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303618static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303619 u8 *phase_table, u8 total_phases)
3620{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303621 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303622 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303623 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3624 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303625 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303626 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3627 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303628
Subhash Jadavani6159c622012-03-15 19:05:55 +05303629 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303630 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3631 mmc_hostname(host->mmc), __func__, total_phases);
3632 return -EINVAL;
3633 }
3634
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303635 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303636 ranges[row_index][col_index] = phase_table[cnt];
3637 phases_per_row[row_index] += 1;
3638 col_index++;
3639
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303640 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641 continue;
3642 /* check if next phase in phase_table is consecutive or not */
3643 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3644 row_index++;
3645 col_index = 0;
3646 }
3647 }
3648
Subhash Jadavani6159c622012-03-15 19:05:55 +05303649 if (row_index >= MAX_PHASES)
3650 return -EINVAL;
3651
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303652 /* Check if phase-0 is present in first valid window? */
3653 if (!ranges[0][0]) {
3654 phase_0_found = true;
3655 phase_0_raw_index = 0;
3656 /* Check if cycle exist between 2 valid windows */
3657 for (cnt = 1; cnt <= row_index; cnt++) {
3658 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303659 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303660 if (ranges[cnt][i] == 15) {
3661 phase_15_found = true;
3662 phase_15_raw_index = cnt;
3663 break;
3664 }
3665 }
3666 }
3667 }
3668 }
3669
3670 /* If 2 valid windows form cycle then merge them as single window */
3671 if (phase_0_found && phase_15_found) {
3672 /* number of phases in raw where phase 0 is present */
3673 u8 phases_0 = phases_per_row[phase_0_raw_index];
3674 /* number of phases in raw where phase 15 is present */
3675 u8 phases_15 = phases_per_row[phase_15_raw_index];
3676
Subhash Jadavani6159c622012-03-15 19:05:55 +05303677 if (phases_0 + phases_15 >= MAX_PHASES)
3678 /*
3679 * If there are more than 1 phase windows then total
3680 * number of phases in both the windows should not be
3681 * more than or equal to MAX_PHASES.
3682 */
3683 return -EINVAL;
3684
3685 /* Merge 2 cyclic windows */
3686 i = phases_15;
3687 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303688 ranges[phase_15_raw_index][i] =
3689 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303690 if (++i >= MAX_PHASES)
3691 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303692 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303693
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303694 phases_per_row[phase_0_raw_index] = 0;
3695 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3696 }
3697
3698 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303699 if (phases_per_row[cnt] > curr_max) {
3700 curr_max = phases_per_row[cnt];
3701 selected_row_index = cnt;
3702 }
3703 }
3704
Subhash Jadavani6159c622012-03-15 19:05:55 +05303705 i = ((curr_max * 3) / 4);
3706 if (i)
3707 i--;
3708
Subhash Jadavani34187042012-03-02 10:59:49 +05303709 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303710
Subhash Jadavani6159c622012-03-15 19:05:55 +05303711 if (ret >= MAX_PHASES) {
3712 ret = -EINVAL;
3713 pr_err("%s: %s: invalid phase selected=%d\n",
3714 mmc_hostname(host->mmc), __func__, ret);
3715 }
3716
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303717 return ret;
3718}
3719
Girish K Sa3f41692012-02-29 12:00:09 +05303720static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303721{
3722 int rc = 0;
3723 struct msmsdcc_host *host = mmc_priv(mmc);
3724 unsigned long flags;
3725 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303726 const u32 *tuning_block_pattern = tuning_block_64;
3727 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303728
3729 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3730
3731 /* Tuning is only required for SDR104 modes */
3732 if (!host->tuning_needed) {
3733 rc = 0;
3734 goto exit;
3735 }
3736
3737 spin_lock_irqsave(&host->lock, flags);
3738 WARN(!host->pwr, "SDCC power is turned off\n");
3739 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3740 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3741
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303742 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303743 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3744 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3745 tuning_block_pattern = tuning_block_128;
3746 size = sizeof(tuning_block_128);
3747 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303748 spin_unlock_irqrestore(&host->lock, flags);
3749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 /* first of all reset the tuning block */
3751 rc = msmsdcc_init_cm_sdc4_dll(host);
3752 if (rc)
3753 goto out;
3754
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303755 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003756 if (!data_buf) {
3757 rc = -ENOMEM;
3758 goto out;
3759 }
3760
3761 phase = 0;
3762 do {
3763 struct mmc_command cmd = {0};
3764 struct mmc_data data = {0};
3765 struct mmc_request mrq = {
3766 .cmd = &cmd,
3767 .data = &data
3768 };
3769 struct scatterlist sg;
3770
3771 /* set the phase in delay line hw block */
3772 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3773 if (rc)
3774 goto kfree;
3775
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303776 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003777 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3778
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303779 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 data.blocks = 1;
3781 data.flags = MMC_DATA_READ;
3782 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3783
3784 data.sg = &sg;
3785 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303786 sg_init_one(&sg, data_buf, size);
3787 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003788 mmc_wait_for_req(mmc, &mrq);
3789
3790 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303791 !memcmp(data_buf, tuning_block_pattern, size)) {
3792 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003793 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303794 pr_debug("%s: %s: found good phase = %d\n",
3795 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003796 }
3797 } while (++phase < 16);
3798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303800 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303801 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303802 if (rc < 0)
3803 goto kfree;
3804 else
3805 phase = (u8)rc;
3806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807 /*
3808 * Finally set the selected phase in delay
3809 * line hw block.
3810 */
3811 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3812 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303813 goto kfree;
3814 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3815 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816 } else {
3817 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303818 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303820 msmsdcc_dump_sdcc_state(host);
3821 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003822 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003823
3824kfree:
3825 kfree(data_buf);
3826out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303827 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303828 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303829 spin_unlock_irqrestore(&host->lock, flags);
3830exit:
3831 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003832 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003833}
3834
3835static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836 .enable = msmsdcc_enable,
3837 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303838 .pre_req = msmsdcc_pre_req,
3839 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003840 .request = msmsdcc_request,
3841 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003842 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003843 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003844 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3845 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003846};
3847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848static unsigned int
3849msmsdcc_slot_status(struct msmsdcc_host *host)
3850{
3851 int status;
3852 unsigned int gpio_no = host->plat->status_gpio;
3853
3854 status = gpio_request(gpio_no, "SD_HW_Detect");
3855 if (status) {
3856 pr_err("%s: %s: Failed to request GPIO %d\n",
3857 mmc_hostname(host->mmc), __func__, gpio_no);
3858 } else {
3859 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003860 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003861 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003862 if (host->plat->is_status_gpio_active_low)
3863 status = !status;
3864 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003865 gpio_free(gpio_no);
3866 }
3867 return status;
3868}
3869
San Mehat9d2bd732009-09-22 16:44:22 -07003870static void
3871msmsdcc_check_status(unsigned long data)
3872{
3873 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3874 unsigned int status;
3875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003876 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003877 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003879 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003880 status = msmsdcc_slot_status(host);
3881
Krishna Konda941604a2012-01-10 17:46:34 -08003882 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003883
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003885 if (host->plat->status)
3886 pr_info("%s: Slot status change detected "
3887 "(%d -> %d)\n",
3888 mmc_hostname(host->mmc),
3889 host->oldstat, status);
3890 else if (host->plat->is_status_gpio_active_low)
3891 pr_info("%s: Slot status change detected "
3892 "(%d -> %d) and the card detect GPIO"
3893 " is ACTIVE_LOW\n",
3894 mmc_hostname(host->mmc),
3895 host->oldstat, status);
3896 else
3897 pr_info("%s: Slot status change detected "
3898 "(%d -> %d) and the card detect GPIO"
3899 " is ACTIVE_HIGH\n",
3900 mmc_hostname(host->mmc),
3901 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003902 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 }
3904 host->oldstat = status;
3905 } else {
3906 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003907 }
San Mehat9d2bd732009-09-22 16:44:22 -07003908}
3909
3910static irqreturn_t
3911msmsdcc_platform_status_irq(int irq, void *dev_id)
3912{
3913 struct msmsdcc_host *host = dev_id;
3914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003916 msmsdcc_check_status((unsigned long) host);
3917 return IRQ_HANDLED;
3918}
3919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920static irqreturn_t
3921msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3922{
3923 struct msmsdcc_host *host = dev_id;
3924
3925 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3926 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303927 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303929 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003930 wake_lock(&host->sdio_wlock);
3931 msmsdcc_disable_irq_wake(host);
3932 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303933 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934 }
3935 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303937 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003938 }
3939 spin_unlock(&host->lock);
3940
3941 return IRQ_HANDLED;
3942}
3943
San Mehat9d2bd732009-09-22 16:44:22 -07003944static void
3945msmsdcc_status_notify_cb(int card_present, void *dev_id)
3946{
3947 struct msmsdcc_host *host = dev_id;
3948
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003950 card_present);
3951 msmsdcc_check_status((unsigned long) host);
3952}
3953
San Mehat9d2bd732009-09-22 16:44:22 -07003954static int
3955msmsdcc_init_dma(struct msmsdcc_host *host)
3956{
3957 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3958 host->dma.host = host;
3959 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003960 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003961
3962 if (!host->dmares)
3963 return -ENODEV;
3964
3965 host->dma.nc = dma_alloc_coherent(NULL,
3966 sizeof(struct msmsdcc_nc_dmadata),
3967 &host->dma.nc_busaddr,
3968 GFP_KERNEL);
3969 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003970 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003971 return -ENOMEM;
3972 }
3973 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3974 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3975 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3976 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3977 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003978 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003979
3980 return 0;
3981}
3982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003983#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3984/**
3985 * Allocate and Connect a SDCC peripheral's SPS endpoint
3986 *
3987 * This function allocates endpoint context and
3988 * connect it with memory endpoint by calling
3989 * appropriate SPS driver APIs.
3990 *
3991 * Also registers a SPS callback function with
3992 * SPS driver
3993 *
3994 * This function should only be called once typically
3995 * during driver probe.
3996 *
3997 * @host - Pointer to sdcc host structure
3998 * @ep - Pointer to sps endpoint data structure
3999 * @is_produce - 1 means Producer endpoint
4000 * 0 means Consumer endpoint
4001 *
4002 * @return - 0 if successful else negative value.
4003 *
4004 */
4005static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
4006 struct msmsdcc_sps_ep_conn_data *ep,
4007 bool is_producer)
4008{
4009 int rc = 0;
4010 struct sps_pipe *sps_pipe_handle;
4011 struct sps_connect *sps_config = &ep->config;
4012 struct sps_register_event *sps_event = &ep->event;
4013
4014 /* Allocate endpoint context */
4015 sps_pipe_handle = sps_alloc_endpoint();
4016 if (!sps_pipe_handle) {
4017 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4018 mmc_hostname(host->mmc), is_producer);
4019 rc = -ENOMEM;
4020 goto out;
4021 }
4022
4023 /* Get default connection configuration for an endpoint */
4024 rc = sps_get_config(sps_pipe_handle, sps_config);
4025 if (rc) {
4026 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4027 " rc=%d", mmc_hostname(host->mmc),
4028 (u32)sps_pipe_handle, rc);
4029 goto get_config_err;
4030 }
4031
4032 /* Modify the default connection configuration */
4033 if (is_producer) {
4034 /*
4035 * For SDCC producer transfer, source should be
4036 * SDCC peripheral where as destination should
4037 * be system memory.
4038 */
4039 sps_config->source = host->sps.bam_handle;
4040 sps_config->destination = SPS_DEV_HANDLE_MEM;
4041 /* Producer pipe will handle this connection */
4042 sps_config->mode = SPS_MODE_SRC;
4043 sps_config->options =
4044 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4045 } else {
4046 /*
4047 * For SDCC consumer transfer, source should be
4048 * system memory where as destination should
4049 * SDCC peripheral
4050 */
4051 sps_config->source = SPS_DEV_HANDLE_MEM;
4052 sps_config->destination = host->sps.bam_handle;
4053 sps_config->mode = SPS_MODE_DEST;
4054 sps_config->options =
4055 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4056 }
4057
4058 /* Producer pipe index */
4059 sps_config->src_pipe_index = host->sps.src_pipe_index;
4060 /* Consumer pipe index */
4061 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4062 /*
4063 * This event thresold value is only significant for BAM-to-BAM
4064 * transfer. It's ignored for BAM-to-System mode transfer.
4065 */
4066 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304067
4068 /* Allocate maximum descriptor fifo size */
4069 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4070 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4072 sps_config->desc.size,
4073 &sps_config->desc.phys_base,
4074 GFP_KERNEL);
4075
Pratibhasagar V00b94332011-10-18 14:57:27 +05304076 if (!sps_config->desc.base) {
4077 rc = -ENOMEM;
4078 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4079 , mmc_hostname(host->mmc));
4080 goto get_config_err;
4081 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4083
4084 /* Establish connection between peripheral and memory endpoint */
4085 rc = sps_connect(sps_pipe_handle, sps_config);
4086 if (rc) {
4087 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4088 " rc=%d", mmc_hostname(host->mmc),
4089 (u32)sps_pipe_handle, rc);
4090 goto sps_connect_err;
4091 }
4092
4093 sps_event->mode = SPS_TRIGGER_CALLBACK;
4094 sps_event->options = SPS_O_EOT;
4095 sps_event->callback = msmsdcc_sps_complete_cb;
4096 sps_event->xfer_done = NULL;
4097 sps_event->user = (void *)host;
4098
4099 /* Register callback event for EOT (End of transfer) event. */
4100 rc = sps_register_event(sps_pipe_handle, sps_event);
4101 if (rc) {
4102 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4103 " rc=%d", mmc_hostname(host->mmc),
4104 (u32)sps_pipe_handle, rc);
4105 goto reg_event_err;
4106 }
4107 /* Now save the sps pipe handle */
4108 ep->pipe_handle = sps_pipe_handle;
4109 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4110 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4111 __func__, is_producer ? "READ" : "WRITE",
4112 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4113 goto out;
4114
4115reg_event_err:
4116 sps_disconnect(sps_pipe_handle);
4117sps_connect_err:
4118 dma_free_coherent(mmc_dev(host->mmc),
4119 sps_config->desc.size,
4120 sps_config->desc.base,
4121 sps_config->desc.phys_base);
4122get_config_err:
4123 sps_free_endpoint(sps_pipe_handle);
4124out:
4125 return rc;
4126}
4127
4128/**
4129 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4130 *
4131 * This function disconnect endpoint and deallocates
4132 * endpoint context.
4133 *
4134 * This function should only be called once typically
4135 * during driver remove.
4136 *
4137 * @host - Pointer to sdcc host structure
4138 * @ep - Pointer to sps endpoint data structure
4139 *
4140 */
4141static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4142 struct msmsdcc_sps_ep_conn_data *ep)
4143{
4144 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4145 struct sps_connect *sps_config = &ep->config;
4146 struct sps_register_event *sps_event = &ep->event;
4147
4148 sps_event->xfer_done = NULL;
4149 sps_event->callback = NULL;
4150 sps_register_event(sps_pipe_handle, sps_event);
4151 sps_disconnect(sps_pipe_handle);
4152 dma_free_coherent(mmc_dev(host->mmc),
4153 sps_config->desc.size,
4154 sps_config->desc.base,
4155 sps_config->desc.phys_base);
4156 sps_free_endpoint(sps_pipe_handle);
4157}
4158
4159/**
4160 * Reset SDCC peripheral's SPS endpoint
4161 *
4162 * This function disconnects an endpoint.
4163 *
4164 * This function should be called for reseting
4165 * SPS endpoint when data transfer error is
4166 * encountered during data transfer. This
4167 * can be considered as soft reset to endpoint.
4168 *
4169 * This function should only be called if
4170 * msmsdcc_sps_init() is already called.
4171 *
4172 * @host - Pointer to sdcc host structure
4173 * @ep - Pointer to sps endpoint data structure
4174 *
4175 * @return - 0 if successful else negative value.
4176 */
4177static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4178 struct msmsdcc_sps_ep_conn_data *ep)
4179{
4180 int rc = 0;
4181 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4182
4183 rc = sps_disconnect(sps_pipe_handle);
4184 if (rc) {
4185 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4186 " rc=%d", mmc_hostname(host->mmc), __func__,
4187 (u32)sps_pipe_handle, rc);
4188 goto out;
4189 }
4190 out:
4191 return rc;
4192}
4193
4194/**
4195 * Restore SDCC peripheral's SPS endpoint
4196 *
4197 * This function connects an endpoint.
4198 *
4199 * This function should be called for restoring
4200 * SPS endpoint after data transfer error is
4201 * encountered during data transfer. This
4202 * can be considered as soft reset to endpoint.
4203 *
4204 * This function should only be called if
4205 * msmsdcc_sps_reset_ep() is called before.
4206 *
4207 * @host - Pointer to sdcc host structure
4208 * @ep - Pointer to sps endpoint data structure
4209 *
4210 * @return - 0 if successful else negative value.
4211 */
4212static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4213 struct msmsdcc_sps_ep_conn_data *ep)
4214{
4215 int rc = 0;
4216 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4217 struct sps_connect *sps_config = &ep->config;
4218 struct sps_register_event *sps_event = &ep->event;
4219
4220 /* Establish connection between peripheral and memory endpoint */
4221 rc = sps_connect(sps_pipe_handle, sps_config);
4222 if (rc) {
4223 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4224 " rc=%d", mmc_hostname(host->mmc), __func__,
4225 (u32)sps_pipe_handle, rc);
4226 goto out;
4227 }
4228
4229 /* Register callback event for EOT (End of transfer) event. */
4230 rc = sps_register_event(sps_pipe_handle, sps_event);
4231 if (rc) {
4232 pr_err("%s: %s: sps_register_event() failed!!!"
4233 " pipe_handle=0x%x, rc=%d",
4234 mmc_hostname(host->mmc), __func__,
4235 (u32)sps_pipe_handle, rc);
4236 goto reg_event_err;
4237 }
4238 goto out;
4239
4240reg_event_err:
4241 sps_disconnect(sps_pipe_handle);
4242out:
4243 return rc;
4244}
4245
4246/**
4247 * Initialize SPS HW connected with SDCC core
4248 *
4249 * This function register BAM HW resources with
4250 * SPS driver and then initialize 2 SPS endpoints
4251 *
4252 * This function should only be called once typically
4253 * during driver probe.
4254 *
4255 * @host - Pointer to sdcc host structure
4256 *
4257 * @return - 0 if successful else negative value.
4258 *
4259 */
4260static int msmsdcc_sps_init(struct msmsdcc_host *host)
4261{
4262 int rc = 0;
4263 struct sps_bam_props bam = {0};
4264
4265 host->bam_base = ioremap(host->bam_memres->start,
4266 resource_size(host->bam_memres));
4267 if (!host->bam_base) {
4268 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4269 " size=0x%x", mmc_hostname(host->mmc),
4270 host->bam_memres->start,
4271 (host->bam_memres->end -
4272 host->bam_memres->start));
4273 rc = -ENOMEM;
4274 goto out;
4275 }
4276
4277 bam.phys_addr = host->bam_memres->start;
4278 bam.virt_addr = host->bam_base;
4279 /*
4280 * This event thresold value is only significant for BAM-to-BAM
4281 * transfer. It's ignored for BAM-to-System mode transfer.
4282 */
4283 bam.event_threshold = 0x10; /* Pipe event threshold */
4284 /*
4285 * This threshold controls when the BAM publish
4286 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304287 * SPS HW will be used for data transfer size even
4288 * less than SDCC FIFO size. So let's set BAM summing
4289 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004290 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304291 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004292 /* SPS driver wll handle the SDCC BAM IRQ */
4293 bam.irq = (u32)host->bam_irqres->start;
4294 bam.manage = SPS_BAM_MGR_LOCAL;
4295
4296 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4297 (u32)bam.phys_addr);
4298 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4299 (u32)bam.virt_addr);
4300
4301 /* Register SDCC Peripheral BAM device to SPS driver */
4302 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4303 if (rc) {
4304 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4305 mmc_hostname(host->mmc), rc);
4306 goto reg_bam_err;
4307 }
4308 pr_info("%s: BAM device registered. bam_handle=0x%x",
4309 mmc_hostname(host->mmc), host->sps.bam_handle);
4310
4311 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4312 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4313
4314 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4315 SPS_PROD_PERIPHERAL);
4316 if (rc)
4317 goto sps_reset_err;
4318 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4319 SPS_CONS_PERIPHERAL);
4320 if (rc)
4321 goto cons_conn_err;
4322
4323 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4324 mmc_hostname(host->mmc),
4325 (unsigned long long)host->bam_memres->start,
4326 (unsigned int)host->bam_irqres->start);
4327 goto out;
4328
4329cons_conn_err:
4330 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4331sps_reset_err:
4332 sps_deregister_bam_device(host->sps.bam_handle);
4333reg_bam_err:
4334 iounmap(host->bam_base);
4335out:
4336 return rc;
4337}
4338
4339/**
4340 * De-initialize SPS HW connected with SDCC core
4341 *
4342 * This function deinitialize SPS endpoints and then
4343 * deregisters BAM resources from SPS driver.
4344 *
4345 * This function should only be called once typically
4346 * during driver remove.
4347 *
4348 * @host - Pointer to sdcc host structure
4349 *
4350 */
4351static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4352{
4353 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4354 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4355 sps_deregister_bam_device(host->sps.bam_handle);
4356 iounmap(host->bam_base);
4357}
4358#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4359
4360static ssize_t
4361show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4362{
4363 struct mmc_host *mmc = dev_get_drvdata(dev);
4364 struct msmsdcc_host *host = mmc_priv(mmc);
4365 int poll;
4366 unsigned long flags;
4367
4368 spin_lock_irqsave(&host->lock, flags);
4369 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4370 spin_unlock_irqrestore(&host->lock, flags);
4371
4372 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4373}
4374
4375static ssize_t
4376set_polling(struct device *dev, struct device_attribute *attr,
4377 const char *buf, size_t count)
4378{
4379 struct mmc_host *mmc = dev_get_drvdata(dev);
4380 struct msmsdcc_host *host = mmc_priv(mmc);
4381 int value;
4382 unsigned long flags;
4383
4384 sscanf(buf, "%d", &value);
4385
4386 spin_lock_irqsave(&host->lock, flags);
4387 if (value) {
4388 mmc->caps |= MMC_CAP_NEEDS_POLL;
4389 mmc_detect_change(host->mmc, 0);
4390 } else {
4391 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4392 }
4393#ifdef CONFIG_HAS_EARLYSUSPEND
4394 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4395#endif
4396 spin_unlock_irqrestore(&host->lock, flags);
4397 return count;
4398}
4399
4400static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4401 show_polling, set_polling);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304402
4403static ssize_t
4404show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4405 char *buf)
4406{
4407 struct mmc_host *mmc = dev_get_drvdata(dev);
4408 struct msmsdcc_host *host = mmc_priv(mmc);
4409
4410 return snprintf(buf, PAGE_SIZE, "%u\n",
4411 host->msm_bus_vote.is_max_bw_needed);
4412}
4413
4414static ssize_t
4415set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4416 const char *buf, size_t count)
4417{
4418 struct mmc_host *mmc = dev_get_drvdata(dev);
4419 struct msmsdcc_host *host = mmc_priv(mmc);
4420 uint32_t value;
4421 unsigned long flags;
4422
4423 if (!kstrtou32(buf, 0, &value)) {
4424 spin_lock_irqsave(&host->lock, flags);
4425 host->msm_bus_vote.is_max_bw_needed = !!value;
4426 spin_unlock_irqrestore(&host->lock, flags);
4427 }
4428
4429 return count;
4430}
4431
4432static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
4433 show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
4434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004435static struct attribute *dev_attrs[] = {
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304436 &dev_attr_max_bus_bw.attr,
4437 /* if polling is enabled, this will be filled with dev_attr_polling */
4438 NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004439 NULL,
4440};
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004442static struct attribute_group dev_attr_grp = {
4443 .attrs = dev_attrs,
4444};
4445
4446#ifdef CONFIG_HAS_EARLYSUSPEND
4447static void msmsdcc_early_suspend(struct early_suspend *h)
4448{
4449 struct msmsdcc_host *host =
4450 container_of(h, struct msmsdcc_host, early_suspend);
4451 unsigned long flags;
4452
4453 spin_lock_irqsave(&host->lock, flags);
4454 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4455 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4456 spin_unlock_irqrestore(&host->lock, flags);
4457};
4458static void msmsdcc_late_resume(struct early_suspend *h)
4459{
4460 struct msmsdcc_host *host =
4461 container_of(h, struct msmsdcc_host, early_suspend);
4462 unsigned long flags;
4463
4464 if (host->polling_enabled) {
4465 spin_lock_irqsave(&host->lock, flags);
4466 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4467 mmc_detect_change(host->mmc, 0);
4468 spin_unlock_irqrestore(&host->lock, flags);
4469 }
4470};
4471#endif
4472
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304473static void msmsdcc_print_regs(const char *name, void __iomem *base,
4474 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304475{
4476 unsigned int i;
4477
4478 if (!base)
4479 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304480
4481 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4482 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304483 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304484 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4485 (u32)readl_relaxed(base + i*4),
4486 (u32)readl_relaxed(base + ((i+1)*4)),
4487 (u32)readl_relaxed(base + ((i+2)*4)),
4488 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304489 }
4490}
4491
4492static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4493{
4494 /* Dump current state of SDCC clocks, power and irq */
4495 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304496 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304497 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304498 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4499 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304500 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4501 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4502
4503 /* Now dump SDCC registers. Don't print FIFO registers */
4504 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304505 msmsdcc_print_regs("SDCC-CORE", host->base,
4506 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304507
4508 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304509 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304510 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4511 else if (host->is_dma_mode)
4512 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4513 mmc_hostname(host->mmc), host->dma.busy,
4514 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304515 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304516 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304517 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4518 host->dml_memres->start,
4519 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304520 pr_info("%s: SPS mode: busy=%d\n",
4521 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304522 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304523
4524 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4525 mmc_hostname(host->mmc), host->curr.xfer_size,
4526 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304527 }
4528
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304529 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4530 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4531 mmc_hostname(host->mmc), host->curr.got_dataend,
4532 host->prog_enable, host->curr.wait_for_auto_prog_done,
4533 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304534 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304535}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004537static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4538{
4539 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4540 struct mmc_request *mrq;
4541 unsigned long flags;
4542
4543 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004544 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545 pr_info("%s: %s: dummy CMD52 timeout\n",
4546 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004547 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548 }
4549
4550 mrq = host->curr.mrq;
4551
4552 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304553 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4554 mrq->cmd->opcode);
4555 msmsdcc_dump_sdcc_state(host);
4556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557 if (!mrq->cmd->error)
4558 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304559 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004560 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004561 if (mrq->data && !mrq->data->error)
4562 mrq->data->error = -ETIMEDOUT;
4563 host->curr.data_xfered = 0;
4564 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004565 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566 } else if (host->sps.sg && host->is_sps_mode) {
4567 /* Stop current SPS transfer */
4568 msmsdcc_sps_exit_curr_xfer(host);
4569 } else {
4570 msmsdcc_reset_and_restore(host);
4571 msmsdcc_stop_data(host);
4572 if (mrq->data && mrq->data->stop)
4573 msmsdcc_start_command(host,
4574 mrq->data->stop, 0);
4575 else
4576 msmsdcc_request_end(host, mrq);
4577 }
4578 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304579 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304580 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004581 msmsdcc_reset_and_restore(host);
4582 msmsdcc_request_end(host, mrq);
4583 }
4584 }
4585 spin_unlock_irqrestore(&host->lock, flags);
4586}
4587
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304588static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4589{
4590 int i, ret;
4591 struct mmc_platform_data *pdata;
4592 struct device_node *np = dev->of_node;
4593 u32 bus_width = 0;
4594 u32 *clk_table;
4595 int clk_table_len;
4596 u32 *sup_voltages;
4597 int sup_volt_len;
4598
4599 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4600 if (!pdata) {
4601 dev_err(dev, "could not allocate memory for platform data\n");
4602 goto err;
4603 }
4604
4605 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4606 if (bus_width == 8) {
4607 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4608 } else if (bus_width == 4) {
4609 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4610 } else {
4611 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4612 pdata->mmc_bus_width = 0;
4613 }
4614
4615 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4616 size_t sz;
4617 sz = sup_volt_len / sizeof(*sup_voltages);
4618 if (sz > 0) {
4619 sup_voltages = devm_kzalloc(dev,
4620 sz * sizeof(*sup_voltages), GFP_KERNEL);
4621 if (!sup_voltages) {
4622 dev_err(dev, "No memory for supported voltage\n");
4623 goto err;
4624 }
4625
4626 ret = of_property_read_u32_array(np,
4627 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4628 if (ret < 0) {
4629 dev_err(dev, "error while reading voltage"
4630 "ranges %d\n", ret);
4631 goto err;
4632 }
4633 } else {
4634 dev_err(dev, "No supported voltages\n");
4635 goto err;
4636 }
4637 for (i = 0; i < sz; i += 2) {
4638 u32 mask;
4639
4640 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4641 sup_voltages[i + 1]);
4642 if (!mask)
4643 dev_err(dev, "Invalide voltage range %d\n", i);
4644 pdata->ocr_mask |= mask;
4645 }
4646 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4647 } else {
4648 dev_err(dev, "Supported voltage range not specified\n");
4649 }
4650
4651 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4652 size_t sz;
4653 sz = clk_table_len / sizeof(*clk_table);
4654
4655 if (sz > 0) {
4656 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4657 GFP_KERNEL);
4658 if (!clk_table) {
4659 dev_err(dev, "No memory for clock table\n");
4660 goto err;
4661 }
4662
4663 ret = of_property_read_u32_array(np,
4664 "qcom,sdcc-clk-rates", clk_table, sz);
4665 if (ret < 0) {
4666 dev_err(dev, "error while reading clk"
4667 "table %d\n", ret);
4668 goto err;
4669 }
4670 } else {
4671 dev_err(dev, "clk_table not specified\n");
4672 goto err;
4673 }
4674 pdata->sup_clk_table = clk_table;
4675 pdata->sup_clk_cnt = sz;
4676 } else {
4677 dev_err(dev, "Supported clock rates not specified\n");
4678 }
4679
4680 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4681 pdata->nonremovable = true;
4682 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4683 pdata->disable_cmd23 = true;
4684
4685 return pdata;
4686err:
4687 return NULL;
4688}
4689
San Mehat9d2bd732009-09-22 16:44:22 -07004690static int
4691msmsdcc_probe(struct platform_device *pdev)
4692{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304693 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004694 struct msmsdcc_host *host;
4695 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004696 unsigned long flags;
4697 struct resource *core_irqres = NULL;
4698 struct resource *bam_irqres = NULL;
4699 struct resource *core_memres = NULL;
4700 struct resource *dml_memres = NULL;
4701 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004702 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004703 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304704 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004705 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004706
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304707 if (pdev->dev.of_node) {
4708 plat = msmsdcc_populate_pdata(&pdev->dev);
4709 of_property_read_u32((&pdev->dev)->of_node,
4710 "cell-index", &pdev->id);
4711 } else {
4712 plat = pdev->dev.platform_data;
4713 }
4714
San Mehat9d2bd732009-09-22 16:44:22 -07004715 /* must have platform data */
4716 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004717 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004718 ret = -EINVAL;
4719 goto out;
4720 }
4721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004722 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004723 return -EINVAL;
4724
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304725 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4726 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4727 return -EINVAL;
4728 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004729
San Mehat9d2bd732009-09-22 16:44:22 -07004730 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004731 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004732 return -ENXIO;
4733 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304734 if (pdev->dev.of_node) {
4735 /*
4736 * Device tree iomem resources are only accessible by index.
4737 * index = 0 -> SDCC register interface
4738 * index = 1 -> DML register interface
4739 * index = 2 -> BAM register interface
4740 * IRQ resources:
4741 * index = 0 -> SDCC IRQ
4742 * index = 1 -> BAM IRQ
4743 */
4744 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4745 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4746 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4747 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4748 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4749 } else {
4750 for (i = 0; i < pdev->num_resources; i++) {
4751 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4752 if (!strncmp(pdev->resource[i].name,
4753 "sdcc_dml_addr",
4754 sizeof("sdcc_dml_addr")))
4755 dml_memres = &pdev->resource[i];
4756 else if (!strncmp(pdev->resource[i].name,
4757 "sdcc_bam_addr",
4758 sizeof("sdcc_bam_addr")))
4759 bam_memres = &pdev->resource[i];
4760 else
4761 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004762
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304763 }
4764 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4765 if (!strncmp(pdev->resource[i].name,
4766 "sdcc_bam_irq",
4767 sizeof("sdcc_bam_irq")))
4768 bam_irqres = &pdev->resource[i];
4769 else
4770 core_irqres = &pdev->resource[i];
4771 }
4772 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4773 if (!strncmp(pdev->resource[i].name,
4774 "sdcc_dma_chnl",
4775 sizeof("sdcc_dma_chnl")))
4776 dmares = &pdev->resource[i];
4777 else if (!strncmp(pdev->resource[i].name,
4778 "sdcc_dma_crci",
4779 sizeof("sdcc_dma_crci")))
4780 dma_crci_res = &pdev->resource[i];
4781 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004782 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783 }
4784
4785 if (!core_irqres || !core_memres) {
4786 pr_err("%s: Invalid sdcc core resource\n", __func__);
4787 return -ENXIO;
4788 }
4789
4790 /*
4791 * Both BAM and DML memory resource should be preset.
4792 * BAM IRQ resource should also be present.
4793 */
4794 if ((bam_memres && !dml_memres) ||
4795 (!bam_memres && dml_memres) ||
4796 ((bam_memres && dml_memres) && !bam_irqres)) {
4797 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004798 return -ENXIO;
4799 }
4800
4801 /*
4802 * Setup our host structure
4803 */
San Mehat9d2bd732009-09-22 16:44:22 -07004804 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4805 if (!mmc) {
4806 ret = -ENOMEM;
4807 goto out;
4808 }
4809
4810 host = mmc_priv(mmc);
4811 host->pdev_id = pdev->id;
4812 host->plat = plat;
4813 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004814 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304815
4816 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004817 host->is_sps_mode = 1;
4818 else if (dmares)
4819 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 host->base = ioremap(core_memres->start,
4822 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004823 if (!host->base) {
4824 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004825 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004826 }
4827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004828 host->core_irqres = core_irqres;
4829 host->bam_irqres = bam_irqres;
4830 host->core_memres = core_memres;
4831 host->dml_memres = dml_memres;
4832 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004833 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004834 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004835 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304836 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838#ifdef CONFIG_MMC_EMBEDDED_SDIO
4839 if (plat->embedded_sdio)
4840 mmc_set_embedded_sdio_data(mmc,
4841 &plat->embedded_sdio->cis,
4842 &plat->embedded_sdio->cccr,
4843 plat->embedded_sdio->funcs,
4844 plat->embedded_sdio->num_funcs);
4845#endif
4846
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304847 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4848 (unsigned long)host);
4849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004850 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4851 (unsigned long)host);
4852 if (host->is_dma_mode) {
4853 /* Setup DMA */
4854 ret = msmsdcc_init_dma(host);
4855 if (ret)
4856 goto ioremap_free;
4857 } else {
4858 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004859 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004860 }
4861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004862 /*
4863 * Setup SDCC clock if derived from Dayatona
4864 * fabric core clock.
4865 */
4866 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004867 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004868 if (!IS_ERR(host->dfab_pclk)) {
4869 /* Set the clock rate to 64MHz for max. performance */
4870 ret = clk_set_rate(host->dfab_pclk, 64000000);
4871 if (ret)
4872 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304873 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004874 if (ret)
4875 goto dfab_pclk_put;
4876 } else
4877 goto dma_free;
4878 }
4879
4880 /*
4881 * Setup main peripheral bus clock
4882 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004883 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004884 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304885 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004886 if (ret)
4887 goto pclk_put;
4888
4889 host->pclk_rate = clk_get_rate(host->pclk);
4890 }
4891
4892 /*
4893 * Setup SDC MMC clock
4894 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004895 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004896 if (IS_ERR(host->clk)) {
4897 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004898 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004899 }
4900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004901 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4902 if (ret) {
4903 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4904 goto clk_put;
4905 }
4906
Asutosh Dasf5298c32012-04-03 14:51:47 +05304907 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004908 if (ret)
4909 goto clk_put;
4910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004911 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304912 if (!host->clk_rate)
4913 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304914
4915 /*
4916 * Lookup the Controller Version, to identify the supported features
4917 * Version number read as 0 would indicate SDCC3 or earlier versions
4918 */
4919 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4920 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4921 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304922 /*
4923 * Set the register write delay according to min. clock frequency
4924 * supported and update later when the host->clk_rate changes.
4925 */
4926 host->reg_write_delay =
4927 (1 + ((3 * USEC_PER_SEC) /
4928 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004929
4930 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304931 /* Apply Hard reset to SDCC to put it in power on default state */
4932 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004933
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004934#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304935 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004936 if (host->plat->cpu_dma_latency)
4937 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4938 else
4939 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4940 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304941 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4942
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304943 ret = msmsdcc_msm_bus_register(host);
4944 if (ret)
4945 goto pm_qos_remove;
4946
4947 if (host->msm_bus_vote.client_handle)
4948 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4949 msmsdcc_msm_bus_work);
4950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004952 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004953 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004954 goto clk_disable;
4955 }
4956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004957
4958 /* Clocks has to be running before accessing SPS/DML HW blocks */
4959 if (host->is_sps_mode) {
4960 /* Initialize SPS */
4961 ret = msmsdcc_sps_init(host);
4962 if (ret)
4963 goto vreg_deinit;
4964 /* Initialize DML */
4965 ret = msmsdcc_dml_init(host);
4966 if (ret)
4967 goto sps_exit;
4968 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304969 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004970
San Mehat9d2bd732009-09-22 16:44:22 -07004971 /*
4972 * Setup MMC host structure
4973 */
4974 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004975 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4976 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004977 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004978 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4979 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004980
San Mehat9d2bd732009-09-22 16:44:22 -07004981 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304982 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304983
4984 /*
4985 * If we send the CMD23 before multi block write/read command
4986 * then we need not to send CMD12 at the end of the transfer.
4987 * If we don't send the CMD12 then only way to detect the PROG_DONE
4988 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4989 * controller. So let's enable the CMD23 for SDCC4 only.
4990 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304991 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304992 mmc->caps |= MMC_CAP_CMD23;
4993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994 mmc->caps |= plat->uhs_caps;
4995 /*
4996 * XPC controls the maximum current in the default speed mode of SDXC
4997 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4998 * XPC=1 means 150mA (max.) and speed class is supported.
4999 */
5000 if (plat->xpc_cap)
5001 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
5002 MMC_CAP_SET_XPC_180);
5003
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05305004 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05305005 if (pdev->dev.of_node) {
5006 if (of_get_property((&pdev->dev)->of_node,
5007 "qcom,sdcc-hs200", NULL))
5008 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5009 }
5010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005011 if (plat->nonremovable)
5012 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005013 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005014
5015 if (plat->is_sdio_al_client)
5016 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005017
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305018 mmc->max_segs = msmsdcc_get_nr_sg(host);
5019 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5020 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005021
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305022 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05305023 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07005024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005025 writel_relaxed(0, host->base + MMCIMASK0);
5026 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305027 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005029 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5030 mb();
5031 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5034 DRIVER_NAME " (cmd)", host);
5035 if (ret)
5036 goto dml_exit;
5037
5038 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5039 DRIVER_NAME " (pio)", host);
5040 if (ret)
5041 goto irq_free;
5042
5043 /*
5044 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5045 * IRQ is un-necessarily being monitored by MPM (Modem power
5046 * management block) during idle-power collapse. The MPM will be
5047 * configured to monitor the DATA1 GPIO line with level-low trigger
5048 * and thus depending on the GPIO status, it prevents TCXO shutdown
5049 * during idle-power collapse.
5050 */
5051 disable_irq(core_irqres->start);
5052 host->sdcc_irq_disabled = 1;
5053
5054 if (plat->sdiowakeup_irq) {
5055 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5056 mmc_hostname(mmc));
5057 ret = request_irq(plat->sdiowakeup_irq,
5058 msmsdcc_platform_sdiowakeup_irq,
5059 IRQF_SHARED | IRQF_TRIGGER_LOW,
5060 DRIVER_NAME "sdiowakeup", host);
5061 if (ret) {
5062 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5063 plat->sdiowakeup_irq, ret);
5064 goto pio_irq_free;
5065 } else {
5066 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305067 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005068 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305069 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005070 }
5071 spin_unlock_irqrestore(&host->lock, flags);
5072 }
5073 }
5074
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305075 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005076 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5077 mmc_hostname(mmc));
5078 }
5079
5080 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5081 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005082 /*
5083 * Setup card detect change
5084 */
5085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005087 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005088 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005089 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005090 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08005091
Krishna Konda941604a2012-01-10 17:46:34 -08005092 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005093 }
San Mehat9d2bd732009-09-22 16:44:22 -07005094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005095 if (plat->status_irq) {
5096 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005097 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005098 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005099 DRIVER_NAME " (slot)",
5100 host);
5101 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005102 pr_err("Unable to get slot IRQ %d (%d)\n",
5103 plat->status_irq, ret);
5104 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005105 }
5106 } else if (plat->register_status_notify) {
5107 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5108 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005109 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005110 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005111
5112 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005113
5114 ret = pm_runtime_set_active(&(pdev)->dev);
5115 if (ret < 0)
5116 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5117 __func__, ret);
5118 /*
5119 * There is no notion of suspend/resume for SD/MMC/SDIO
5120 * cards. So host can be suspended/resumed with out
5121 * worrying about its children.
5122 */
5123 pm_suspend_ignore_children(&(pdev)->dev, true);
5124
5125 /*
5126 * MMC/SD/SDIO bus suspend/resume operations are defined
5127 * only for the slots that will be used for non-removable
5128 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5129 * defined. Otherwise, they simply become card removal and
5130 * insertion events during suspend and resume respectively.
5131 * Hence, enable run-time PM only for slots for which bus
5132 * suspend/resume operations are defined.
5133 */
5134#ifdef CONFIG_MMC_UNSAFE_RESUME
5135 /*
5136 * If this capability is set, MMC core will enable/disable host
5137 * for every claim/release operation on a host. We use this
5138 * notification to increment/decrement runtime pm usage count.
5139 */
5140 mmc->caps |= MMC_CAP_DISABLE;
5141 pm_runtime_enable(&(pdev)->dev);
5142#else
5143 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
5144 mmc->caps |= MMC_CAP_DISABLE;
5145 pm_runtime_enable(&(pdev)->dev);
5146 }
5147#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05305148#ifndef CONFIG_PM_RUNTIME
5149 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
5150#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005151 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5152 (unsigned long)host);
5153
San Mehat9d2bd732009-09-22 16:44:22 -07005154 mmc_add_host(mmc);
5155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005156#ifdef CONFIG_HAS_EARLYSUSPEND
5157 host->early_suspend.suspend = msmsdcc_early_suspend;
5158 host->early_suspend.resume = msmsdcc_late_resume;
5159 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5160 register_early_suspend(&host->early_suspend);
5161#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005162
Krishna Konda25786ec2011-07-25 16:21:36 -07005163 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5164 " dmacrcri %d\n", mmc_hostname(mmc),
5165 (unsigned long long)core_memres->start,
5166 (unsigned int) core_irqres->start,
5167 (unsigned int) plat->status_irq, host->dma.channel,
5168 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005169
5170 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5171 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5172 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5173 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5174 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5175 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5176 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5177 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5178 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5179 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5180 host->eject);
5181 pr_info("%s: Power save feature enable = %d\n",
5182 mmc_hostname(mmc), msmsdcc_pwrsave);
5183
Krishna Konda25786ec2011-07-25 16:21:36 -07005184 if (host->is_dma_mode && host->dma.channel != -1
5185 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005186 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005187 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005188 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189 mmc_hostname(mmc), host->dma.cmd_busaddr,
5190 host->dma.cmdptr_busaddr);
5191 } else if (host->is_sps_mode) {
5192 pr_info("%s: SPS-BAM data transfer mode available\n",
5193 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005194 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005195 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005197#if defined(CONFIG_DEBUG_FS)
5198 msmsdcc_dbg_createhost(host);
5199#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305200 if (!plat->status_irq)
5201 dev_attrs[1] = &dev_attr_polling.attr;
5202
5203 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
5204 if (ret)
5205 goto platform_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005206 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005207
5208 platform_irq_free:
5209 del_timer_sync(&host->req_tout_timer);
5210 pm_runtime_disable(&(pdev)->dev);
5211 pm_runtime_set_suspended(&(pdev)->dev);
5212
5213 if (plat->status_irq)
5214 free_irq(plat->status_irq, host);
5215 sdiowakeup_irq_free:
5216 wake_lock_destroy(&host->sdio_suspend_wlock);
5217 if (plat->sdiowakeup_irq)
5218 free_irq(plat->sdiowakeup_irq, host);
5219 pio_irq_free:
5220 if (plat->sdiowakeup_irq)
5221 wake_lock_destroy(&host->sdio_wlock);
5222 free_irq(core_irqres->start, host);
5223 irq_free:
5224 free_irq(core_irqres->start, host);
5225 dml_exit:
5226 if (host->is_sps_mode)
5227 msmsdcc_dml_exit(host);
5228 sps_exit:
5229 if (host->is_sps_mode)
5230 msmsdcc_sps_exit(host);
5231 vreg_deinit:
5232 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005233 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005234 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305235 msmsdcc_msm_bus_unregister(host);
5236 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005237 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305238 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005239 clk_put:
5240 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005241 pclk_disable:
5242 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305243 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005244 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005245 if (!IS_ERR(host->pclk))
5246 clk_put(host->pclk);
5247 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305248 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005249 dfab_pclk_put:
5250 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5251 clk_put(host->dfab_pclk);
5252 dma_free:
5253 if (host->is_dma_mode) {
5254 if (host->dmares)
5255 dma_free_coherent(NULL,
5256 sizeof(struct msmsdcc_nc_dmadata),
5257 host->dma.nc, host->dma.nc_busaddr);
5258 }
5259 ioremap_free:
5260 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005261 host_free:
5262 mmc_free_host(mmc);
5263 out:
5264 return ret;
5265}
5266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005267static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005268{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005269 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5270 struct mmc_platform_data *plat;
5271 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005273 if (!mmc)
5274 return -ENXIO;
5275
5276 if (pm_runtime_suspended(&(pdev)->dev))
5277 pm_runtime_resume(&(pdev)->dev);
5278
5279 host = mmc_priv(mmc);
5280
5281 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5282 plat = host->plat;
5283
5284 if (!plat->status_irq)
5285 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
5286
5287 del_timer_sync(&host->req_tout_timer);
5288 tasklet_kill(&host->dma_tlet);
5289 tasklet_kill(&host->sps.tlet);
5290 mmc_remove_host(mmc);
5291
5292 if (plat->status_irq)
5293 free_irq(plat->status_irq, host);
5294
5295 wake_lock_destroy(&host->sdio_suspend_wlock);
5296 if (plat->sdiowakeup_irq) {
5297 wake_lock_destroy(&host->sdio_wlock);
5298 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5299 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005300 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005301
5302 free_irq(host->core_irqres->start, host);
5303 free_irq(host->core_irqres->start, host);
5304
5305 clk_put(host->clk);
5306 if (!IS_ERR(host->pclk))
5307 clk_put(host->pclk);
5308 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5309 clk_put(host->dfab_pclk);
5310
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005311 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305312 pm_qos_remove_request(&host->pm_qos_req_dma);
5313
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305314 if (host->msm_bus_vote.client_handle) {
5315 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5316 msmsdcc_msm_bus_unregister(host);
5317 }
5318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005319 msmsdcc_vreg_init(host, false);
5320
5321 if (host->is_dma_mode) {
5322 if (host->dmares)
5323 dma_free_coherent(NULL,
5324 sizeof(struct msmsdcc_nc_dmadata),
5325 host->dma.nc, host->dma.nc_busaddr);
5326 }
5327
5328 if (host->is_sps_mode) {
5329 msmsdcc_dml_exit(host);
5330 msmsdcc_sps_exit(host);
5331 }
5332
5333 iounmap(host->base);
5334 mmc_free_host(mmc);
5335
5336#ifdef CONFIG_HAS_EARLYSUSPEND
5337 unregister_early_suspend(&host->early_suspend);
5338#endif
5339 pm_runtime_disable(&(pdev)->dev);
5340 pm_runtime_set_suspended(&(pdev)->dev);
5341
5342 return 0;
5343}
5344
5345#ifdef CONFIG_MSM_SDIO_AL
5346int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5347{
5348 struct msmsdcc_host *host = mmc_priv(mmc);
5349 unsigned long flags;
5350
Asutosh Dasf5298c32012-04-03 14:51:47 +05305351 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005352 spin_lock_irqsave(&host->lock, flags);
5353 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5354 enable ? "En" : "Dis");
5355
5356 if (enable) {
5357 if (!host->sdcc_irq_disabled) {
5358 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305359 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005360 host->sdcc_irq_disabled = 1;
5361 }
5362
5363 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305364 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005365 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305366 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005367 host->clks_on = 0;
5368 }
5369
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305370 if (host->plat->sdio_lpm_gpio_setup &&
5371 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005372 spin_unlock_irqrestore(&host->lock, flags);
5373 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5374 spin_lock_irqsave(&host->lock, flags);
5375 host->sdio_gpio_lpm = 1;
5376 }
5377
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305378 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005379 msmsdcc_enable_irq_wake(host);
5380 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305381 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005382 }
5383 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305384 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005385 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305386 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005387 msmsdcc_disable_irq_wake(host);
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), 1);
5394 spin_lock_irqsave(&host->lock, flags);
5395 host->sdio_gpio_lpm = 0;
5396 }
5397
5398 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305399 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005400 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305401 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005402 host->clks_on = 1;
5403 }
5404
5405 if (host->sdcc_irq_disabled) {
5406 writel_relaxed(host->mci_irqenable,
5407 host->base + MMCIMASK0);
5408 mb();
5409 enable_irq(host->core_irqres->start);
5410 host->sdcc_irq_disabled = 0;
5411 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005412 }
5413 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305414 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005415 return 0;
5416}
5417#else
5418int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5419{
5420 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005421}
5422#endif
5423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005424#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005425static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005426msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005427{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005428 struct mmc_host *mmc = dev_get_drvdata(dev);
5429 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005430 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305431 unsigned long flags;
5432
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305433 if (host->plat->is_sdio_al_client) {
5434 rc = 0;
5435 goto out;
5436 }
San Mehat9d2bd732009-09-22 16:44:22 -07005437
Sahitya Tummala7661a452011-07-18 13:28:35 +05305438 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005439 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005440 host->sdcc_suspending = 1;
5441 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005443 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005444 * MMC core thinks that host is disabled by now since
5445 * runtime suspend is scheduled after msmsdcc_disable()
5446 * is called. Thus, MMC core will try to enable the host
5447 * while suspending it. This results in a synchronous
5448 * runtime resume request while in runtime suspending
5449 * context and hence inorder to complete this resume
5450 * requet, it will wait for suspend to be complete,
5451 * but runtime suspend also can not proceed further
5452 * until the host is resumed. Thus, it leads to a hang.
5453 * Hence, increase the pm usage count before suspending
5454 * the host so that any resume requests after this will
5455 * simple become pm usage counter increment operations.
5456 */
5457 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305458 /* If there is pending detect work abort runtime suspend */
5459 if (unlikely(work_busy(&mmc->detect.work)))
5460 rc = -EAGAIN;
5461 else
5462 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005463 pm_runtime_put_noidle(dev);
5464
5465 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305466 spin_lock_irqsave(&host->lock, flags);
5467 host->sdcc_suspended = true;
5468 spin_unlock_irqrestore(&host->lock, flags);
5469 if (mmc->card && mmc_card_sdio(mmc->card) &&
5470 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005471 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305472 * If SDIO function driver doesn't want
5473 * to power off the card, atleast turn off
5474 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005475 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305476 mmc_host_clk_hold(mmc);
5477 spin_lock_irqsave(&mmc->clk_lock, flags);
5478 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005479 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305480 mmc->clk_gated = true;
5481 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5482 mmc_set_ios(mmc);
5483 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005484 }
5485 }
5486 host->sdcc_suspending = 0;
5487 mmc->suspend_task = NULL;
5488 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5489 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005490 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305491 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305492out:
5493 /* set bus bandwidth to 0 immediately */
5494 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005495 return rc;
5496}
5497
5498static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005499msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005500{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005501 struct mmc_host *mmc = dev_get_drvdata(dev);
5502 struct msmsdcc_host *host = mmc_priv(mmc);
5503 unsigned long flags;
5504
5505 if (host->plat->is_sdio_al_client)
5506 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005507
Sahitya Tummala7661a452011-07-18 13:28:35 +05305508 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005509 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305510 if (mmc->card && mmc_card_sdio(mmc->card) &&
5511 mmc_card_keep_power(mmc)) {
5512 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305513 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305514 mmc_set_ios(mmc);
5515 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305516 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005517
5518 mmc_resume_host(mmc);
5519
5520 /*
5521 * FIXME: Clearing of flags must be handled in clients
5522 * resume handler.
5523 */
5524 spin_lock_irqsave(&host->lock, flags);
5525 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305526 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005527 spin_unlock_irqrestore(&host->lock, flags);
5528
5529 /*
5530 * After resuming the host wait for sometime so that
5531 * the SDIO work will be processed.
5532 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305533 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305534 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005535 host->plat->sdiowakeup_irq) &&
5536 wake_lock_active(&host->sdio_wlock))
5537 wake_lock_timeout(&host->sdio_wlock, 1);
5538 }
5539
5540 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005541 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305542 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005543 return 0;
5544}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005545
5546static int msmsdcc_runtime_idle(struct device *dev)
5547{
5548 struct mmc_host *mmc = dev_get_drvdata(dev);
5549 struct msmsdcc_host *host = mmc_priv(mmc);
5550
5551 if (host->plat->is_sdio_al_client)
5552 return 0;
5553
5554 /* Idle timeout is not configurable for now */
5555 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5556
5557 return -EAGAIN;
5558}
5559
5560static int msmsdcc_pm_suspend(struct device *dev)
5561{
5562 struct mmc_host *mmc = dev_get_drvdata(dev);
5563 struct msmsdcc_host *host = mmc_priv(mmc);
5564 int rc = 0;
5565
5566 if (host->plat->is_sdio_al_client)
5567 return 0;
5568
5569
5570 if (host->plat->status_irq)
5571 disable_irq(host->plat->status_irq);
5572
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005573 if (!pm_runtime_suspended(dev))
5574 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005575
5576 return rc;
5577}
5578
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305579static int msmsdcc_suspend_noirq(struct device *dev)
5580{
5581 struct mmc_host *mmc = dev_get_drvdata(dev);
5582 struct msmsdcc_host *host = mmc_priv(mmc);
5583 int rc = 0;
5584
5585 /*
5586 * After platform suspend there may be active request
5587 * which might have enabled clocks. For example, in SDIO
5588 * case, ksdioirq thread might have scheduled after sdcc
5589 * suspend but before system freeze. In that case abort
5590 * suspend and retry instead of keeping the clocks on
5591 * during suspend and not allowing TCXO.
5592 */
5593
Asutosh Dasf5298c32012-04-03 14:51:47 +05305594 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305595 pr_warn("%s: clocks are on after suspend, aborting system "
5596 "suspend\n", mmc_hostname(mmc));
5597 rc = -EAGAIN;
5598 }
5599
5600 return rc;
5601}
5602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005603static int msmsdcc_pm_resume(struct device *dev)
5604{
5605 struct mmc_host *mmc = dev_get_drvdata(dev);
5606 struct msmsdcc_host *host = mmc_priv(mmc);
5607 int rc = 0;
5608
5609 if (host->plat->is_sdio_al_client)
5610 return 0;
5611
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005612 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305613 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005614 else
5615 host->pending_resume = true;
5616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005617 if (host->plat->status_irq) {
5618 msmsdcc_check_status((unsigned long)host);
5619 enable_irq(host->plat->status_irq);
5620 }
5621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005622 return rc;
5623}
5624
Daniel Walker08ecfde2010-06-23 12:32:20 -07005625#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005626static int msmsdcc_runtime_suspend(struct device *dev)
5627{
5628 return 0;
5629}
5630static int msmsdcc_runtime_idle(struct device *dev)
5631{
5632 return 0;
5633}
5634static int msmsdcc_pm_suspend(struct device *dev)
5635{
5636 return 0;
5637}
5638static int msmsdcc_pm_resume(struct device *dev)
5639{
5640 return 0;
5641}
5642static int msmsdcc_suspend_noirq(struct device *dev)
5643{
5644 return 0;
5645}
5646static int msmsdcc_runtime_resume(struct device *dev)
5647{
5648 return 0;
5649}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005650#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005652static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5653 .runtime_suspend = msmsdcc_runtime_suspend,
5654 .runtime_resume = msmsdcc_runtime_resume,
5655 .runtime_idle = msmsdcc_runtime_idle,
5656 .suspend = msmsdcc_pm_suspend,
5657 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305658 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005659};
5660
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305661static const struct of_device_id msmsdcc_dt_match[] = {
5662 {.compatible = "qcom,msm-sdcc"},
5663
5664};
5665MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5666
San Mehat9d2bd732009-09-22 16:44:22 -07005667static struct platform_driver msmsdcc_driver = {
5668 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005669 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005670 .driver = {
5671 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005672 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305673 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005674 },
5675};
5676
5677static int __init msmsdcc_init(void)
5678{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005679#if defined(CONFIG_DEBUG_FS)
5680 int ret = 0;
5681 ret = msmsdcc_dbg_init();
5682 if (ret) {
5683 pr_err("Failed to create debug fs dir \n");
5684 return ret;
5685 }
5686#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005687 return platform_driver_register(&msmsdcc_driver);
5688}
5689
5690static void __exit msmsdcc_exit(void)
5691{
5692 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005693
5694#if defined(CONFIG_DEBUG_FS)
5695 debugfs_remove(debugfs_file);
5696 debugfs_remove(debugfs_dir);
5697#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005698}
5699
5700module_init(msmsdcc_init);
5701module_exit(msmsdcc_exit);
5702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005703MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005704MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005705
5706#if defined(CONFIG_DEBUG_FS)
5707
5708static int
5709msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5710{
5711 file->private_data = inode->i_private;
5712 return 0;
5713}
5714
5715static ssize_t
5716msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5717 size_t count, loff_t *ppos)
5718{
5719 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005720 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005721 int max, i;
5722
5723 i = 0;
5724 max = sizeof(buf) - 1;
5725
5726 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5727 host->curr.cmd, host->curr.data);
5728 if (host->curr.cmd) {
5729 struct mmc_command *cmd = host->curr.cmd;
5730
5731 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5732 cmd->opcode, cmd->arg, cmd->flags);
5733 }
5734 if (host->curr.data) {
5735 struct mmc_data *data = host->curr.data;
5736 i += scnprintf(buf + i, max - i,
5737 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5738 data->timeout_ns, data->timeout_clks,
5739 data->blksz, data->blocks, data->error,
5740 data->flags);
5741 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5742 host->curr.xfer_size, host->curr.xfer_remain,
5743 host->curr.data_xfered, host->dma.sg);
5744 }
5745
5746 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5747}
5748
5749static const struct file_operations msmsdcc_dbg_state_ops = {
5750 .read = msmsdcc_dbg_state_read,
5751 .open = msmsdcc_dbg_state_open,
5752};
5753
5754static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5755{
5756 if (debugfs_dir) {
5757 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5758 0644, debugfs_dir, host,
5759 &msmsdcc_dbg_state_ops);
5760 }
5761}
5762
5763static int __init msmsdcc_dbg_init(void)
5764{
5765 int err;
5766
5767 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5768 if (IS_ERR(debugfs_dir)) {
5769 err = PTR_ERR(debugfs_dir);
5770 debugfs_dir = NULL;
5771 return err;
5772 }
5773
5774 return 0;
5775}
5776#endif