blob: edf44005f65ed8a928e222aafa32028dd07ec2c5 [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>
Steve Mucklef132c6c2012-06-06 18:30:57 -070046#include <linux/pm_qos.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 Mehat9d2bd732009-09-22 16:44:22 -0700113
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};
San Mehat865c8062009-11-13 13:42:06 -0800124
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);
San Mehat9d2bd732009-09-22 16:44:22 -0700160
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530161static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530162{
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530163 unsigned short ret = NR_SG;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530164
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530165 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
279 /* Reset the controller */
280 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
281 if (ret)
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530282 pr_err("%s: Clock assert failed at %u Hz"
283 " with err %d\n", mmc_hostname(host->mmc),
284 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530285
286 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
287 if (ret)
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530288 pr_err("%s: Clock deassert failed at %u Hz"
289 " with err %d\n", mmc_hostname(host->mmc),
290 host->clk_rate, ret);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530291
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);
San Mehat9d2bd732009-09-22 16:44:22 -0700354
355 if (mrq->data)
356 mrq->data->bytes_xfered = host->curr.data_xfered;
357 if (mrq->cmd->error == -ETIMEDOUT)
358 mdelay(5);
359
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530360 /* Clear current request information as current request has ended */
361 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
362
San Mehat9d2bd732009-09-22 16:44:22 -0700363 /*
364 * Need to drop the host lock here; mmc_request_done may call
365 * back into the driver...
366 */
367 spin_unlock(&host->lock);
368 mmc_request_done(host->mmc, mrq);
369 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370
371 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700372}
373
374static void
375msmsdcc_stop_data(struct msmsdcc_host *host)
376{
San Mehat9d2bd732009-09-22 16:44:22 -0700377 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530378 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +0530379 host->curr.wait_for_auto_prog_done = false;
380 host->curr.got_auto_prog_done = false;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700381 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
382 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530383 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700384}
385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700387{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 return host->core_memres->start + MMCIFIFO;
389}
390
391static inline unsigned int msmsdcc_get_min_sup_clk_rate(
392 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530393
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395{
396 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530397 if (!host->sdcc_version)
398 udelay(host->reg_write_delay);
399 else if (readl_relaxed(host->base + MCI_STATUS2) &
400 MCI_MCLK_REG_WR_ACTIVE) {
401 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530402
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530403 start = ktime_get();
404 while (readl_relaxed(host->base + MCI_STATUS2) &
405 MCI_MCLK_REG_WR_ACTIVE) {
406 diff = ktime_sub(ktime_get(), start);
407 /* poll for max. 1 ms */
408 if (ktime_to_us(diff) > 1000) {
409 pr_warning("%s: previous reg. write is"
410 " still active\n",
411 mmc_hostname(host->mmc));
412 break;
413 }
414 }
415 }
San Mehat9d2bd732009-09-22 16:44:22 -0700416}
417
Subhash Jadavanidd432952012-03-28 11:25:56 +0530418static inline void msmsdcc_delay(struct msmsdcc_host *host)
419{
420 udelay(host->reg_write_delay);
421
San Mehat9d2bd732009-09-22 16:44:22 -0700422}
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 }
San Mehat9d2bd732009-09-22 16:44:22 -0700502
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) {
San Mehat9d2bd732009-09-22 16:44:22 -0700519 mrq->data->bytes_xfered = host->curr.data_xfered;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700520 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)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700541 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;
San Mehat9d2bd732009-09-22 16:44:22 -0700776
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530777 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));
San Mehat9d2bd732009-09-22 16:44:22 -0700813
814 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;
San Mehat9d2bd732009-09-22 16:44:22 -0700838 box = &nc->cmd[0];
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530839 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;
San Mehat9d2bd732009-09-22 16:44:22 -0700888
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
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530897 /* 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);
San Mehat9d2bd732009-09-22 16:44:22 -0700907 }
908
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530909 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)
San Mehat56a8b5b2009-11-21 12:29:46 -0800914{
Asutosh Dasaccacd42012-03-08 14:33:17 +0530915 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;
San Mehat9d2bd732009-09-22 16:44:22 -0700949}
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 Mehat9d2bd732009-09-22 16:44:22 -0700965{
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) {
Girish K Sa3c76eb2011-10-11 11:44:09 +05301098 pr_err("%s: Overlapping command requests\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001100 }
1101 host->curr.cmd = cmd;
1102}
1103
1104static void
1105msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1106 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001107{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301108 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001109 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001111 unsigned int pio_irqmask = 0;
1112
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301113 BUG_ON(!data->sg);
1114 BUG_ON(!data->sg_len);
1115
San Mehat9d2bd732009-09-22 16:44:22 -07001116 host->curr.data = data;
1117 host->curr.xfer_size = data->blksz * data->blocks;
1118 host->curr.xfer_remain = host->curr.xfer_size;
1119 host->curr.data_xfered = 0;
1120 host->curr.got_dataend = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301121 host->curr.got_auto_prog_done = false;
San Mehat9d2bd732009-09-22 16:44:22 -07001122
San Mehat9d2bd732009-09-22 16:44:22 -07001123 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1124
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301125 if (host->curr.wait_for_auto_prog_done)
1126 datactrl |= MCI_AUTO_PROG_DONE;
San Mehat9d2bd732009-09-22 16:44:22 -07001127
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;
1161 } 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 ;
Subhash Jadavani63540362012-06-12 14:56:04 +05301176 WARN(!timeout,
1177 "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
1178 mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
San Mehat9d2bd732009-09-22 16:44:22 -07001179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1181 /* Use ADM (Application Data Mover) HW for Data transfer */
1182 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001183 host->cmd_timeout = timeout;
1184 host->cmd_pio_irqmask = pio_irqmask;
1185 host->cmd_datactrl = datactrl;
1186 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1189 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001190 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001191
1192 if (cmd) {
1193 msmsdcc_start_command_deferred(host, cmd, &c);
1194 host->cmd_c = c;
1195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1197 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1198 host->base + MMCIMASK0);
1199 mb();
1200 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001201 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1208 (~(MCI_IRQ_PIO))) | pio_irqmask,
1209 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001211
1212 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301213 /* Delay between data/command */
1214 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001215 /* Daisy-chain the command if requested */
1216 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301217 } else {
1218 /*
1219 * We don't need delay after writing to DATA_CTRL
1220 * register if we are not writing to CMD register
1221 * immediately after this. As we already have delay
1222 * before sending the command, we just need mb() here.
1223 */
1224 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001225 }
San Mehat9d2bd732009-09-22 16:44:22 -07001226 }
1227}
1228
1229static void
1230msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1231{
San Mehat56a8b5b2009-11-21 12:29:46 -08001232 msmsdcc_start_command_deferred(host, cmd, &c);
1233 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001234}
1235
1236static void
1237msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1238 unsigned int status)
1239{
1240 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301242 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1243 || data->mrq->cmd->opcode ==
1244 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245 pr_err("%s: Data CRC error\n",
1246 mmc_hostname(host->mmc));
1247 pr_err("%s: opcode 0x%.8x\n", __func__,
1248 data->mrq->cmd->opcode);
1249 pr_err("%s: blksz %d, blocks %d\n", __func__,
1250 data->blksz, data->blocks);
1251 data->error = -EILSEQ;
1252 }
San Mehat9d2bd732009-09-22 16:44:22 -07001253 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 /* CRC is optional for the bus test commands, not all
1255 * cards respond back with CRC. However controller
1256 * waits for the CRC and times out. Hence ignore the
1257 * data timeouts during the Bustest.
1258 */
1259 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1260 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301261 pr_err("%s: CMD%d: Data timeout\n",
1262 mmc_hostname(host->mmc),
1263 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301265 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 }
San Mehat9d2bd732009-09-22 16:44:22 -07001267 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001268 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001269 data->error = -EIO;
1270 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001271 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001272 data->error = -EIO;
1273 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001274 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001276 data->error = -EIO;
1277 }
San Mehat9d2bd732009-09-22 16:44:22 -07001278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001280 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 host->dummy_52_needed = 0;
1282}
San Mehat9d2bd732009-09-22 16:44:22 -07001283
1284static int
1285msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1286{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001288 uint32_t *ptr = (uint32_t *) buffer;
1289 int count = 0;
1290
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301291 if (remain % 4)
1292 remain = ((remain >> 2) + 1) << 2;
1293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1295
1296 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001297 ptr++;
1298 count += sizeof(uint32_t);
1299
1300 remain -= sizeof(uint32_t);
1301 if (remain == 0)
1302 break;
1303 }
1304 return count;
1305}
1306
1307static int
1308msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001310{
1311 void __iomem *base = host->base;
1312 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 while (readl_relaxed(base + MMCISTATUS) &
1316 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1317 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001318
San Mehat9d2bd732009-09-22 16:44:22 -07001319 count = min(remain, maxcnt);
1320
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301321 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1322 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001323 ptr += count;
1324 remain -= count;
1325
1326 if (remain == 0)
1327 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 }
1329 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001330
1331 return ptr - buffer;
1332}
1333
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001334/*
1335 * Copy up to a word (4 bytes) between a scatterlist
1336 * and a temporary bounce buffer when the word lies across
1337 * two pages. The temporary buffer can then be read to/
1338 * written from the FIFO once.
1339 */
1340static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001341{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001342 struct msmsdcc_pio_data *pio = &host->pio;
1343 unsigned int bytes_avail;
1344
1345 if (host->curr.data->flags & MMC_DATA_READ)
1346 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1347 pio->bounce_buf_len);
1348 else
1349 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1350 pio->bounce_buf_len);
1351
1352 while (pio->bounce_buf_len != 4) {
1353 if (!sg_miter_next(&pio->sg_miter))
1354 break;
1355 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1356 4 - pio->bounce_buf_len);
1357 if (host->curr.data->flags & MMC_DATA_READ)
1358 memcpy(pio->sg_miter.addr,
1359 &pio->bounce_buf[pio->bounce_buf_len],
1360 bytes_avail);
1361 else
1362 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1363 pio->sg_miter.addr, bytes_avail);
1364
1365 pio->sg_miter.consumed = bytes_avail;
1366 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001367 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001368}
1369
1370/*
1371 * Use sg_miter_next to return as many 4-byte aligned
1372 * chunks as possible, using a temporary 4 byte buffer
1373 * for alignment if necessary
1374 */
1375static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1376{
1377 struct msmsdcc_pio_data *pio = &host->pio;
1378 unsigned int length, rlength;
1379 char *buffer;
1380
1381 if (!sg_miter_next(&pio->sg_miter))
1382 return 0;
1383
1384 buffer = pio->sg_miter.addr;
1385 length = pio->sg_miter.length;
1386
1387 if (length < host->curr.xfer_remain) {
1388 rlength = round_down(length, 4);
1389 if (rlength) {
1390 /*
1391 * We have a 4-byte aligned chunk.
1392 * The rounding will be reflected by
1393 * a call to msmsdcc_sg_consumed
1394 */
1395 length = rlength;
1396 goto sg_next_end;
1397 }
1398 /*
1399 * We have a length less than 4 bytes. Check to
1400 * see if more buffer is available, and combine
1401 * to make 4 bytes if possible.
1402 */
1403 pio->bounce_buf_len = length;
1404 memset(pio->bounce_buf, 0, 4);
1405
1406 /*
1407 * On a read, get 4 bytes from FIFO, and distribute
1408 * (4-bouce_buf_len) bytes into consecutive
1409 * sgl buffers when msmsdcc_sg_consumed is called
1410 */
1411 if (host->curr.data->flags & MMC_DATA_READ) {
1412 buffer = pio->bounce_buf;
1413 length = 4;
1414 goto sg_next_end;
1415 } else {
1416 _msmsdcc_sg_consume_word(host);
1417 buffer = pio->bounce_buf;
1418 length = pio->bounce_buf_len;
1419 }
1420 }
1421
1422sg_next_end:
1423 *buf = buffer;
1424 *len = length;
1425 return 1;
1426}
1427
1428/*
1429 * Update sg_miter.consumed based on how many bytes were
1430 * consumed. If the bounce buffer was used to read from FIFO,
1431 * redistribute into sgls.
1432 */
1433static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1434 unsigned int length)
1435{
1436 struct msmsdcc_pio_data *pio = &host->pio;
1437
1438 if (host->curr.data->flags & MMC_DATA_READ) {
1439 if (length > pio->sg_miter.consumed)
1440 /*
1441 * consumed 4 bytes, but sgl
1442 * describes < 4 bytes
1443 */
1444 _msmsdcc_sg_consume_word(host);
1445 else
1446 pio->sg_miter.consumed = length;
1447 } else
1448 if (length < pio->sg_miter.consumed)
1449 pio->sg_miter.consumed = length;
1450}
1451
1452static void msmsdcc_sg_start(struct msmsdcc_host *host)
1453{
1454 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1455
1456 host->pio.bounce_buf_len = 0;
1457
1458 if (host->curr.data->flags & MMC_DATA_READ)
1459 sg_miter_flags |= SG_MITER_TO_SG;
1460 else
1461 sg_miter_flags |= SG_MITER_FROM_SG;
1462
1463 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1464 host->curr.data->sg_len, sg_miter_flags);
1465}
1466
1467static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1468{
1469 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001470}
1471
San Mehat1cd22962010-02-03 12:59:29 -08001472static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001473msmsdcc_pio_irq(int irq, void *dev_id)
1474{
1475 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001477 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001478 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001479 unsigned int remain;
1480 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001481
Murali Palnati36448a42011-09-02 15:06:18 +05301482 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301487 (MCI_IRQ_PIO)) == 0) {
1488 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301489 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301490 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491#if IRQ_DEBUG
1492 msmsdcc_print_status(host, "irq1-r", status);
1493#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001494 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001495
1496 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001497 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1500 | MCI_RXDATAAVLBL)))
1501 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001502
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001503 if (!msmsdcc_sg_next(host, &buffer, &remain))
1504 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001505
San Mehat9d2bd732009-09-22 16:44:22 -07001506 len = 0;
1507 if (status & MCI_RXACTIVE)
1508 len = msmsdcc_pio_read(host, buffer, remain);
1509 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001511
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301512 /* len might have aligned to 32bits above */
1513 if (len > remain)
1514 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001515
San Mehat9d2bd732009-09-22 16:44:22 -07001516 host->curr.xfer_remain -= len;
1517 host->curr.data_xfered += len;
1518 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001519 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 if (remain) /* Done with this page? */
1522 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001525 } while (1);
1526
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001527 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001528 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1531 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1532 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1533 host->base + MMCIMASK0);
1534 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301535 /*
1536 * back to back write to MASK0 register don't need
1537 * synchronization delay.
1538 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1540 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1541 }
1542 mb();
1543 } else if (!host->curr.xfer_remain) {
1544 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1545 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1546 mb();
1547 }
San Mehat9d2bd732009-09-22 16:44:22 -07001548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001550
1551 return IRQ_HANDLED;
1552}
1553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554static void
1555msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1556
1557static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1558 struct mmc_data *data)
1559{
1560 u32 loop_cnt = 0;
1561
1562 /*
1563 * For read commands with data less than fifo size, it is possible to
1564 * get DATAEND first and RXDATA_AVAIL might be set later because of
1565 * synchronization delay through the asynchronous RX FIFO. Thus, for
1566 * such cases, even after DATAEND interrupt is received software
1567 * should poll for RXDATA_AVAIL until the requested data is read out
1568 * of FIFO. This change is needed to get around this abnormal but
1569 * sometimes expected behavior of SDCC3 controller.
1570 *
1571 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1572 * after the data is loaded into RX FIFO. This would amount to less
1573 * than a microsecond and thus looping for 1000 times is good enough
1574 * for that delay.
1575 */
1576 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1577 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1578 spin_unlock(&host->lock);
1579 msmsdcc_pio_irq(1, host);
1580 spin_lock(&host->lock);
1581 }
1582 }
1583 if (loop_cnt == 1000) {
1584 pr_info("%s: Timed out while polling for Rx Data\n",
1585 mmc_hostname(host->mmc));
1586 data->error = -ETIMEDOUT;
1587 msmsdcc_reset_and_restore(host);
1588 }
1589}
1590
San Mehat9d2bd732009-09-22 16:44:22 -07001591static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1592{
1593 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001594
1595 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301596 if (mmc_resp_type(cmd))
1597 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1598 /*
1599 * Read rest of the response registers only if
1600 * long response is expected for this command
1601 */
1602 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1603 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1604 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1605 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1606 }
San Mehat9d2bd732009-09-22 16:44:22 -07001607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301609 pr_debug("%s: CMD%d: Command timeout\n",
1610 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001611 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001612 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301613 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301614 pr_err("%s: CMD%d: Command CRC error\n",
1615 mmc_hostname(host->mmc), cmd->opcode);
1616 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001617 cmd->error = -EILSEQ;
1618 }
1619
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301620 if (!cmd->error) {
1621 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1622 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1623 mod_timer(&host->req_tout_timer, (jiffies +
1624 msecs_to_jiffies(host->curr.req_tout_ms)));
1625 }
1626 }
1627
San Mehat9d2bd732009-09-22 16:44:22 -07001628 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 if (host->curr.data && host->dma.sg &&
1630 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001631 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 else if (host->curr.data && host->sps.sg &&
1633 host->is_sps_mode){
1634 /* Stop current SPS transfer */
1635 msmsdcc_sps_exit_curr_xfer(host);
1636 }
San Mehat9d2bd732009-09-22 16:44:22 -07001637 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301638 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001639 msmsdcc_stop_data(host);
1640 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301641 } else { /* host->data == NULL */
1642 if (!cmd->error && host->prog_enable) {
1643 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301645 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301647 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301648 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301649 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301650 host->curr.wait_for_auto_prog_done = false;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001651 if (host->dummy_52_needed)
1652 host->dummy_52_needed = 0;
1653 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301655 msmsdcc_request_end(host, cmd->mrq);
1656 }
1657 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301658 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301659 if (cmd == host->curr.mrq->sbc)
1660 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1661 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1662 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301663 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001664 }
1665}
1666
San Mehat9d2bd732009-09-22 16:44:22 -07001667static irqreturn_t
1668msmsdcc_irq(int irq, void *dev_id)
1669{
1670 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001671 u32 status;
1672 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001674
1675 spin_lock(&host->lock);
1676
1677 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 struct mmc_command *cmd;
1679 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 if (timer) {
1682 timer = 0;
1683 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001684 }
San Mehat9d2bd732009-09-22 16:44:22 -07001685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 if (!host->clks_on) {
1687 pr_debug("%s: %s: SDIO async irq received\n",
1688 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301689
1690 /*
1691 * Only async interrupt can come when clocks are off,
1692 * disable further interrupts and enable them when
1693 * clocks are on.
1694 */
1695 if (!host->sdcc_irq_disabled) {
1696 disable_irq_nosync(irq);
1697 host->sdcc_irq_disabled = 1;
1698 }
1699
1700 /*
1701 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1702 * will take care of signaling sdio irq during
1703 * mmc_sdio_resume().
1704 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301705 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301706 /*
1707 * This is a wakeup interrupt so hold wakelock
1708 * until SDCC resume is handled.
1709 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301711 } else {
1712 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301713 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301714 spin_lock(&host->lock);
1715 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301716 ret = 1;
1717 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 }
1719
1720 status = readl_relaxed(host->base + MMCISTATUS);
1721
1722 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1723 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001724 break;
1725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726#if IRQ_DEBUG
1727 msmsdcc_print_status(host, "irq0-r", status);
1728#endif
1729 status &= readl_relaxed(host->base + MMCIMASK0);
1730 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301731 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301732 if (host->clk_rate <=
1733 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301734 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735#if IRQ_DEBUG
1736 msmsdcc_print_status(host, "irq0-p", status);
1737#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 if (status & MCI_SDIOINTROPE) {
1740 if (host->sdcc_suspending)
1741 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301742 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301744 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001745 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001746 data = host->curr.data;
1747
1748 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1750 MCI_CMDTIMEOUT)) {
1751 if (status & MCI_CMDTIMEOUT)
1752 pr_debug("%s: dummy CMD52 timeout\n",
1753 mmc_hostname(host->mmc));
1754 if (status & MCI_CMDCRCFAIL)
1755 pr_debug("%s: dummy CMD52 CRC failed\n",
1756 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001757 host->dummy_52_sent = 0;
1758 host->dummy_52_needed = 0;
1759 if (data) {
1760 msmsdcc_stop_data(host);
1761 msmsdcc_request_end(host, data->mrq);
1762 }
1763 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 spin_unlock(&host->lock);
1765 return IRQ_HANDLED;
1766 }
1767 break;
1768 }
1769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 /*
1771 * Check for proper command response
1772 */
1773 cmd = host->curr.cmd;
1774 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1775 MCI_CMDTIMEOUT | MCI_PROGDONE |
1776 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1777 msmsdcc_do_cmdirq(host, status);
1778 }
1779
Sathish Ambley081d7842011-11-29 11:19:41 -08001780 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 /* Check for data errors */
1782 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1783 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1784 msmsdcc_data_err(host, data, status);
1785 host->curr.data_xfered = 0;
1786 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001787 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 else if (host->sps.sg && host->is_sps_mode) {
1789 /* Stop current SPS transfer */
1790 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301791 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 msmsdcc_reset_and_restore(host);
1793 if (host->curr.data)
1794 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301795 if (!data->stop || (host->curr.mrq->sbc
1796 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 timer |=
1798 msmsdcc_request_end(host,
1799 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301800 else if ((host->curr.mrq->sbc
1801 && data->error) ||
1802 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 msmsdcc_start_command(host,
1804 data->stop,
1805 0);
1806 timer = 1;
1807 }
1808 }
1809 }
1810
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301811 /* Check for prog done */
1812 if (host->curr.wait_for_auto_prog_done &&
1813 (status & MCI_PROGDONE))
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05301814 host->curr.got_auto_prog_done = true;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816 /* Check for data done */
1817 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1818 host->curr.got_dataend = 1;
1819
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301820 if (host->curr.got_dataend &&
1821 (!host->curr.wait_for_auto_prog_done ||
1822 (host->curr.wait_for_auto_prog_done &&
1823 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 /*
1825 * If DMA is still in progress, we complete
1826 * via the completion handler
1827 */
1828 if (!host->dma.busy && !host->sps.busy) {
1829 /*
1830 * There appears to be an issue in the
1831 * controller where if you request a
1832 * small block transfer (< fifo size),
1833 * you may get your DATAEND/DATABLKEND
1834 * irq without the PIO data irq.
1835 *
1836 * Check to see if theres still data
1837 * to be read, and simulate a PIO irq.
1838 */
1839 if (data->flags & MMC_DATA_READ)
1840 msmsdcc_wait_for_rxdata(host,
1841 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 if (!data->error) {
1843 host->curr.data_xfered =
1844 host->curr.xfer_size;
1845 host->curr.xfer_remain -=
1846 host->curr.xfer_size;
1847 }
1848
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001849 if (!host->dummy_52_needed) {
1850 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301851 if (!data->stop ||
1852 (host->curr.mrq->sbc
1853 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001854 msmsdcc_request_end(
1855 host,
1856 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301857 else if ((host->curr.mrq->sbc
1858 && data->error) ||
1859 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001860 msmsdcc_start_command(
1861 host,
1862 data->stop, 0);
1863 timer = 1;
1864 }
1865 } else {
1866 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001868 &dummy52cmd,
1869 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 }
1871 }
1872 }
1873 }
1874
San Mehat9d2bd732009-09-22 16:44:22 -07001875 ret = 1;
1876 } while (status);
1877
1878 spin_unlock(&host->lock);
1879
San Mehat9d2bd732009-09-22 16:44:22 -07001880 return IRQ_RETVAL(ret);
1881}
1882
1883static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301884msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1885 bool is_first_request)
1886{
1887 struct msmsdcc_host *host = mmc_priv(mmc);
1888 struct mmc_data *data = mrq->data;
1889 int rc = 0;
1890
1891 if (unlikely(!data)) {
1892 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1893 __func__);
1894 return;
1895 }
1896 if (unlikely(data->host_cookie)) {
1897 /* Very wrong */
1898 data->host_cookie = 0;
1899 pr_err("%s: %s Request reposted for prepare\n",
1900 mmc_hostname(mmc), __func__);
1901 return;
1902 }
1903
1904 if (!msmsdcc_is_dma_possible(host, data))
1905 return;
1906
1907 rc = msmsdcc_prep_xfer(host, data);
1908 if (unlikely(rc < 0)) {
1909 data->host_cookie = 0;
1910 return;
1911 }
1912
1913 data->host_cookie = 1;
1914}
1915
1916static void
1917msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1918{
1919 struct msmsdcc_host *host = mmc_priv(mmc);
1920 unsigned int dir;
1921 struct mmc_data *data = mrq->data;
1922
1923 if (unlikely(!data)) {
1924 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1925 __func__);
1926 return;
1927 }
1928 if (data->flags & MMC_DATA_READ)
1929 dir = DMA_FROM_DEVICE;
1930 else
1931 dir = DMA_TO_DEVICE;
1932
1933 if (data->host_cookie)
1934 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1935 data->sg_len, dir);
1936
1937 data->host_cookie = 0;
1938}
1939
1940static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1942{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301943 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301945 if ((mrq->data->flags & MMC_DATA_READ) ||
1946 host->curr.use_wr_data_pend)
1947 msmsdcc_start_data(host, mrq->data,
1948 mrq->sbc ? mrq->sbc : mrq->cmd,
1949 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301950 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301951 msmsdcc_start_command(host,
1952 mrq->sbc ? mrq->sbc : mrq->cmd,
1953 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 } else {
1955 msmsdcc_start_command(host, mrq->cmd, 0);
1956 }
1957}
1958
1959static void
San Mehat9d2bd732009-09-22 16:44:22 -07001960msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1961{
1962 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301963 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 /*
1966 * Get the SDIO AL client out of LPM.
1967 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001968 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969 if (host->plat->is_sdio_al_client)
1970 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001971
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301972 /* check if sps pipe reset is pending? */
1973 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1974 msmsdcc_sps_pipes_reset_and_restore(host);
1975 host->sps.pipe_reset_pending = false;
1976 }
San Mehat9d2bd732009-09-22 16:44:22 -07001977
1978 spin_lock_irqsave(&host->lock, flags);
1979
San Mehat9d2bd732009-09-22 16:44:22 -07001980 if (host->eject) {
1981 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1982 mrq->cmd->error = 0;
1983 mrq->data->bytes_xfered = mrq->data->blksz *
1984 mrq->data->blocks;
1985 } else
1986 mrq->cmd->error = -ENOMEDIUM;
1987
1988 spin_unlock_irqrestore(&host->lock, flags);
1989 mmc_request_done(mmc, mrq);
1990 return;
1991 }
1992
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301993 /*
subhashjf181c292012-05-02 13:07:40 +05301994 * Don't start the request if SDCC is not in proper state to handle it
1995 */
1996 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1997 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1998 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1999 __func__, mrq->cmd->opcode);
2000 msmsdcc_dump_sdcc_state(host);
2001 mrq->cmd->error = -EIO;
2002 if (mrq->data) {
2003 mrq->data->error = -EIO;
2004 mrq->data->bytes_xfered = 0;
2005 }
2006 spin_unlock_irqrestore(&host->lock, flags);
2007 mmc_request_done(mmc, mrq);
2008 return;
2009 }
2010
2011 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2012 " other request (CMD%d) is in progress\n",
2013 mmc_hostname(host->mmc), __func__,
2014 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2015
2016 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302017 * Set timeout value to 10 secs (or more in case of buggy cards)
2018 */
2019 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302020 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302021 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302022 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302023 /*
2024 * Kick the software request timeout timer here with the timeout
2025 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302026 */
2027 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302028 (jiffies +
2029 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002030
San Mehat9d2bd732009-09-22 16:44:22 -07002031 host->curr.mrq = mrq;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302032 if (mrq->sbc) {
2033 mrq->sbc->mrq = mrq;
2034 mrq->sbc->data = mrq->data;
2035 }
2036
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302037 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302038 if (host->sdcc_version) {
2039 if (!mrq->stop)
2040 host->curr.wait_for_auto_prog_done = true;
2041 } else {
2042 if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
2043 (mrq->cmd->opcode == 54))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 host->dummy_52_needed = 1;
2045 }
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05302046
Subhash Jadavanif5277752011-10-12 16:47:52 +05302047 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2048 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2049 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002050 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302051
Subhash Jadavanif5277752011-10-12 16:47:52 +05302052 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302053
San Mehat9d2bd732009-09-22 16:44:22 -07002054 spin_unlock_irqrestore(&host->lock, flags);
2055}
2056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2058 int min_uV, int max_uV)
2059{
2060 int rc = 0;
2061
2062 if (vreg->set_voltage_sup) {
2063 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2064 if (rc) {
2065 pr_err("%s: regulator_set_voltage(%s) failed."
2066 " min_uV=%d, max_uV=%d, rc=%d\n",
2067 __func__, vreg->name, min_uV, max_uV, rc);
2068 }
2069 }
2070
2071 return rc;
2072}
2073
2074static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2075 int uA_load)
2076{
2077 int rc = 0;
2078
Krishna Kondafea60182011-11-01 16:01:34 -07002079 /* regulators that do not support regulator_set_voltage also
2080 do not support regulator_set_optimum_mode */
2081 if (vreg->set_voltage_sup) {
2082 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2083 if (rc < 0)
2084 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2085 "uA_load=%d) failed. rc=%d\n", __func__,
2086 vreg->name, uA_load, rc);
2087 else
2088 /* regulator_set_optimum_mode() can return non zero
2089 * value even for success case.
2090 */
2091 rc = 0;
2092 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093
2094 return rc;
2095}
2096
2097static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2098 struct device *dev)
2099{
2100 int rc = 0;
2101
2102 /* check if regulator is already initialized? */
2103 if (vreg->reg)
2104 goto out;
2105
2106 /* Get the regulator handle */
2107 vreg->reg = regulator_get(dev, vreg->name);
2108 if (IS_ERR(vreg->reg)) {
2109 rc = PTR_ERR(vreg->reg);
2110 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2111 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002112 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002113 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002114
2115 if (regulator_count_voltages(vreg->reg) > 0)
2116 vreg->set_voltage_sup = 1;
2117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118out:
2119 return rc;
2120}
2121
2122static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2123{
2124 if (vreg->reg)
2125 regulator_put(vreg->reg);
2126}
2127
2128/* This init function should be called only once for each SDCC slot */
2129static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2130{
2131 int rc = 0;
2132 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302133 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134 struct device *dev = mmc_dev(host->mmc);
2135
2136 curr_slot = host->plat->vreg_data;
2137 if (!curr_slot)
2138 goto out;
2139
2140 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302141 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142
2143 if (is_init) {
2144 /*
2145 * Get the regulator handle from voltage regulator framework
2146 * and then try to set the voltage level for the regulator
2147 */
2148 if (curr_vdd_reg) {
2149 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2150 if (rc)
2151 goto out;
2152 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302153 if (curr_vdd_io_reg) {
2154 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155 if (rc)
2156 goto vdd_reg_deinit;
2157 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002158 rc = msmsdcc_vreg_reset(host);
2159 if (rc)
2160 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2161 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002162 goto out;
2163 } else {
2164 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302165 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302167vdd_io_reg_deinit:
2168 if (curr_vdd_io_reg)
2169 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170vdd_reg_deinit:
2171 if (curr_vdd_reg)
2172 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2173out:
2174 return rc;
2175}
2176
2177static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2178{
2179 int rc = 0;
2180
Subhash Jadavanicc922692011-08-01 23:05:01 +05302181 /* Put regulator in HPM (high power mode) */
2182 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2183 if (rc < 0)
2184 goto out;
2185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 if (!vreg->is_enabled) {
2187 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302188 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2189 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190 if (rc)
2191 goto out;
2192
2193 rc = regulator_enable(vreg->reg);
2194 if (rc) {
2195 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2196 __func__, vreg->name, rc);
2197 goto out;
2198 }
2199 vreg->is_enabled = true;
2200 }
2201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202out:
2203 return rc;
2204}
2205
2206static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2207{
2208 int rc = 0;
2209
2210 /* Never disable regulator marked as always_on */
2211 if (vreg->is_enabled && !vreg->always_on) {
2212 rc = regulator_disable(vreg->reg);
2213 if (rc) {
2214 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2215 __func__, vreg->name, rc);
2216 goto out;
2217 }
2218 vreg->is_enabled = false;
2219
2220 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2221 if (rc < 0)
2222 goto out;
2223
2224 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302225 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 if (rc)
2227 goto out;
2228 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2229 /* Put always_on regulator in LPM (low power mode) */
2230 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2231 if (rc < 0)
2232 goto out;
2233 }
2234out:
2235 return rc;
2236}
2237
2238static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2239{
2240 int rc = 0, i;
2241 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302242 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243
2244 curr_slot = host->plat->vreg_data;
2245 if (!curr_slot)
2246 goto out;
2247
Subhash Jadavani937c7502012-06-01 15:34:46 +05302248 vreg_table[0] = curr_slot->vdd_data;
2249 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250
2251 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2252 if (vreg_table[i]) {
2253 if (enable)
2254 rc = msmsdcc_vreg_enable(vreg_table[i]);
2255 else
2256 rc = msmsdcc_vreg_disable(vreg_table[i]);
2257 if (rc)
2258 goto out;
2259 }
2260 }
2261out:
2262 return rc;
2263}
2264
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002265/*
2266 * Reset vreg by ensuring it is off during probe. A call
2267 * to enable vreg is needed to balance disable vreg
2268 */
2269static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2270{
2271 int rc;
2272
2273 rc = msmsdcc_setup_vreg(host, 1);
2274 if (rc)
2275 return rc;
2276 rc = msmsdcc_setup_vreg(host, 0);
2277 return rc;
2278}
2279
Subhash Jadavani937c7502012-06-01 15:34:46 +05302280enum vdd_io_level {
2281 /* set vdd_io_data->low_vol_level */
2282 VDD_IO_LOW,
2283 /* set vdd_io_data->high_vol_level */
2284 VDD_IO_HIGH,
2285 /*
2286 * set whatever there in voltage_level (third argument) of
2287 * msmsdcc_set_vdd_io_vol() function.
2288 */
2289 VDD_IO_SET_LEVEL,
2290};
2291
2292static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2293 enum vdd_io_level level,
2294 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002295{
2296 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302297 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298
2299 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302300 struct msm_mmc_reg_data *vdd_io_reg =
2301 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302
Subhash Jadavani937c7502012-06-01 15:34:46 +05302303 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2304 switch (level) {
2305 case VDD_IO_LOW:
2306 set_level = vdd_io_reg->low_vol_level;
2307 break;
2308 case VDD_IO_HIGH:
2309 set_level = vdd_io_reg->high_vol_level;
2310 break;
2311 case VDD_IO_SET_LEVEL:
2312 set_level = voltage_level;
2313 break;
2314 default:
2315 pr_err("%s: %s: invalid argument level = %d",
2316 mmc_hostname(host->mmc), __func__,
2317 level);
2318 rc = -EINVAL;
2319 goto out;
2320 }
2321 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2322 set_level, set_level);
2323 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 }
2325
Subhash Jadavani937c7502012-06-01 15:34:46 +05302326out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302327 return rc;
2328}
2329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2331{
2332 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2333 return 1;
2334 return 0;
2335}
2336
Asutosh Dasf5298c32012-04-03 14:51:47 +05302337/*
2338 * Any function calling msmsdcc_setup_clocks must
2339 * acquire clk_mutex. May sleep.
2340 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2342{
2343 if (enable) {
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302344 if (!IS_ERR_OR_NULL(host->bus_clk))
2345 clk_prepare_enable(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302347 clk_prepare_enable(host->pclk);
2348 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302349 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302350 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302352 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302353 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302354 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302356 clk_disable_unprepare(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05302357 if (!IS_ERR_OR_NULL(host->bus_clk))
2358 clk_disable_unprepare(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359 }
2360}
2361
2362static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2363 unsigned int req_clk)
2364{
2365 unsigned int sel_clk = -1;
2366
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302367 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2368 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2369 goto out;
2370 }
2371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2373 unsigned char cnt;
2374
2375 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2376 if (host->plat->sup_clk_table[cnt] > req_clk)
2377 break;
2378 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2379 sel_clk = host->plat->sup_clk_table[cnt];
2380 break;
2381 } else
2382 sel_clk = host->plat->sup_clk_table[cnt];
2383 }
2384 } else {
2385 if ((req_clk < host->plat->msmsdcc_fmax) &&
2386 (req_clk > host->plat->msmsdcc_fmid))
2387 sel_clk = host->plat->msmsdcc_fmid;
2388 else
2389 sel_clk = req_clk;
2390 }
2391
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302392out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 return sel_clk;
2394}
2395
2396static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2397 struct msmsdcc_host *host)
2398{
2399 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2400 return host->plat->sup_clk_table[0];
2401 else
2402 return host->plat->msmsdcc_fmin;
2403}
2404
2405static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2406 struct msmsdcc_host *host)
2407{
2408 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2409 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2410 else
2411 return host->plat->msmsdcc_fmax;
2412}
2413
2414static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302415{
2416 struct msm_mmc_gpio_data *curr;
2417 int i, rc = 0;
2418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302420 for (i = 0; i < curr->size; i++) {
2421 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 if (curr->gpio[i].is_always_on &&
2423 curr->gpio[i].is_enabled)
2424 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302425 rc = gpio_request(curr->gpio[i].no,
2426 curr->gpio[i].name);
2427 if (rc) {
2428 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2429 mmc_hostname(host->mmc),
2430 curr->gpio[i].no,
2431 curr->gpio[i].name, rc);
2432 goto free_gpios;
2433 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302435 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 if (curr->gpio[i].is_always_on)
2437 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302438 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302440 }
2441 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302443
2444free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302446 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 curr->gpio[i].is_enabled = false;
2448 }
2449out:
2450 return rc;
2451}
2452
2453static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2454{
2455 struct msm_mmc_pad_data *curr;
2456 int i;
2457
2458 curr = host->plat->pin_data->pad_data;
2459 for (i = 0; i < curr->drv->size; i++) {
2460 if (enable)
2461 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2462 curr->drv->on[i].val);
2463 else
2464 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2465 curr->drv->off[i].val);
2466 }
2467
2468 for (i = 0; i < curr->pull->size; i++) {
2469 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002470 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 curr->pull->on[i].val);
2472 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002473 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002474 curr->pull->off[i].val);
2475 }
2476
2477 return 0;
2478}
2479
2480static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2481{
2482 int rc = 0;
2483
2484 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2485 return 0;
2486
2487 if (host->plat->pin_data->is_gpio)
2488 rc = msmsdcc_setup_gpio(host, enable);
2489 else
2490 rc = msmsdcc_setup_pad(host, enable);
2491
2492 if (!rc)
2493 host->plat->pin_data->cfg_sts = enable;
2494
2495 return rc;
2496}
2497
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302498static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2499 unsigned mode)
2500{
2501 int ret = 0;
2502 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2503
2504 if (!pin)
2505 return 0;
2506
2507 switch (mode) {
2508 case SDC_DAT1_DISABLE:
2509 ret = msm_mpm_enable_pin(pin, 0);
2510 break;
2511 case SDC_DAT1_ENABLE:
2512 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2513 ret = msm_mpm_enable_pin(pin, 1);
2514 break;
2515 case SDC_DAT1_ENWAKE:
2516 ret = msm_mpm_set_pin_wake(pin, 1);
2517 break;
2518 case SDC_DAT1_DISWAKE:
2519 ret = msm_mpm_set_pin_wake(pin, 0);
2520 break;
2521 default:
2522 ret = -EINVAL;
2523 break;
2524 }
2525
2526 return ret;
2527}
2528
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302529static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2530{
2531 u32 pwr = 0;
2532 int ret = 0;
2533 struct mmc_host *mmc = host->mmc;
2534
2535 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2536 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2537 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2538 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2539
2540 if (ret) {
2541 pr_err("%s: Failed to setup voltage regulators\n",
2542 mmc_hostname(host->mmc));
2543 goto out;
2544 }
2545
2546 switch (ios->power_mode) {
2547 case MMC_POWER_OFF:
2548 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302549 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302550 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302551 * If VDD IO rail is always on, set low voltage for VDD
2552 * IO rail when slot is not in use (like when card is not
2553 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302554 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302555 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302556 msmsdcc_setup_pins(host, false);
2557 break;
2558 case MMC_POWER_UP:
2559 /* writing PWR_UP bit is redundant */
2560 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302561 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302562
Subhash Jadavani937c7502012-06-01 15:34:46 +05302563 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302564 msmsdcc_setup_pins(host, true);
2565 break;
2566 case MMC_POWER_ON:
2567 pwr = MCI_PWR_ON;
2568 break;
2569 }
2570
2571out:
2572 return pwr;
2573}
2574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2576{
2577 unsigned int wakeup_irq;
2578
2579 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2580 host->plat->sdiowakeup_irq :
2581 host->core_irqres->start;
2582
2583 if (!host->irq_wake_enabled) {
2584 enable_irq_wake(wakeup_irq);
2585 host->irq_wake_enabled = true;
2586 }
2587}
2588
2589static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2590{
2591 unsigned int wakeup_irq;
2592
2593 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2594 host->plat->sdiowakeup_irq :
2595 host->core_irqres->start;
2596
2597 if (host->irq_wake_enabled) {
2598 disable_irq_wake(wakeup_irq);
2599 host->irq_wake_enabled = false;
2600 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302601}
2602
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302603/* Returns required bandwidth in Bytes per Sec */
2604static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2605 struct mmc_ios *ios)
2606{
2607 unsigned int bw;
2608
2609 bw = host->clk_rate;
2610 /*
2611 * For DDR mode, SDCC controller clock will be at
2612 * the double rate than the actual clock that goes to card.
2613 */
2614 if (ios->bus_width == MMC_BUS_WIDTH_4)
2615 bw /= 2;
2616 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2617 bw /= 8;
2618
2619 return bw;
2620}
2621
2622static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2623 unsigned int bw)
2624{
2625 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2626 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2627 int i;
2628
2629 if (host->msm_bus_vote.is_max_bw_needed && bw)
2630 return host->msm_bus_vote.max_bw_vote;
2631
2632 for (i = 0; i < size; i++) {
2633 if (bw <= table[i])
2634 break;
2635 }
2636
2637 if (i && (i == size))
2638 i--;
2639
2640 return i;
2641}
2642
2643static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2644{
2645 int rc = 0;
2646 struct msm_bus_scale_pdata *use_cases;
2647
2648 if (host->plat->msm_bus_voting_data &&
2649 host->plat->msm_bus_voting_data->use_cases &&
2650 host->plat->msm_bus_voting_data->bw_vecs &&
2651 host->plat->msm_bus_voting_data->bw_vecs_size) {
2652 use_cases = host->plat->msm_bus_voting_data->use_cases;
2653 host->msm_bus_vote.client_handle =
2654 msm_bus_scale_register_client(use_cases);
2655 } else {
2656 return 0;
2657 }
2658
2659 if (!host->msm_bus_vote.client_handle) {
2660 pr_err("%s: msm_bus_scale_register_client() failed\n",
2661 mmc_hostname(host->mmc));
2662 rc = -EFAULT;
2663 } else {
2664 /* cache the vote index for minimum and maximum bandwidth */
2665 host->msm_bus_vote.min_bw_vote =
2666 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2667 host->msm_bus_vote.max_bw_vote =
2668 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2669 }
2670
2671 return rc;
2672}
2673
2674static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2675{
2676 if (host->msm_bus_vote.client_handle)
2677 msm_bus_scale_unregister_client(
2678 host->msm_bus_vote.client_handle);
2679}
2680
2681/*
2682 * This function must be called with host lock acquired.
2683 * Caller of this function should also ensure that msm bus client
2684 * handle is not null.
2685 */
2686static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2687 int vote,
2688 unsigned long flags)
2689{
2690 int rc = 0;
2691
2692 if (vote != host->msm_bus_vote.curr_vote) {
2693 spin_unlock_irqrestore(&host->lock, flags);
2694 rc = msm_bus_scale_client_update_request(
2695 host->msm_bus_vote.client_handle, vote);
2696 if (rc)
2697 pr_err("%s: msm_bus_scale_client_update_request() failed."
2698 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2699 mmc_hostname(host->mmc),
2700 host->msm_bus_vote.client_handle, vote, rc);
2701 spin_lock_irqsave(&host->lock, flags);
2702 if (!rc)
2703 host->msm_bus_vote.curr_vote = vote;
2704 }
2705
2706 return rc;
2707}
2708
2709/*
2710 * Internal work. Work to set 0 bandwidth for msm bus.
2711 */
2712static void msmsdcc_msm_bus_work(struct work_struct *work)
2713{
2714 struct msmsdcc_host *host = container_of(work,
2715 struct msmsdcc_host,
2716 msm_bus_vote.vote_work.work);
2717 unsigned long flags;
2718
2719 if (!host->msm_bus_vote.client_handle)
2720 return;
2721
2722 spin_lock_irqsave(&host->lock, flags);
2723 /* don't vote for 0 bandwidth if any request is in progress */
2724 if (!host->curr.mrq)
2725 msmsdcc_msm_bus_set_vote(host,
2726 host->msm_bus_vote.min_bw_vote, flags);
2727 else
2728 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2729 " bus voting to 0 bandwidth\n",
2730 mmc_hostname(host->mmc), __func__);
2731 spin_unlock_irqrestore(&host->lock, flags);
2732}
2733
2734/*
2735 * This function cancels any scheduled delayed work
2736 * and sets the bus vote based on ios argument.
2737 * If "ios" argument is NULL, bandwidth required is 0 else
2738 * calculate the bandwidth based on ios parameters.
2739 */
2740static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2741 struct msmsdcc_host *host,
2742 struct mmc_ios *ios)
2743{
2744 unsigned long flags;
2745 unsigned int bw;
2746 int vote;
2747
2748 if (!host->msm_bus_vote.client_handle)
2749 return;
2750
2751 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2752
2753 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2754 spin_lock_irqsave(&host->lock, flags);
2755 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2756 msmsdcc_msm_bus_set_vote(host, vote, flags);
2757 spin_unlock_irqrestore(&host->lock, flags);
2758}
2759
2760/* This function queues a work which will set the bandwidth requiement to 0 */
2761static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2762{
2763 unsigned long flags;
2764
2765 if (!host->msm_bus_vote.client_handle)
2766 return;
2767
2768 spin_lock_irqsave(&host->lock, flags);
2769 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2770 queue_delayed_work(system_nrt_wq,
2771 &host->msm_bus_vote.vote_work,
2772 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2773 spin_unlock_irqrestore(&host->lock, flags);
2774}
2775
San Mehat9d2bd732009-09-22 16:44:22 -07002776static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302777msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2778{
2779 struct mmc_host *mmc = host->mmc;
2780
2781 /*
2782 * SDIO_AL clients has different mechanism of handling LPM through
2783 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2784 * part of that. Here, we are interested only in clients like WLAN.
2785 */
2786 if (!(mmc->card && mmc_card_sdio(mmc->card))
2787 || host->plat->is_sdio_al_client)
2788 goto out;
2789
2790 if (!host->sdcc_suspended) {
2791 /*
2792 * When MSM is not in power collapse and we
2793 * are disabling clocks, enable bit 22 in MASK0
2794 * to handle asynchronous SDIO interrupts.
2795 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302796 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302797 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302798 mb();
2799 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302800 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302801 msmsdcc_sync_reg_wr(host);
2802 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302803 goto out;
2804 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2805 /*
2806 * Wakeup MSM only if SDIO function drivers set
2807 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2808 */
2809 goto out;
2810 }
2811
2812 if (enable_wakeup_irq) {
2813 if (!host->plat->sdiowakeup_irq) {
2814 /*
2815 * When there is no gpio line that can be configured
2816 * as wakeup interrupt handle it by configuring
2817 * asynchronous sdio interrupts and DAT1 line.
2818 */
2819 writel_relaxed(MCI_SDIOINTMASK,
2820 host->base + MMCIMASK0);
2821 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302822 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302823 /* configure sdcc core interrupt as wakeup interrupt */
2824 msmsdcc_enable_irq_wake(host);
2825 } else {
2826 /* Let gpio line handle wakeup interrupt */
2827 writel_relaxed(0, host->base + MMCIMASK0);
2828 mb();
2829 if (host->sdio_wakeupirq_disabled) {
2830 host->sdio_wakeupirq_disabled = 0;
2831 /* configure gpio line as wakeup interrupt */
2832 msmsdcc_enable_irq_wake(host);
2833 enable_irq(host->plat->sdiowakeup_irq);
2834 }
2835 }
2836 } else {
2837 if (!host->plat->sdiowakeup_irq) {
2838 /*
2839 * We may not have cleared bit 22 in the interrupt
2840 * handler as the clocks might be off at that time.
2841 */
2842 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302843 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302844 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302845 msmsdcc_disable_irq_wake(host);
2846 } else if (!host->sdio_wakeupirq_disabled) {
2847 disable_irq_nosync(host->plat->sdiowakeup_irq);
2848 msmsdcc_disable_irq_wake(host);
2849 host->sdio_wakeupirq_disabled = 1;
2850 }
2851 }
2852out:
2853 return;
San Mehat9d2bd732009-09-22 16:44:22 -07002854}
2855
2856static void
2857msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2858{
2859 struct msmsdcc_host *host = mmc_priv(mmc);
2860 u32 clk = 0, pwr = 0;
2861 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002862 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002864
Sahitya Tummala7a892482011-01-18 11:22:49 +05302865
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302866 /*
2867 * Disable SDCC core interrupt until set_ios is completed.
2868 * This avoids any race conditions with interrupt raised
2869 * when turning on/off the clocks. One possible
2870 * scenario is SDIO operational interrupt while the clock
2871 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302872 * host->lock is being released intermittently below.
2873 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302874 */
2875
Asutosh Dasf5298c32012-04-03 14:51:47 +05302876 mutex_lock(&host->clk_mutex);
2877 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07002878 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302879 if (!host->sdcc_irq_disabled) {
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05302880 disable_irq_nosync(host->core_irqres->start);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302881 host->sdcc_irq_disabled = 1;
2882 }
San Mehatd0719e52009-12-03 10:58:54 -08002883 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002884
Sujit Reddy Thummab7258622012-06-12 12:57:10 +05302885 /* Make sure sdcc core irq is synchronized */
2886 synchronize_irq(host->core_irqres->start);
2887
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302888 pwr = msmsdcc_setup_pwr(host, ios);
2889
2890 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002891 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302893 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302895 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002896 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302897 writel_relaxed(host->mci_irqenable,
2898 host->base + MMCIMASK0);
2899 mb();
2900 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002901 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902
2903 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2904 /*
2905 * For DDR50 mode, controller needs clock rate to be
2906 * double than what is required on the SD card CLK pin.
2907 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302908 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909 /*
2910 * Make sure that we don't double the clock if
2911 * doubled clock rate is already set
2912 */
2913 if (!host->ddr_doubled_clk_rate ||
2914 (host->ddr_doubled_clk_rate &&
2915 (host->ddr_doubled_clk_rate != ios->clock))) {
2916 host->ddr_doubled_clk_rate =
2917 msmsdcc_get_sup_clk_rate(
2918 host, (ios->clock * 2));
2919 clock = host->ddr_doubled_clk_rate;
2920 }
2921 } else {
2922 host->ddr_doubled_clk_rate = 0;
2923 }
2924
2925 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302926 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302928 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302930 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931 mmc_hostname(mmc), clock);
2932 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302933 host->reg_write_delay =
2934 (1 + ((3 * USEC_PER_SEC) /
2935 (host->clk_rate ? host->clk_rate :
2936 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002937 }
2938 /*
2939 * give atleast 2 MCLK cycles delay for clocks
2940 * and SDCC core to stabilize
2941 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302942 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002944 clk |= MCI_CLK_ENABLE;
2945 }
2946
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 if (ios->bus_width == MMC_BUS_WIDTH_8)
2948 clk |= MCI_CLK_WIDEBUS_8;
2949 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2950 clk |= MCI_CLK_WIDEBUS_4;
2951 else
2952 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954 if (msmsdcc_is_pwrsave(host))
2955 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002959 host->tuning_needed = 0;
2960 /*
2961 * Select the controller timing mode according
2962 * to current bus speed mode
2963 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302964 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2965 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966 clk |= (4 << 14);
2967 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302968 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002969 clk |= (3 << 14);
2970 } else {
2971 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07002972 }
2973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2975 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07002976
Subhash Jadavani00083572012-02-15 16:18:01 +05302977 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2978 if (!ios->vdd)
2979 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07002980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002981 if (host->io_pad_pwr_switch)
2982 clk |= IO_PAD_PWR_SWITCH;
2983
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302984 /* Don't write into registers if clocks are disabled */
2985 if (host->clks_on) {
2986 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2987 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302988 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302990 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2991 host->pwr = pwr;
2992 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302993 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994 }
San Mehat9d2bd732009-09-22 16:44:22 -07002995 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002996
2997 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302998 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302999 spin_unlock_irqrestore(&host->lock, flags);
3000 /*
3001 * May get a wake-up interrupt the instant we disable the
3002 * clocks. This would disable the wake-up interrupt.
3003 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303005 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006 host->clks_on = 0;
3007 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303008
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303009 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303010 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303011 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303012
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303013 /* Let interrupts be disabled if the host is powered off */
3014 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3015 enable_irq(host->core_irqres->start);
3016 host->sdcc_irq_disabled = 0;
3017 }
3018
San Mehat4adbbcc2009-11-08 13:00:37 -08003019 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303020 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003021}
3022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3024{
3025 struct msmsdcc_host *host = mmc_priv(mmc);
3026 u32 clk;
3027
3028 clk = readl_relaxed(host->base + MMCICLOCK);
3029 pr_debug("Changing to pwr_save=%d", pwrsave);
3030 if (pwrsave && msmsdcc_is_pwrsave(host))
3031 clk |= MCI_CLK_PWRSAVE;
3032 else
3033 clk &= ~MCI_CLK_PWRSAVE;
3034 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303035 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036
3037 return 0;
3038}
3039
3040static int msmsdcc_get_ro(struct mmc_host *mmc)
3041{
3042 int status = -ENOSYS;
3043 struct msmsdcc_host *host = mmc_priv(mmc);
3044
3045 if (host->plat->wpswitch) {
3046 status = host->plat->wpswitch(mmc_dev(mmc));
3047 } else if (host->plat->wpswitch_gpio) {
3048 status = gpio_request(host->plat->wpswitch_gpio,
3049 "SD_WP_Switch");
3050 if (status) {
3051 pr_err("%s: %s: Failed to request GPIO %d\n",
3052 mmc_hostname(mmc), __func__,
3053 host->plat->wpswitch_gpio);
3054 } else {
3055 status = gpio_direction_input(
3056 host->plat->wpswitch_gpio);
3057 if (!status) {
3058 /*
3059 * Wait for atleast 300ms as debounce
3060 * time for GPIO input to stabilize.
3061 */
3062 msleep(300);
3063 status = gpio_get_value_cansleep(
3064 host->plat->wpswitch_gpio);
Sujit Reddy Thumma8f912ea2012-06-22 16:18:43 +05303065 status ^= !host->plat->is_wpswitch_active_low;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 }
3067 gpio_free(host->plat->wpswitch_gpio);
3068 }
3069 }
3070
3071 if (status < 0)
3072 status = -ENOSYS;
3073 pr_debug("%s: Card read-only status %d\n", __func__, status);
3074
3075 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003076}
3077
3078static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3079{
3080 struct msmsdcc_host *host = mmc_priv(mmc);
3081 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303083 /*
3084 * We may come here with clocks turned off in that case don't
3085 * attempt to write into MASK0 register. While turning on the
3086 * clocks mci_irqenable will be written to MASK0 register.
3087 */
San Mehat9d2bd732009-09-22 16:44:22 -07003088
3089 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003090 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303092 if (host->clks_on) {
3093 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303095 mb();
3096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 } else {
3098 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303099 if (host->clks_on) {
3100 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303102 mb();
3103 }
San Mehat9d2bd732009-09-22 16:44:22 -07003104 }
3105 spin_unlock_irqrestore(&host->lock, flags);
3106}
3107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303109static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003110{
subhashj245831e2012-04-30 18:46:17 +05303111 struct device *dev = mmc_dev(host->mmc);
3112
3113 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3114 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3115 " request_pending=%d, request=%d\n",
3116 mmc_hostname(host->mmc), dev->power.runtime_status,
3117 atomic_read(&dev->power.usage_count),
3118 dev->power.is_suspended, dev->power.disable_depth,
3119 dev->power.runtime_error, dev->power.request_pending,
3120 dev->power.request);
3121}
3122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123static int msmsdcc_enable(struct mmc_host *mmc)
3124{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003125 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003127 struct msmsdcc_host *host = mmc_priv(mmc);
3128
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303129 msmsdcc_pm_qos_update_latency(host, 1);
3130
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003131 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303132 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003134 if (host->sdcc_suspended && host->pending_resume &&
3135 !pm_runtime_suspended(dev)) {
3136 host->pending_resume = false;
3137 pm_runtime_get_noresume(dev);
3138 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303139 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003140 }
3141
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303142 if (dev->power.runtime_status == RPM_SUSPENDING) {
3143 if (mmc->suspend_task == current) {
3144 pm_runtime_get_noresume(dev);
3145 goto out;
3146 }
3147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303149 rc = pm_runtime_get_sync(dev);
3150
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303151skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303152 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3154 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303155 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303156 return rc;
3157 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303158out:
3159 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303160 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161}
3162
Steve Mucklef132c6c2012-06-06 18:30:57 -07003163static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003164{
3165 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303166 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303168 msmsdcc_pm_qos_update_latency(host, 0);
3169
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303170 if (mmc->card && mmc_card_sdio(mmc->card)) {
3171 rc = 0;
3172 goto out;
3173 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303174
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303175 if (host->plat->disable_runtime_pm)
3176 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177
3178 rc = pm_runtime_put_sync(mmc->parent);
3179
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003180 /*
3181 * Ignore -EAGAIN as that is not fatal, it means that
3182 * either runtime usage count is non-zero or the runtime
3183 * pm itself is disabled or not in proper state to process
3184 * idle notification.
3185 */
3186 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3188 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303189 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003190 return rc;
3191 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303192
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303193out:
3194 msmsdcc_msm_bus_queue_work(host);
3195 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196}
3197#else
subhashj245831e2012-04-30 18:46:17 +05303198static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3199
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303200static int msmsdcc_enable(struct mmc_host *mmc)
3201{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003202 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303203 struct msmsdcc_host *host = mmc_priv(mmc);
3204 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303205 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303206
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303207 msmsdcc_pm_qos_update_latency(host, 1);
3208
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303209 if (mmc->card && mmc_card_sdio(mmc->card)) {
3210 rc = 0;
3211 goto out;
3212 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003213
3214 if (host->sdcc_suspended && host->pending_resume) {
3215 host->pending_resume = false;
3216 rc = msmsdcc_runtime_resume(dev);
3217 goto out;
3218 }
3219
Asutosh Dasf5298c32012-04-03 14:51:47 +05303220 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303221 spin_lock_irqsave(&host->lock, flags);
3222 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303223 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303224 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303225 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303226 host->clks_on = 1;
3227 }
3228 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303229 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303230
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003231out:
3232 if (rc < 0) {
3233 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3234 __func__, rc);
3235 return rc;
3236 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303237 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303238 return 0;
3239}
3240
Steve Mucklef132c6c2012-06-06 18:30:57 -07003241static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303242{
3243 struct msmsdcc_host *host = mmc_priv(mmc);
3244 unsigned long flags;
3245
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303246 msmsdcc_pm_qos_update_latency(host, 0);
3247
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303248 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303249 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303250
Asutosh Dasf5298c32012-04-03 14:51:47 +05303251 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303252 spin_lock_irqsave(&host->lock, flags);
3253 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303254 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303255 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303256 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303257 host->clks_on = 0;
3258 }
3259 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303260 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303261
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303262out:
3263 msmsdcc_msm_bus_queue_work(host);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303264 return 0;
3265}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266#endif
3267
Subhash Jadavani937c7502012-06-01 15:34:46 +05303268static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3269 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003270{
3271 struct msmsdcc_host *host = mmc_priv(mmc);
3272 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303273 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003274
Subhash Jadavani00083572012-02-15 16:18:01 +05303275 spin_lock_irqsave(&host->lock, flags);
3276 host->io_pad_pwr_switch = 0;
3277 spin_unlock_irqrestore(&host->lock, flags);
3278
Subhash Jadavani937c7502012-06-01 15:34:46 +05303279 switch (ios->signal_voltage) {
3280 case MMC_SIGNAL_VOLTAGE_330:
3281 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3282 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303283 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303284 case MMC_SIGNAL_VOLTAGE_180:
3285 break;
3286 case MMC_SIGNAL_VOLTAGE_120:
3287 /*
3288 * For eMMC cards, VDD_IO voltage range must be changed
3289 * only if it operates in HS200 SDR 1.2V mode or in
3290 * DDR 1.2V mode.
3291 */
3292 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003293 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303294 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003295 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303296 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003297 goto out;
3298 }
San Mehat9d2bd732009-09-22 16:44:22 -07003299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003300 /*
3301 * If we are here means voltage switch from high voltage to
3302 * low voltage is required
3303 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303304 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305
3306 /*
3307 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3308 * register until they become all zeros.
3309 */
3310 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303311 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3313 mmc_hostname(mmc), __func__);
3314 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003315 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316
3317 /* Stop SD CLK output. */
3318 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3319 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303320 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003321 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322
3323 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303324 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3325 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003326 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303327 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303328 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003329 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330
3331 spin_lock_irqsave(&host->lock, flags);
3332 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3333 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303334 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335 host->io_pad_pwr_switch = 1;
3336 spin_unlock_irqrestore(&host->lock, flags);
3337
3338 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3339 usleep_range(5000, 5500);
3340
3341 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303342 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3344 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303345 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003346 spin_unlock_irqrestore(&host->lock, flags);
3347
3348 /*
3349 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3350 * don't become all ones within 1 ms then a Voltage Switch
3351 * sequence has failed and a power cycle to the card is required.
3352 * Otherwise Voltage Switch sequence is completed successfully.
3353 */
3354 usleep_range(1000, 1500);
3355
3356 spin_lock_irqsave(&host->lock, flags);
3357 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3358 != (0xF << 1)) {
3359 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3360 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303361 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003362 goto out_unlock;
3363 }
3364
3365out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303366 /* Enable PWRSAVE */
3367 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3368 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303369 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003370 spin_unlock_irqrestore(&host->lock, flags);
3371out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303372 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003373}
3374
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303375static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378
3379 /* Program the MCLK value to MCLK_FREQ bit field */
3380 if (host->clk_rate <= 112000000)
3381 mclk_freq = 0;
3382 else if (host->clk_rate <= 125000000)
3383 mclk_freq = 1;
3384 else if (host->clk_rate <= 137000000)
3385 mclk_freq = 2;
3386 else if (host->clk_rate <= 150000000)
3387 mclk_freq = 3;
3388 else if (host->clk_rate <= 162000000)
3389 mclk_freq = 4;
3390 else if (host->clk_rate <= 175000000)
3391 mclk_freq = 5;
3392 else if (host->clk_rate <= 187000000)
3393 mclk_freq = 6;
3394 else if (host->clk_rate <= 200000000)
3395 mclk_freq = 7;
3396
3397 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3398 & ~(7 << 24)) | (mclk_freq << 24)),
3399 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400}
3401
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303402/* Initialize the DLL (Programmable Delay Line ) */
3403static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003404{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303406 unsigned long flags;
3407 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303409 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410 /*
3411 * Make sure that clock is always enabled when DLL
3412 * tuning is in progress. Keeping PWRSAVE ON may
3413 * turn off the clock. So let's disable the PWRSAVE
3414 * here and re-enable it once tuning is completed.
3415 */
3416 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3417 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303418 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303419
3420 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3421 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3422 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3423
3424 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3425 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3426 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3427
3428 msmsdcc_cm_sdc4_dll_set_freq(host);
3429
3430 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3431 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3432 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3433
3434 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3435 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3436 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3437
3438 /* Set DLL_EN bit to 1. */
3439 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3440 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3441
3442 /* Set CK_OUT_EN bit to 1. */
3443 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3444 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3445
3446 wait_cnt = 50;
3447 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3448 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3449 /* max. wait for 50us sec for LOCK bit to be set */
3450 if (--wait_cnt == 0) {
3451 pr_err("%s: %s: DLL failed to LOCK\n",
3452 mmc_hostname(host->mmc), __func__);
3453 rc = -ETIMEDOUT;
3454 goto out;
3455 }
3456 /* wait for 1us before polling again */
3457 udelay(1);
3458 }
3459
3460out:
3461 /* re-enable PWRSAVE */
3462 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3463 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303464 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303465 spin_unlock_irqrestore(&host->lock, flags);
3466
3467 return rc;
3468}
3469
3470static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3471 u8 poll)
3472{
3473 int rc = 0;
3474 u32 wait_cnt = 50;
3475 u8 ck_out_en = 0;
3476
3477 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3478 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3479 MCI_CK_OUT_EN);
3480
3481 while (ck_out_en != poll) {
3482 if (--wait_cnt == 0) {
3483 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3484 mmc_hostname(host->mmc), __func__, poll);
3485 rc = -ETIMEDOUT;
3486 goto out;
3487 }
3488 udelay(1);
3489
3490 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3491 MCI_CK_OUT_EN);
3492 }
3493out:
3494 return rc;
3495}
3496
3497/*
3498 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3499 * calibration sequence. This function should be called before
3500 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3501 * commands (CMD17/CMD18).
3502 *
3503 * This function gets called when host spinlock acquired.
3504 */
3505static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3506{
3507 int rc = 0;
3508 u32 config;
3509
3510 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3511 config |= MCI_CDR_EN;
3512 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3513 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3514
3515 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3516 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3517 if (rc)
3518 goto err_out;
3519
3520 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3521 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3522 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3523
3524 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3525 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3526 if (rc)
3527 goto err_out;
3528
3529 goto out;
3530
3531err_out:
3532 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3533out:
3534 return rc;
3535}
3536
3537static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3538 u8 phase)
3539{
3540 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303541 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3542 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3543 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303544 unsigned long flags;
3545 u32 config;
3546
3547 spin_lock_irqsave(&host->lock, flags);
3548
3549 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3550 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3551 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3552 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3553
3554 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3555 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3556 if (rc)
3557 goto err_out;
3558
3559 /*
3560 * Write the selected DLL clock output phase (0 ... 15)
3561 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3562 */
3563 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3564 & ~(0xF << 20))
3565 | (grey_coded_phase_table[phase] << 20)),
3566 host->base + MCI_DLL_CONFIG);
3567
3568 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3569 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3570 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3571
3572 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3573 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3574 if (rc)
3575 goto err_out;
3576
3577 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3578 config |= MCI_CDR_EN;
3579 config &= ~MCI_CDR_EXT_EN;
3580 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3581 goto out;
3582
3583err_out:
3584 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3585 mmc_hostname(host->mmc), __func__, phase);
3586out:
3587 spin_unlock_irqrestore(&host->lock, flags);
3588 return rc;
3589}
3590
3591/*
3592 * Find out the greatest range of consecuitive selected
3593 * DLL clock output phases that can be used as sampling
3594 * setting for SD3.0 UHS-I card read operation (in SDR104
3595 * timing mode) or for eMMC4.5 card read operation (in HS200
3596 * timing mode).
3597 * Select the 3/4 of the range and configure the DLL with the
3598 * selected DLL clock output phase.
3599*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303600static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303601 u8 *phase_table, u8 total_phases)
3602{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303603 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303604 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303605 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3606 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303607 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303608 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3609 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303610
Subhash Jadavani6159c622012-03-15 19:05:55 +05303611 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303612 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3613 mmc_hostname(host->mmc), __func__, total_phases);
3614 return -EINVAL;
3615 }
3616
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303617 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303618 ranges[row_index][col_index] = phase_table[cnt];
3619 phases_per_row[row_index] += 1;
3620 col_index++;
3621
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303622 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303623 continue;
3624 /* check if next phase in phase_table is consecutive or not */
3625 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3626 row_index++;
3627 col_index = 0;
3628 }
3629 }
3630
Subhash Jadavani6159c622012-03-15 19:05:55 +05303631 if (row_index >= MAX_PHASES)
3632 return -EINVAL;
3633
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303634 /* Check if phase-0 is present in first valid window? */
3635 if (!ranges[0][0]) {
3636 phase_0_found = true;
3637 phase_0_raw_index = 0;
3638 /* Check if cycle exist between 2 valid windows */
3639 for (cnt = 1; cnt <= row_index; cnt++) {
3640 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303641 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303642 if (ranges[cnt][i] == 15) {
3643 phase_15_found = true;
3644 phase_15_raw_index = cnt;
3645 break;
3646 }
3647 }
3648 }
3649 }
3650 }
3651
3652 /* If 2 valid windows form cycle then merge them as single window */
3653 if (phase_0_found && phase_15_found) {
3654 /* number of phases in raw where phase 0 is present */
3655 u8 phases_0 = phases_per_row[phase_0_raw_index];
3656 /* number of phases in raw where phase 15 is present */
3657 u8 phases_15 = phases_per_row[phase_15_raw_index];
3658
Subhash Jadavani6159c622012-03-15 19:05:55 +05303659 if (phases_0 + phases_15 >= MAX_PHASES)
3660 /*
3661 * If there are more than 1 phase windows then total
3662 * number of phases in both the windows should not be
3663 * more than or equal to MAX_PHASES.
3664 */
3665 return -EINVAL;
3666
3667 /* Merge 2 cyclic windows */
3668 i = phases_15;
3669 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303670 ranges[phase_15_raw_index][i] =
3671 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303672 if (++i >= MAX_PHASES)
3673 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303674 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303675
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303676 phases_per_row[phase_0_raw_index] = 0;
3677 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3678 }
3679
3680 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303681 if (phases_per_row[cnt] > curr_max) {
3682 curr_max = phases_per_row[cnt];
3683 selected_row_index = cnt;
3684 }
3685 }
3686
Subhash Jadavani6159c622012-03-15 19:05:55 +05303687 i = ((curr_max * 3) / 4);
3688 if (i)
3689 i--;
3690
Subhash Jadavani34187042012-03-02 10:59:49 +05303691 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303692
Subhash Jadavani6159c622012-03-15 19:05:55 +05303693 if (ret >= MAX_PHASES) {
3694 ret = -EINVAL;
3695 pr_err("%s: %s: invalid phase selected=%d\n",
3696 mmc_hostname(host->mmc), __func__, ret);
3697 }
3698
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303699 return ret;
3700}
3701
Girish K Sa3f41692012-02-29 12:00:09 +05303702static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303703{
3704 int rc = 0;
3705 struct msmsdcc_host *host = mmc_priv(mmc);
3706 unsigned long flags;
3707 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303708 const u32 *tuning_block_pattern = tuning_block_64;
3709 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303710
3711 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3712
3713 /* Tuning is only required for SDR104 modes */
3714 if (!host->tuning_needed) {
3715 rc = 0;
3716 goto exit;
3717 }
3718
3719 spin_lock_irqsave(&host->lock, flags);
3720 WARN(!host->pwr, "SDCC power is turned off\n");
3721 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3722 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3723
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303724 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303725 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3726 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3727 tuning_block_pattern = tuning_block_128;
3728 size = sizeof(tuning_block_128);
3729 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303730 spin_unlock_irqrestore(&host->lock, flags);
3731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003732 /* first of all reset the tuning block */
3733 rc = msmsdcc_init_cm_sdc4_dll(host);
3734 if (rc)
3735 goto out;
3736
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303737 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738 if (!data_buf) {
3739 rc = -ENOMEM;
3740 goto out;
3741 }
3742
3743 phase = 0;
3744 do {
3745 struct mmc_command cmd = {0};
3746 struct mmc_data data = {0};
3747 struct mmc_request mrq = {
3748 .cmd = &cmd,
3749 .data = &data
3750 };
3751 struct scatterlist sg;
3752
3753 /* set the phase in delay line hw block */
3754 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3755 if (rc)
3756 goto kfree;
3757
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303758 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3760
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303761 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762 data.blocks = 1;
3763 data.flags = MMC_DATA_READ;
3764 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3765
3766 data.sg = &sg;
3767 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303768 sg_init_one(&sg, data_buf, size);
3769 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003770 mmc_wait_for_req(mmc, &mrq);
3771
3772 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303773 !memcmp(data_buf, tuning_block_pattern, size)) {
3774 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303776 pr_debug("%s: %s: found good phase = %d\n",
3777 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 }
3779 } while (++phase < 16);
3780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303782 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303783 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303784 if (rc < 0)
3785 goto kfree;
3786 else
3787 phase = (u8)rc;
3788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789 /*
3790 * Finally set the selected phase in delay
3791 * line hw block.
3792 */
3793 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3794 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303795 goto kfree;
3796 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3797 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 } else {
3799 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303800 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303802 msmsdcc_dump_sdcc_state(host);
3803 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003804 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003805
3806kfree:
3807 kfree(data_buf);
3808out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303809 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303810 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303811 spin_unlock_irqrestore(&host->lock, flags);
3812exit:
3813 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003814 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003815}
3816
San Mehat9d2bd732009-09-22 16:44:22 -07003817static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 .enable = msmsdcc_enable,
3819 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303820 .pre_req = msmsdcc_pre_req,
3821 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003822 .request = msmsdcc_request,
3823 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003825 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303826 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003827 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003828};
3829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830static unsigned int
3831msmsdcc_slot_status(struct msmsdcc_host *host)
3832{
3833 int status;
3834 unsigned int gpio_no = host->plat->status_gpio;
3835
3836 status = gpio_request(gpio_no, "SD_HW_Detect");
3837 if (status) {
3838 pr_err("%s: %s: Failed to request GPIO %d\n",
3839 mmc_hostname(host->mmc), __func__, gpio_no);
3840 } else {
3841 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003842 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003843 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003844 if (host->plat->is_status_gpio_active_low)
3845 status = !status;
3846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847 gpio_free(gpio_no);
3848 }
3849 return status;
3850}
3851
San Mehat9d2bd732009-09-22 16:44:22 -07003852static void
3853msmsdcc_check_status(unsigned long data)
3854{
3855 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3856 unsigned int status;
3857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003859 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003861 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 status = msmsdcc_slot_status(host);
3863
Krishna Konda941604a2012-01-10 17:46:34 -08003864 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003866 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003867 if (host->plat->status)
3868 pr_info("%s: Slot status change detected "
3869 "(%d -> %d)\n",
3870 mmc_hostname(host->mmc),
3871 host->oldstat, status);
3872 else if (host->plat->is_status_gpio_active_low)
3873 pr_info("%s: Slot status change detected "
3874 "(%d -> %d) and the card detect GPIO"
3875 " is ACTIVE_LOW\n",
3876 mmc_hostname(host->mmc),
3877 host->oldstat, status);
3878 else
3879 pr_info("%s: Slot status change detected "
3880 "(%d -> %d) and the card detect GPIO"
3881 " is ACTIVE_HIGH\n",
3882 mmc_hostname(host->mmc),
3883 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003884 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885 }
3886 host->oldstat = status;
3887 } else {
3888 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003889 }
San Mehat9d2bd732009-09-22 16:44:22 -07003890}
3891
3892static irqreturn_t
3893msmsdcc_platform_status_irq(int irq, void *dev_id)
3894{
3895 struct msmsdcc_host *host = dev_id;
3896
Girish K Sa3c76eb2011-10-11 11:44:09 +05303897 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003898 msmsdcc_check_status((unsigned long) host);
3899 return IRQ_HANDLED;
3900}
3901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902static irqreturn_t
3903msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3904{
3905 struct msmsdcc_host *host = dev_id;
3906
3907 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3908 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303909 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003910 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303911 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 wake_lock(&host->sdio_wlock);
3913 msmsdcc_disable_irq_wake(host);
3914 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303915 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 }
3917 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303919 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303920 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303921 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922 }
3923 spin_unlock(&host->lock);
3924
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303925out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926 return IRQ_HANDLED;
3927}
3928
San Mehat9d2bd732009-09-22 16:44:22 -07003929static void
3930msmsdcc_status_notify_cb(int card_present, void *dev_id)
3931{
3932 struct msmsdcc_host *host = dev_id;
3933
Girish K Sa3c76eb2011-10-11 11:44:09 +05303934 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003935 card_present);
3936 msmsdcc_check_status((unsigned long) host);
3937}
3938
San Mehat9d2bd732009-09-22 16:44:22 -07003939static int
3940msmsdcc_init_dma(struct msmsdcc_host *host)
3941{
3942 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3943 host->dma.host = host;
3944 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003945 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003946
3947 if (!host->dmares)
3948 return -ENODEV;
3949
3950 host->dma.nc = dma_alloc_coherent(NULL,
3951 sizeof(struct msmsdcc_nc_dmadata),
3952 &host->dma.nc_busaddr,
3953 GFP_KERNEL);
3954 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003955 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003956 return -ENOMEM;
3957 }
3958 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3959 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3960 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3961 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3962 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003963 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003964
3965 return 0;
3966}
3967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3969/**
3970 * Allocate and Connect a SDCC peripheral's SPS endpoint
3971 *
3972 * This function allocates endpoint context and
3973 * connect it with memory endpoint by calling
3974 * appropriate SPS driver APIs.
3975 *
3976 * Also registers a SPS callback function with
3977 * SPS driver
3978 *
3979 * This function should only be called once typically
3980 * during driver probe.
3981 *
3982 * @host - Pointer to sdcc host structure
3983 * @ep - Pointer to sps endpoint data structure
3984 * @is_produce - 1 means Producer endpoint
3985 * 0 means Consumer endpoint
3986 *
3987 * @return - 0 if successful else negative value.
3988 *
3989 */
3990static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3991 struct msmsdcc_sps_ep_conn_data *ep,
3992 bool is_producer)
3993{
3994 int rc = 0;
3995 struct sps_pipe *sps_pipe_handle;
3996 struct sps_connect *sps_config = &ep->config;
3997 struct sps_register_event *sps_event = &ep->event;
3998
3999 /* Allocate endpoint context */
4000 sps_pipe_handle = sps_alloc_endpoint();
4001 if (!sps_pipe_handle) {
4002 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4003 mmc_hostname(host->mmc), is_producer);
4004 rc = -ENOMEM;
4005 goto out;
4006 }
4007
4008 /* Get default connection configuration for an endpoint */
4009 rc = sps_get_config(sps_pipe_handle, sps_config);
4010 if (rc) {
4011 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4012 " rc=%d", mmc_hostname(host->mmc),
4013 (u32)sps_pipe_handle, rc);
4014 goto get_config_err;
4015 }
4016
4017 /* Modify the default connection configuration */
4018 if (is_producer) {
4019 /*
4020 * For SDCC producer transfer, source should be
4021 * SDCC peripheral where as destination should
4022 * be system memory.
4023 */
4024 sps_config->source = host->sps.bam_handle;
4025 sps_config->destination = SPS_DEV_HANDLE_MEM;
4026 /* Producer pipe will handle this connection */
4027 sps_config->mode = SPS_MODE_SRC;
4028 sps_config->options =
4029 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4030 } else {
4031 /*
4032 * For SDCC consumer transfer, source should be
4033 * system memory where as destination should
4034 * SDCC peripheral
4035 */
4036 sps_config->source = SPS_DEV_HANDLE_MEM;
4037 sps_config->destination = host->sps.bam_handle;
4038 sps_config->mode = SPS_MODE_DEST;
4039 sps_config->options =
4040 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4041 }
4042
4043 /* Producer pipe index */
4044 sps_config->src_pipe_index = host->sps.src_pipe_index;
4045 /* Consumer pipe index */
4046 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4047 /*
4048 * This event thresold value is only significant for BAM-to-BAM
4049 * transfer. It's ignored for BAM-to-System mode transfer.
4050 */
4051 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304052
4053 /* Allocate maximum descriptor fifo size */
4054 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4055 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4057 sps_config->desc.size,
4058 &sps_config->desc.phys_base,
4059 GFP_KERNEL);
4060
Pratibhasagar V00b94332011-10-18 14:57:27 +05304061 if (!sps_config->desc.base) {
4062 rc = -ENOMEM;
4063 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4064 , mmc_hostname(host->mmc));
4065 goto get_config_err;
4066 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4068
4069 /* Establish connection between peripheral and memory endpoint */
4070 rc = sps_connect(sps_pipe_handle, sps_config);
4071 if (rc) {
4072 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4073 " rc=%d", mmc_hostname(host->mmc),
4074 (u32)sps_pipe_handle, rc);
4075 goto sps_connect_err;
4076 }
4077
4078 sps_event->mode = SPS_TRIGGER_CALLBACK;
4079 sps_event->options = SPS_O_EOT;
4080 sps_event->callback = msmsdcc_sps_complete_cb;
4081 sps_event->xfer_done = NULL;
4082 sps_event->user = (void *)host;
4083
4084 /* Register callback event for EOT (End of transfer) event. */
4085 rc = sps_register_event(sps_pipe_handle, sps_event);
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 reg_event_err;
4091 }
4092 /* Now save the sps pipe handle */
4093 ep->pipe_handle = sps_pipe_handle;
4094 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4095 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4096 __func__, is_producer ? "READ" : "WRITE",
4097 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4098 goto out;
4099
4100reg_event_err:
4101 sps_disconnect(sps_pipe_handle);
4102sps_connect_err:
4103 dma_free_coherent(mmc_dev(host->mmc),
4104 sps_config->desc.size,
4105 sps_config->desc.base,
4106 sps_config->desc.phys_base);
4107get_config_err:
4108 sps_free_endpoint(sps_pipe_handle);
4109out:
4110 return rc;
4111}
4112
4113/**
4114 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4115 *
4116 * This function disconnect endpoint and deallocates
4117 * endpoint context.
4118 *
4119 * This function should only be called once typically
4120 * during driver remove.
4121 *
4122 * @host - Pointer to sdcc host structure
4123 * @ep - Pointer to sps endpoint data structure
4124 *
4125 */
4126static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4127 struct msmsdcc_sps_ep_conn_data *ep)
4128{
4129 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4130 struct sps_connect *sps_config = &ep->config;
4131 struct sps_register_event *sps_event = &ep->event;
4132
4133 sps_event->xfer_done = NULL;
4134 sps_event->callback = NULL;
4135 sps_register_event(sps_pipe_handle, sps_event);
4136 sps_disconnect(sps_pipe_handle);
4137 dma_free_coherent(mmc_dev(host->mmc),
4138 sps_config->desc.size,
4139 sps_config->desc.base,
4140 sps_config->desc.phys_base);
4141 sps_free_endpoint(sps_pipe_handle);
4142}
4143
4144/**
4145 * Reset SDCC peripheral's SPS endpoint
4146 *
4147 * This function disconnects an endpoint.
4148 *
4149 * This function should be called for reseting
4150 * SPS endpoint when data transfer error is
4151 * encountered during data transfer. This
4152 * can be considered as soft reset to endpoint.
4153 *
4154 * This function should only be called if
4155 * msmsdcc_sps_init() is already called.
4156 *
4157 * @host - Pointer to sdcc host structure
4158 * @ep - Pointer to sps endpoint data structure
4159 *
4160 * @return - 0 if successful else negative value.
4161 */
4162static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4163 struct msmsdcc_sps_ep_conn_data *ep)
4164{
4165 int rc = 0;
4166 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4167
4168 rc = sps_disconnect(sps_pipe_handle);
4169 if (rc) {
4170 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4171 " rc=%d", mmc_hostname(host->mmc), __func__,
4172 (u32)sps_pipe_handle, rc);
4173 goto out;
4174 }
4175 out:
4176 return rc;
4177}
4178
4179/**
4180 * Restore SDCC peripheral's SPS endpoint
4181 *
4182 * This function connects an endpoint.
4183 *
4184 * This function should be called for restoring
4185 * SPS endpoint after data transfer error is
4186 * encountered during data transfer. This
4187 * can be considered as soft reset to endpoint.
4188 *
4189 * This function should only be called if
4190 * msmsdcc_sps_reset_ep() is called before.
4191 *
4192 * @host - Pointer to sdcc host structure
4193 * @ep - Pointer to sps endpoint data structure
4194 *
4195 * @return - 0 if successful else negative value.
4196 */
4197static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4198 struct msmsdcc_sps_ep_conn_data *ep)
4199{
4200 int rc = 0;
4201 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4202 struct sps_connect *sps_config = &ep->config;
4203 struct sps_register_event *sps_event = &ep->event;
4204
4205 /* Establish connection between peripheral and memory endpoint */
4206 rc = sps_connect(sps_pipe_handle, sps_config);
4207 if (rc) {
4208 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4209 " rc=%d", mmc_hostname(host->mmc), __func__,
4210 (u32)sps_pipe_handle, rc);
4211 goto out;
4212 }
4213
4214 /* Register callback event for EOT (End of transfer) event. */
4215 rc = sps_register_event(sps_pipe_handle, sps_event);
4216 if (rc) {
4217 pr_err("%s: %s: sps_register_event() failed!!!"
4218 " pipe_handle=0x%x, rc=%d",
4219 mmc_hostname(host->mmc), __func__,
4220 (u32)sps_pipe_handle, rc);
4221 goto reg_event_err;
4222 }
4223 goto out;
4224
4225reg_event_err:
4226 sps_disconnect(sps_pipe_handle);
4227out:
4228 return rc;
4229}
4230
4231/**
4232 * Initialize SPS HW connected with SDCC core
4233 *
4234 * This function register BAM HW resources with
4235 * SPS driver and then initialize 2 SPS endpoints
4236 *
4237 * This function should only be called once typically
4238 * during driver probe.
4239 *
4240 * @host - Pointer to sdcc host structure
4241 *
4242 * @return - 0 if successful else negative value.
4243 *
4244 */
4245static int msmsdcc_sps_init(struct msmsdcc_host *host)
4246{
4247 int rc = 0;
4248 struct sps_bam_props bam = {0};
4249
4250 host->bam_base = ioremap(host->bam_memres->start,
4251 resource_size(host->bam_memres));
4252 if (!host->bam_base) {
4253 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4254 " size=0x%x", mmc_hostname(host->mmc),
4255 host->bam_memres->start,
4256 (host->bam_memres->end -
4257 host->bam_memres->start));
4258 rc = -ENOMEM;
4259 goto out;
4260 }
4261
4262 bam.phys_addr = host->bam_memres->start;
4263 bam.virt_addr = host->bam_base;
4264 /*
4265 * This event thresold value is only significant for BAM-to-BAM
4266 * transfer. It's ignored for BAM-to-System mode transfer.
4267 */
4268 bam.event_threshold = 0x10; /* Pipe event threshold */
4269 /*
4270 * This threshold controls when the BAM publish
4271 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304272 * SPS HW will be used for data transfer size even
4273 * less than SDCC FIFO size. So let's set BAM summing
4274 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304276 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004277 /* SPS driver wll handle the SDCC BAM IRQ */
4278 bam.irq = (u32)host->bam_irqres->start;
4279 bam.manage = SPS_BAM_MGR_LOCAL;
4280
4281 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4282 (u32)bam.phys_addr);
4283 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4284 (u32)bam.virt_addr);
4285
4286 /* Register SDCC Peripheral BAM device to SPS driver */
4287 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4288 if (rc) {
4289 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4290 mmc_hostname(host->mmc), rc);
4291 goto reg_bam_err;
4292 }
4293 pr_info("%s: BAM device registered. bam_handle=0x%x",
4294 mmc_hostname(host->mmc), host->sps.bam_handle);
4295
4296 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4297 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4298
4299 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4300 SPS_PROD_PERIPHERAL);
4301 if (rc)
4302 goto sps_reset_err;
4303 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4304 SPS_CONS_PERIPHERAL);
4305 if (rc)
4306 goto cons_conn_err;
4307
4308 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4309 mmc_hostname(host->mmc),
4310 (unsigned long long)host->bam_memres->start,
4311 (unsigned int)host->bam_irqres->start);
4312 goto out;
4313
4314cons_conn_err:
4315 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4316sps_reset_err:
4317 sps_deregister_bam_device(host->sps.bam_handle);
4318reg_bam_err:
4319 iounmap(host->bam_base);
4320out:
4321 return rc;
4322}
4323
4324/**
4325 * De-initialize SPS HW connected with SDCC core
4326 *
4327 * This function deinitialize SPS endpoints and then
4328 * deregisters BAM resources from SPS driver.
4329 *
4330 * This function should only be called once typically
4331 * during driver remove.
4332 *
4333 * @host - Pointer to sdcc host structure
4334 *
4335 */
4336static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4337{
4338 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4339 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4340 sps_deregister_bam_device(host->sps.bam_handle);
4341 iounmap(host->bam_base);
4342}
4343#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4344
4345static ssize_t
4346show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4347{
4348 struct mmc_host *mmc = dev_get_drvdata(dev);
4349 struct msmsdcc_host *host = mmc_priv(mmc);
4350 int poll;
4351 unsigned long flags;
4352
4353 spin_lock_irqsave(&host->lock, flags);
4354 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4355 spin_unlock_irqrestore(&host->lock, flags);
4356
4357 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4358}
4359
4360static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304361store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 const char *buf, size_t count)
4363{
4364 struct mmc_host *mmc = dev_get_drvdata(dev);
4365 struct msmsdcc_host *host = mmc_priv(mmc);
4366 int value;
4367 unsigned long flags;
4368
4369 sscanf(buf, "%d", &value);
4370
4371 spin_lock_irqsave(&host->lock, flags);
4372 if (value) {
4373 mmc->caps |= MMC_CAP_NEEDS_POLL;
4374 mmc_detect_change(host->mmc, 0);
4375 } else {
4376 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4377 }
4378#ifdef CONFIG_HAS_EARLYSUSPEND
4379 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4380#endif
4381 spin_unlock_irqrestore(&host->lock, flags);
4382 return count;
4383}
4384
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304385static ssize_t
4386show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4387 char *buf)
4388{
4389 struct mmc_host *mmc = dev_get_drvdata(dev);
4390 struct msmsdcc_host *host = mmc_priv(mmc);
4391
4392 return snprintf(buf, PAGE_SIZE, "%u\n",
4393 host->msm_bus_vote.is_max_bw_needed);
4394}
4395
4396static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304397store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304398 const char *buf, size_t count)
4399{
4400 struct mmc_host *mmc = dev_get_drvdata(dev);
4401 struct msmsdcc_host *host = mmc_priv(mmc);
4402 uint32_t value;
4403 unsigned long flags;
4404
4405 if (!kstrtou32(buf, 0, &value)) {
4406 spin_lock_irqsave(&host->lock, flags);
4407 host->msm_bus_vote.is_max_bw_needed = !!value;
4408 spin_unlock_irqrestore(&host->lock, flags);
4409 }
4410
4411 return count;
4412}
4413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004414#ifdef CONFIG_HAS_EARLYSUSPEND
4415static void msmsdcc_early_suspend(struct early_suspend *h)
4416{
4417 struct msmsdcc_host *host =
4418 container_of(h, struct msmsdcc_host, early_suspend);
4419 unsigned long flags;
4420
4421 spin_lock_irqsave(&host->lock, flags);
4422 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4423 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4424 spin_unlock_irqrestore(&host->lock, flags);
4425};
4426static void msmsdcc_late_resume(struct early_suspend *h)
4427{
4428 struct msmsdcc_host *host =
4429 container_of(h, struct msmsdcc_host, early_suspend);
4430 unsigned long flags;
4431
4432 if (host->polling_enabled) {
4433 spin_lock_irqsave(&host->lock, flags);
4434 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4435 mmc_detect_change(host->mmc, 0);
4436 spin_unlock_irqrestore(&host->lock, flags);
4437 }
4438};
4439#endif
4440
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304441static void msmsdcc_print_regs(const char *name, void __iomem *base,
4442 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304443{
4444 unsigned int i;
4445
4446 if (!base)
4447 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304448
4449 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4450 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304451 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304452 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4453 (u32)readl_relaxed(base + i*4),
4454 (u32)readl_relaxed(base + ((i+1)*4)),
4455 (u32)readl_relaxed(base + ((i+2)*4)),
4456 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304457 }
4458}
4459
4460static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4461{
4462 /* Dump current state of SDCC clocks, power and irq */
4463 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304464 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304465 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304466 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4467 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304468 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4469 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4470
4471 /* Now dump SDCC registers. Don't print FIFO registers */
4472 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304473 msmsdcc_print_regs("SDCC-CORE", host->base,
4474 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304475
4476 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304477 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304478 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4479 else if (host->is_dma_mode)
4480 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4481 mmc_hostname(host->mmc), host->dma.busy,
4482 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304483 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304484 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304485 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4486 host->dml_memres->start,
4487 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304488 pr_info("%s: SPS mode: busy=%d\n",
4489 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304490 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304491
4492 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4493 mmc_hostname(host->mmc), host->curr.xfer_size,
4494 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304495 }
4496
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304497 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304498 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4499 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4500 host->curr.got_dataend, host->prog_enable,
4501 host->curr.wait_for_auto_prog_done,
4502 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304503 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304504}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4507{
4508 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4509 struct mmc_request *mrq;
4510 unsigned long flags;
4511
4512 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004513 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 pr_info("%s: %s: dummy CMD52 timeout\n",
4515 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004516 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004517 }
4518
4519 mrq = host->curr.mrq;
4520
4521 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304522 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4523 mrq->cmd->opcode);
4524 msmsdcc_dump_sdcc_state(host);
4525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004526 if (!mrq->cmd->error)
4527 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304528 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004529 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004530 if (mrq->data && !mrq->data->error)
4531 mrq->data->error = -ETIMEDOUT;
4532 host->curr.data_xfered = 0;
4533 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004534 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004535 } else if (host->sps.sg && host->is_sps_mode) {
4536 /* Stop current SPS transfer */
4537 msmsdcc_sps_exit_curr_xfer(host);
4538 } else {
4539 msmsdcc_reset_and_restore(host);
4540 msmsdcc_stop_data(host);
4541 if (mrq->data && mrq->data->stop)
4542 msmsdcc_start_command(host,
4543 mrq->data->stop, 0);
4544 else
4545 msmsdcc_request_end(host, mrq);
4546 }
4547 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304548 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304549 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004550 msmsdcc_reset_and_restore(host);
4551 msmsdcc_request_end(host, mrq);
4552 }
4553 }
4554 spin_unlock_irqrestore(&host->lock, flags);
4555}
4556
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304557static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4558{
4559 int i, ret;
4560 struct mmc_platform_data *pdata;
4561 struct device_node *np = dev->of_node;
4562 u32 bus_width = 0;
4563 u32 *clk_table;
4564 int clk_table_len;
4565 u32 *sup_voltages;
4566 int sup_volt_len;
4567
4568 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4569 if (!pdata) {
4570 dev_err(dev, "could not allocate memory for platform data\n");
4571 goto err;
4572 }
4573
4574 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4575 if (bus_width == 8) {
4576 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4577 } else if (bus_width == 4) {
4578 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4579 } else {
4580 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4581 pdata->mmc_bus_width = 0;
4582 }
4583
4584 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4585 size_t sz;
4586 sz = sup_volt_len / sizeof(*sup_voltages);
4587 if (sz > 0) {
4588 sup_voltages = devm_kzalloc(dev,
4589 sz * sizeof(*sup_voltages), GFP_KERNEL);
4590 if (!sup_voltages) {
4591 dev_err(dev, "No memory for supported voltage\n");
4592 goto err;
4593 }
4594
4595 ret = of_property_read_u32_array(np,
4596 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4597 if (ret < 0) {
4598 dev_err(dev, "error while reading voltage"
4599 "ranges %d\n", ret);
4600 goto err;
4601 }
4602 } else {
4603 dev_err(dev, "No supported voltages\n");
4604 goto err;
4605 }
4606 for (i = 0; i < sz; i += 2) {
4607 u32 mask;
4608
4609 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4610 sup_voltages[i + 1]);
4611 if (!mask)
4612 dev_err(dev, "Invalide voltage range %d\n", i);
4613 pdata->ocr_mask |= mask;
4614 }
4615 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4616 } else {
4617 dev_err(dev, "Supported voltage range not specified\n");
4618 }
4619
4620 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4621 size_t sz;
4622 sz = clk_table_len / sizeof(*clk_table);
4623
4624 if (sz > 0) {
4625 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4626 GFP_KERNEL);
4627 if (!clk_table) {
4628 dev_err(dev, "No memory for clock table\n");
4629 goto err;
4630 }
4631
4632 ret = of_property_read_u32_array(np,
4633 "qcom,sdcc-clk-rates", clk_table, sz);
4634 if (ret < 0) {
4635 dev_err(dev, "error while reading clk"
4636 "table %d\n", ret);
4637 goto err;
4638 }
4639 } else {
4640 dev_err(dev, "clk_table not specified\n");
4641 goto err;
4642 }
4643 pdata->sup_clk_table = clk_table;
4644 pdata->sup_clk_cnt = sz;
4645 } else {
4646 dev_err(dev, "Supported clock rates not specified\n");
4647 }
4648
4649 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4650 pdata->nonremovable = true;
4651 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4652 pdata->disable_cmd23 = true;
4653
4654 return pdata;
4655err:
4656 return NULL;
4657}
4658
San Mehat9d2bd732009-09-22 16:44:22 -07004659static int
4660msmsdcc_probe(struct platform_device *pdev)
4661{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304662 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004663 struct msmsdcc_host *host;
4664 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665 unsigned long flags;
4666 struct resource *core_irqres = NULL;
4667 struct resource *bam_irqres = NULL;
4668 struct resource *core_memres = NULL;
4669 struct resource *dml_memres = NULL;
4670 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004671 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004672 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304673 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004674 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004675
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304676 if (pdev->dev.of_node) {
4677 plat = msmsdcc_populate_pdata(&pdev->dev);
4678 of_property_read_u32((&pdev->dev)->of_node,
4679 "cell-index", &pdev->id);
4680 } else {
4681 plat = pdev->dev.platform_data;
4682 }
San Mehat9d2bd732009-09-22 16:44:22 -07004683
4684 /* must have platform data */
4685 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004686 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004687 ret = -EINVAL;
4688 goto out;
4689 }
4690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004691 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004692 return -EINVAL;
4693
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304694 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4695 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4696 return -EINVAL;
4697 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698
San Mehat9d2bd732009-09-22 16:44:22 -07004699 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004700 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004701 return -ENXIO;
4702 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304703 if (pdev->dev.of_node) {
4704 /*
4705 * Device tree iomem resources are only accessible by index.
4706 * index = 0 -> SDCC register interface
4707 * index = 1 -> DML register interface
4708 * index = 2 -> BAM register interface
4709 * IRQ resources:
4710 * index = 0 -> SDCC IRQ
4711 * index = 1 -> BAM IRQ
4712 */
4713 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4714 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4715 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4716 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4717 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4718 } else {
4719 for (i = 0; i < pdev->num_resources; i++) {
4720 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4721 if (!strncmp(pdev->resource[i].name,
4722 "sdcc_dml_addr",
4723 sizeof("sdcc_dml_addr")))
4724 dml_memres = &pdev->resource[i];
4725 else if (!strncmp(pdev->resource[i].name,
4726 "sdcc_bam_addr",
4727 sizeof("sdcc_bam_addr")))
4728 bam_memres = &pdev->resource[i];
4729 else
4730 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004731
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304732 }
4733 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4734 if (!strncmp(pdev->resource[i].name,
4735 "sdcc_bam_irq",
4736 sizeof("sdcc_bam_irq")))
4737 bam_irqres = &pdev->resource[i];
4738 else
4739 core_irqres = &pdev->resource[i];
4740 }
4741 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4742 if (!strncmp(pdev->resource[i].name,
4743 "sdcc_dma_chnl",
4744 sizeof("sdcc_dma_chnl")))
4745 dmares = &pdev->resource[i];
4746 else if (!strncmp(pdev->resource[i].name,
4747 "sdcc_dma_crci",
4748 sizeof("sdcc_dma_crci")))
4749 dma_crci_res = &pdev->resource[i];
4750 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004751 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004752 }
San Mehat9d2bd732009-09-22 16:44:22 -07004753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754 if (!core_irqres || !core_memres) {
4755 pr_err("%s: Invalid sdcc core resource\n", __func__);
4756 return -ENXIO;
4757 }
4758
4759 /*
4760 * Both BAM and DML memory resource should be preset.
4761 * BAM IRQ resource should also be present.
4762 */
4763 if ((bam_memres && !dml_memres) ||
4764 (!bam_memres && dml_memres) ||
4765 ((bam_memres && dml_memres) && !bam_irqres)) {
4766 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004767 return -ENXIO;
4768 }
4769
4770 /*
4771 * Setup our host structure
4772 */
San Mehat9d2bd732009-09-22 16:44:22 -07004773 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4774 if (!mmc) {
4775 ret = -ENOMEM;
4776 goto out;
4777 }
4778
4779 host = mmc_priv(mmc);
4780 host->pdev_id = pdev->id;
4781 host->plat = plat;
4782 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004783 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05304784
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304785 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004786 host->is_sps_mode = 1;
4787 else if (dmares)
4788 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004789
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004790 host->base = ioremap(core_memres->start,
4791 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004792 if (!host->base) {
4793 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05304794 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004795 }
4796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797 host->core_irqres = core_irqres;
4798 host->bam_irqres = bam_irqres;
4799 host->core_memres = core_memres;
4800 host->dml_memres = dml_memres;
4801 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004802 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004803 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004804 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304805 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004807#ifdef CONFIG_MMC_EMBEDDED_SDIO
4808 if (plat->embedded_sdio)
4809 mmc_set_embedded_sdio_data(mmc,
4810 &plat->embedded_sdio->cis,
4811 &plat->embedded_sdio->cccr,
4812 plat->embedded_sdio->funcs,
4813 plat->embedded_sdio->num_funcs);
4814#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004815
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304816 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4817 (unsigned long)host);
4818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004819 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4820 (unsigned long)host);
4821 if (host->is_dma_mode) {
4822 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05304823 ret = msmsdcc_init_dma(host);
4824 if (ret)
4825 goto ioremap_free;
4826 } else {
4827 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004828 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05304829 }
San Mehat9d2bd732009-09-22 16:44:22 -07004830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004831 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05304832 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05304834 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
4835 if (!IS_ERR_OR_NULL(host->bus_clk)) {
4836 /* Vote for max. clk rate for max. performance */
4837 ret = clk_set_rate(host->bus_clk, INT_MAX);
4838 if (ret)
4839 goto bus_clk_put;
4840 ret = clk_prepare_enable(host->bus_clk);
4841 if (ret)
4842 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07004843 }
4844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004845 /*
4846 * Setup main peripheral bus clock
4847 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004848 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004849 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304850 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004851 if (ret)
4852 goto pclk_put;
4853
4854 host->pclk_rate = clk_get_rate(host->pclk);
4855 }
4856
4857 /*
4858 * Setup SDC MMC clock
4859 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004860 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004861 if (IS_ERR(host->clk)) {
4862 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004863 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004864 }
4865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05304867 if (ret) {
4868 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4869 goto clk_put;
4870 }
4871
Asutosh Dasf5298c32012-04-03 14:51:47 +05304872 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004873 if (ret)
4874 goto clk_put;
4875
San Mehat9d2bd732009-09-22 16:44:22 -07004876 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304877 if (!host->clk_rate)
4878 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304879
4880 /*
4881 * Lookup the Controller Version, to identify the supported features
4882 * Version number read as 0 would indicate SDCC3 or earlier versions
4883 */
4884 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4885 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4886 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304887 /*
4888 * Set the register write delay according to min. clock frequency
4889 * supported and update later when the host->clk_rate changes.
4890 */
4891 host->reg_write_delay =
4892 (1 + ((3 * USEC_PER_SEC) /
4893 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004894
4895 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304896 /* Apply Hard reset to SDCC to put it in power on default state */
4897 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004898
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004899#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304900 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004901 if (host->plat->cpu_dma_latency)
4902 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4903 else
4904 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4905 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304906 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4907
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304908 ret = msmsdcc_msm_bus_register(host);
4909 if (ret)
4910 goto pm_qos_remove;
4911
4912 if (host->msm_bus_vote.client_handle)
4913 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4914 msmsdcc_msm_bus_work);
4915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004916 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004917 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004918 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004919 goto clk_disable;
4920 }
4921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004922
4923 /* Clocks has to be running before accessing SPS/DML HW blocks */
4924 if (host->is_sps_mode) {
4925 /* Initialize SPS */
4926 ret = msmsdcc_sps_init(host);
4927 if (ret)
4928 goto vreg_deinit;
4929 /* Initialize DML */
4930 ret = msmsdcc_dml_init(host);
4931 if (ret)
4932 goto sps_exit;
4933 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304934 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004935
San Mehat9d2bd732009-09-22 16:44:22 -07004936 /*
4937 * Setup MMC host structure
4938 */
4939 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4941 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004942 mmc->ocr_avail = plat->ocr_mask;
Sujit Reddy Thumma0e05f022012-06-11 19:44:18 +05304943 mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
4944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4946 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004947 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304948 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07004949
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304950 /*
4951 * If we send the CMD23 before multi block write/read command
4952 * then we need not to send CMD12 at the end of the transfer.
4953 * If we don't send the CMD12 then only way to detect the PROG_DONE
4954 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4955 * controller. So let's enable the CMD23 for SDCC4 only.
4956 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304957 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304958 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07004959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004960 mmc->caps |= plat->uhs_caps;
4961 /*
4962 * XPC controls the maximum current in the default speed mode of SDXC
4963 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4964 * XPC=1 means 150mA (max.) and speed class is supported.
4965 */
4966 if (plat->xpc_cap)
4967 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4968 MMC_CAP_SET_XPC_180);
4969
Maya Erez25e22612012-05-20 08:45:01 +03004970 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03004971 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304972 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03004973 mmc->caps2 |= MMC_CAP2_SANITIZE;
4974
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304975 if (pdev->dev.of_node) {
4976 if (of_get_property((&pdev->dev)->of_node,
4977 "qcom,sdcc-hs200", NULL))
4978 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4979 }
4980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004981 if (plat->nonremovable)
4982 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004983 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03004985 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
4986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004987 if (plat->is_sdio_al_client)
4988 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004989
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304990 mmc->max_segs = msmsdcc_get_nr_sg(host);
4991 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4992 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004993
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304994 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07004995 mmc->max_seg_size = mmc->max_req_size;
4996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004997 writel_relaxed(0, host->base + MMCIMASK0);
4998 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304999 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005001 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5002 mb();
5003 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005005 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5006 DRIVER_NAME " (cmd)", host);
5007 if (ret)
5008 goto dml_exit;
5009
5010 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5011 DRIVER_NAME " (pio)", host);
5012 if (ret)
5013 goto irq_free;
5014
5015 /*
5016 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5017 * IRQ is un-necessarily being monitored by MPM (Modem power
5018 * management block) during idle-power collapse. The MPM will be
5019 * configured to monitor the DATA1 GPIO line with level-low trigger
5020 * and thus depending on the GPIO status, it prevents TCXO shutdown
5021 * during idle-power collapse.
5022 */
5023 disable_irq(core_irqres->start);
5024 host->sdcc_irq_disabled = 1;
5025
5026 if (plat->sdiowakeup_irq) {
5027 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5028 mmc_hostname(mmc));
5029 ret = request_irq(plat->sdiowakeup_irq,
5030 msmsdcc_platform_sdiowakeup_irq,
5031 IRQF_SHARED | IRQF_TRIGGER_LOW,
5032 DRIVER_NAME "sdiowakeup", host);
5033 if (ret) {
5034 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5035 plat->sdiowakeup_irq, ret);
5036 goto pio_irq_free;
5037 } else {
5038 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305039 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005040 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305041 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005042 }
5043 spin_unlock_irqrestore(&host->lock, flags);
5044 }
5045 }
5046
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305047 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5049 mmc_hostname(mmc));
5050 }
5051
5052 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5053 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005054 /*
5055 * Setup card detect change
5056 */
5057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005059 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005060 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005061 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005062 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005063
Krishna Konda941604a2012-01-10 17:46:34 -08005064 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 }
San Mehat9d2bd732009-09-22 16:44:22 -07005066
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005067 if (plat->status_irq) {
5068 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005069 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005070 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005071 DRIVER_NAME " (slot)",
5072 host);
5073 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074 pr_err("Unable to get slot IRQ %d (%d)\n",
5075 plat->status_irq, ret);
5076 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005077 }
5078 } else if (plat->register_status_notify) {
5079 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5080 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005081 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005082 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005083
5084 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005085
5086 ret = pm_runtime_set_active(&(pdev)->dev);
5087 if (ret < 0)
5088 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5089 __func__, ret);
5090 /*
5091 * There is no notion of suspend/resume for SD/MMC/SDIO
5092 * cards. So host can be suspended/resumed with out
5093 * worrying about its children.
5094 */
5095 pm_suspend_ignore_children(&(pdev)->dev, true);
5096
5097 /*
5098 * MMC/SD/SDIO bus suspend/resume operations are defined
5099 * only for the slots that will be used for non-removable
5100 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5101 * defined. Otherwise, they simply become card removal and
5102 * insertion events during suspend and resume respectively.
5103 * Hence, enable run-time PM only for slots for which bus
5104 * suspend/resume operations are defined.
5105 */
5106#ifdef CONFIG_MMC_UNSAFE_RESUME
5107 /*
5108 * If this capability is set, MMC core will enable/disable host
5109 * for every claim/release operation on a host. We use this
5110 * notification to increment/decrement runtime pm usage count.
5111 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005112 pm_runtime_enable(&(pdev)->dev);
5113#else
5114 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005115 pm_runtime_enable(&(pdev)->dev);
5116 }
5117#endif
5118 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5119 (unsigned long)host);
5120
San Mehat9d2bd732009-09-22 16:44:22 -07005121 mmc_add_host(mmc);
5122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005123#ifdef CONFIG_HAS_EARLYSUSPEND
5124 host->early_suspend.suspend = msmsdcc_early_suspend;
5125 host->early_suspend.resume = msmsdcc_late_resume;
5126 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5127 register_early_suspend(&host->early_suspend);
5128#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005129
Krishna Konda25786ec2011-07-25 16:21:36 -07005130 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5131 " dmacrcri %d\n", mmc_hostname(mmc),
5132 (unsigned long long)core_memres->start,
5133 (unsigned int) core_irqres->start,
5134 (unsigned int) plat->status_irq, host->dma.channel,
5135 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005136
5137 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5138 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5139 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5140 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5141 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5142 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5143 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5144 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5145 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5146 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5147 host->eject);
5148 pr_info("%s: Power save feature enable = %d\n",
5149 mmc_hostname(mmc), msmsdcc_pwrsave);
5150
Krishna Konda25786ec2011-07-25 16:21:36 -07005151 if (host->is_dma_mode && host->dma.channel != -1
5152 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005153 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005154 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005155 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005156 mmc_hostname(mmc), host->dma.cmd_busaddr,
5157 host->dma.cmdptr_busaddr);
5158 } else if (host->is_sps_mode) {
5159 pr_info("%s: SPS-BAM data transfer mode available\n",
5160 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005161 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005162 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005164#if defined(CONFIG_DEBUG_FS)
5165 msmsdcc_dbg_createhost(host);
5166#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305167
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305168 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5169 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5170 sysfs_attr_init(&host->max_bus_bw.attr);
5171 host->max_bus_bw.attr.name = "max_bus_bw";
5172 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5173 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305174 if (ret)
5175 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305176
5177 if (!plat->status_irq) {
5178 host->polling.show = show_polling;
5179 host->polling.store = store_polling;
5180 sysfs_attr_init(&host->polling.attr);
5181 host->polling.attr.name = "polling";
5182 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5183 ret = device_create_file(&pdev->dev, &host->polling);
5184 if (ret)
5185 goto remove_max_bus_bw_file;
5186 }
San Mehat9d2bd732009-09-22 16:44:22 -07005187 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005188
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305189 remove_max_bus_bw_file:
5190 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005191 platform_irq_free:
5192 del_timer_sync(&host->req_tout_timer);
5193 pm_runtime_disable(&(pdev)->dev);
5194 pm_runtime_set_suspended(&(pdev)->dev);
5195
5196 if (plat->status_irq)
5197 free_irq(plat->status_irq, host);
5198 sdiowakeup_irq_free:
5199 wake_lock_destroy(&host->sdio_suspend_wlock);
5200 if (plat->sdiowakeup_irq)
5201 free_irq(plat->sdiowakeup_irq, host);
5202 pio_irq_free:
5203 if (plat->sdiowakeup_irq)
5204 wake_lock_destroy(&host->sdio_wlock);
5205 free_irq(core_irqres->start, host);
5206 irq_free:
5207 free_irq(core_irqres->start, host);
5208 dml_exit:
5209 if (host->is_sps_mode)
5210 msmsdcc_dml_exit(host);
5211 sps_exit:
5212 if (host->is_sps_mode)
5213 msmsdcc_sps_exit(host);
5214 vreg_deinit:
5215 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005216 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005217 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305218 msmsdcc_msm_bus_unregister(host);
5219 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005220 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305221 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005222 clk_put:
5223 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005224 pclk_disable:
5225 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305226 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005227 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005228 if (!IS_ERR(host->pclk))
5229 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305230 if (!IS_ERR_OR_NULL(host->bus_clk))
5231 clk_disable_unprepare(host->bus_clk);
5232 bus_clk_put:
5233 if (!IS_ERR_OR_NULL(host->bus_clk))
5234 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005235 if (host->is_dma_mode) {
5236 if (host->dmares)
5237 dma_free_coherent(NULL,
5238 sizeof(struct msmsdcc_nc_dmadata),
5239 host->dma.nc, host->dma.nc_busaddr);
5240 }
5241 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305242 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005243 host_free:
5244 mmc_free_host(mmc);
5245 out:
5246 return ret;
5247}
5248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005249static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005250{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005251 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5252 struct mmc_platform_data *plat;
5253 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005255 if (!mmc)
5256 return -ENXIO;
5257
5258 if (pm_runtime_suspended(&(pdev)->dev))
5259 pm_runtime_resume(&(pdev)->dev);
5260
5261 host = mmc_priv(mmc);
5262
5263 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5264 plat = host->plat;
5265
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305266 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005267 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305268 device_remove_file(&pdev->dev, &host->polling);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005269
5270 del_timer_sync(&host->req_tout_timer);
5271 tasklet_kill(&host->dma_tlet);
5272 tasklet_kill(&host->sps.tlet);
5273 mmc_remove_host(mmc);
5274
5275 if (plat->status_irq)
5276 free_irq(plat->status_irq, host);
5277
5278 wake_lock_destroy(&host->sdio_suspend_wlock);
5279 if (plat->sdiowakeup_irq) {
5280 wake_lock_destroy(&host->sdio_wlock);
5281 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5282 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005283 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005284
5285 free_irq(host->core_irqres->start, host);
5286 free_irq(host->core_irqres->start, host);
5287
5288 clk_put(host->clk);
5289 if (!IS_ERR(host->pclk))
5290 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305291 if (!IS_ERR_OR_NULL(host->bus_clk))
5292 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005293
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005294 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305295 pm_qos_remove_request(&host->pm_qos_req_dma);
5296
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305297 if (host->msm_bus_vote.client_handle) {
5298 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5299 msmsdcc_msm_bus_unregister(host);
5300 }
5301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005302 msmsdcc_vreg_init(host, false);
5303
5304 if (host->is_dma_mode) {
5305 if (host->dmares)
5306 dma_free_coherent(NULL,
5307 sizeof(struct msmsdcc_nc_dmadata),
5308 host->dma.nc, host->dma.nc_busaddr);
5309 }
5310
5311 if (host->is_sps_mode) {
5312 msmsdcc_dml_exit(host);
5313 msmsdcc_sps_exit(host);
5314 }
5315
5316 iounmap(host->base);
5317 mmc_free_host(mmc);
5318
5319#ifdef CONFIG_HAS_EARLYSUSPEND
5320 unregister_early_suspend(&host->early_suspend);
5321#endif
5322 pm_runtime_disable(&(pdev)->dev);
5323 pm_runtime_set_suspended(&(pdev)->dev);
5324
5325 return 0;
5326}
5327
5328#ifdef CONFIG_MSM_SDIO_AL
5329int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5330{
5331 struct msmsdcc_host *host = mmc_priv(mmc);
5332 unsigned long flags;
5333
Asutosh Dasf5298c32012-04-03 14:51:47 +05305334 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005335 spin_lock_irqsave(&host->lock, flags);
5336 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5337 enable ? "En" : "Dis");
5338
5339 if (enable) {
5340 if (!host->sdcc_irq_disabled) {
5341 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305342 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005343 host->sdcc_irq_disabled = 1;
5344 }
5345
5346 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305347 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005348 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305349 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005350 host->clks_on = 0;
5351 }
5352
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305353 if (host->plat->sdio_lpm_gpio_setup &&
5354 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005355 spin_unlock_irqrestore(&host->lock, flags);
5356 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5357 spin_lock_irqsave(&host->lock, flags);
5358 host->sdio_gpio_lpm = 1;
5359 }
5360
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305361 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005362 msmsdcc_enable_irq_wake(host);
5363 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305364 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005365 }
5366 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305367 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005368 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305369 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005370 msmsdcc_disable_irq_wake(host);
5371 }
5372
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305373 if (host->plat->sdio_lpm_gpio_setup &&
5374 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005375 spin_unlock_irqrestore(&host->lock, flags);
5376 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5377 spin_lock_irqsave(&host->lock, flags);
5378 host->sdio_gpio_lpm = 0;
5379 }
5380
5381 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305382 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005383 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305384 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005385 host->clks_on = 1;
5386 }
5387
5388 if (host->sdcc_irq_disabled) {
5389 writel_relaxed(host->mci_irqenable,
5390 host->base + MMCIMASK0);
5391 mb();
5392 enable_irq(host->core_irqres->start);
5393 host->sdcc_irq_disabled = 0;
5394 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005395 }
5396 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305397 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005398 return 0;
5399}
5400#else
5401int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5402{
5403 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005404}
5405#endif
5406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005407#ifdef CONFIG_PM
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05305408#ifdef CONFIG_MMC_CLKGATE
5409static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
5410{
5411 struct mmc_host *mmc = host->mmc;
5412 unsigned long flags;
5413
5414 mmc_host_clk_hold(mmc);
5415 spin_lock_irqsave(&mmc->clk_lock, flags);
5416 mmc->clk_old = mmc->ios.clock;
5417 mmc->ios.clock = 0;
5418 mmc->clk_gated = true;
5419 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5420 mmc_set_ios(mmc);
5421 mmc_host_clk_release(mmc);
5422}
5423
5424static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
5425{
5426 struct mmc_host *mmc = host->mmc;
5427
5428 mmc_host_clk_hold(mmc);
5429 mmc->ios.clock = host->clk_rate;
5430 mmc_set_ios(mmc);
5431 mmc_host_clk_release(mmc);
5432}
5433#else
5434static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
5435{
5436 struct mmc_host *mmc = host->mmc;
5437
5438 mmc->ios.clock = 0;
5439 mmc_set_ios(mmc);
5440}
5441
5442static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
5443{
5444 struct mmc_host *mmc = host->mmc;
5445
5446 mmc->ios.clock = host->clk_rate;
5447 mmc_set_ios(mmc);
5448}
5449#endif
5450
San Mehat9d2bd732009-09-22 16:44:22 -07005451static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005452msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005453{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005454 struct mmc_host *mmc = dev_get_drvdata(dev);
5455 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005456 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305457 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005458
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305459 if (host->plat->is_sdio_al_client) {
5460 rc = 0;
5461 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07005462 }
San Mehat9d2bd732009-09-22 16:44:22 -07005463
Sahitya Tummala7661a452011-07-18 13:28:35 +05305464 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005465 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005466 host->sdcc_suspending = 1;
5467 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005469 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005470 * MMC core thinks that host is disabled by now since
5471 * runtime suspend is scheduled after msmsdcc_disable()
5472 * is called. Thus, MMC core will try to enable the host
5473 * while suspending it. This results in a synchronous
5474 * runtime resume request while in runtime suspending
5475 * context and hence inorder to complete this resume
5476 * requet, it will wait for suspend to be complete,
5477 * but runtime suspend also can not proceed further
5478 * until the host is resumed. Thus, it leads to a hang.
5479 * Hence, increase the pm usage count before suspending
5480 * the host so that any resume requests after this will
5481 * simple become pm usage counter increment operations.
5482 */
5483 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305484 /* If there is pending detect work abort runtime suspend */
5485 if (unlikely(work_busy(&mmc->detect.work)))
5486 rc = -EAGAIN;
5487 else
5488 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005489 pm_runtime_put_noidle(dev);
5490
5491 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305492 spin_lock_irqsave(&host->lock, flags);
5493 host->sdcc_suspended = true;
5494 spin_unlock_irqrestore(&host->lock, flags);
5495 if (mmc->card && mmc_card_sdio(mmc->card) &&
5496 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005497 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305498 * If SDIO function driver doesn't want
5499 * to power off the card, atleast turn off
5500 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005501 */
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05305502 msmsdcc_gate_clock(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005503 }
5504 }
5505 host->sdcc_suspending = 0;
5506 mmc->suspend_task = NULL;
5507 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5508 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005509 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305510 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305511out:
5512 /* set bus bandwidth to 0 immediately */
5513 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005514 return rc;
5515}
5516
5517static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005518msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005519{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005520 struct mmc_host *mmc = dev_get_drvdata(dev);
5521 struct msmsdcc_host *host = mmc_priv(mmc);
5522 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005524 if (host->plat->is_sdio_al_client)
5525 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005526
Sahitya Tummala7661a452011-07-18 13:28:35 +05305527 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005528 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305529 if (mmc->card && mmc_card_sdio(mmc->card) &&
5530 mmc_card_keep_power(mmc)) {
Sujit Reddy Thumma458ab8c2012-06-13 08:56:32 +05305531 msmsdcc_ungate_clock(host);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305532 }
San Mehat9d2bd732009-09-22 16:44:22 -07005533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005534 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005536 /*
5537 * FIXME: Clearing of flags must be handled in clients
5538 * resume handler.
5539 */
5540 spin_lock_irqsave(&host->lock, flags);
5541 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305542 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005543 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07005544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005545 /*
5546 * After resuming the host wait for sometime so that
5547 * the SDIO work will be processed.
5548 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305549 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305550 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005551 host->plat->sdiowakeup_irq) &&
5552 wake_lock_active(&host->sdio_wlock))
5553 wake_lock_timeout(&host->sdio_wlock, 1);
5554 }
5555
5556 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005557 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305558 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005559 return 0;
5560}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005561
5562static int msmsdcc_runtime_idle(struct device *dev)
5563{
5564 struct mmc_host *mmc = dev_get_drvdata(dev);
5565 struct msmsdcc_host *host = mmc_priv(mmc);
5566
5567 if (host->plat->is_sdio_al_client)
5568 return 0;
5569
5570 /* Idle timeout is not configurable for now */
5571 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5572
5573 return -EAGAIN;
5574}
5575
5576static int msmsdcc_pm_suspend(struct device *dev)
5577{
5578 struct mmc_host *mmc = dev_get_drvdata(dev);
5579 struct msmsdcc_host *host = mmc_priv(mmc);
5580 int rc = 0;
5581
5582 if (host->plat->is_sdio_al_client)
5583 return 0;
5584
5585
5586 if (host->plat->status_irq)
5587 disable_irq(host->plat->status_irq);
5588
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005589 if (!pm_runtime_suspended(dev))
5590 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005591
5592 return rc;
5593}
5594
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305595static int msmsdcc_suspend_noirq(struct device *dev)
5596{
5597 struct mmc_host *mmc = dev_get_drvdata(dev);
5598 struct msmsdcc_host *host = mmc_priv(mmc);
5599 int rc = 0;
5600
5601 /*
5602 * After platform suspend there may be active request
5603 * which might have enabled clocks. For example, in SDIO
5604 * case, ksdioirq thread might have scheduled after sdcc
5605 * suspend but before system freeze. In that case abort
5606 * suspend and retry instead of keeping the clocks on
5607 * during suspend and not allowing TCXO.
5608 */
5609
Asutosh Dasf5298c32012-04-03 14:51:47 +05305610 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305611 pr_warn("%s: clocks are on after suspend, aborting system "
5612 "suspend\n", mmc_hostname(mmc));
5613 rc = -EAGAIN;
5614 }
5615
5616 return rc;
5617}
5618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005619static int msmsdcc_pm_resume(struct device *dev)
5620{
5621 struct mmc_host *mmc = dev_get_drvdata(dev);
5622 struct msmsdcc_host *host = mmc_priv(mmc);
5623 int rc = 0;
5624
5625 if (host->plat->is_sdio_al_client)
5626 return 0;
5627
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005628 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305629 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005630 else
5631 host->pending_resume = true;
5632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005633 if (host->plat->status_irq) {
5634 msmsdcc_check_status((unsigned long)host);
5635 enable_irq(host->plat->status_irq);
5636 }
5637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005638 return rc;
5639}
5640
Daniel Walker08ecfde2010-06-23 12:32:20 -07005641#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005642static int msmsdcc_runtime_suspend(struct device *dev)
5643{
5644 return 0;
5645}
5646static int msmsdcc_runtime_idle(struct device *dev)
5647{
5648 return 0;
5649}
5650static int msmsdcc_pm_suspend(struct device *dev)
5651{
5652 return 0;
5653}
5654static int msmsdcc_pm_resume(struct device *dev)
5655{
5656 return 0;
5657}
5658static int msmsdcc_suspend_noirq(struct device *dev)
5659{
5660 return 0;
5661}
5662static int msmsdcc_runtime_resume(struct device *dev)
5663{
5664 return 0;
5665}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005666#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005668static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5669 .runtime_suspend = msmsdcc_runtime_suspend,
5670 .runtime_resume = msmsdcc_runtime_resume,
5671 .runtime_idle = msmsdcc_runtime_idle,
5672 .suspend = msmsdcc_pm_suspend,
5673 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305674 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005675};
5676
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305677static const struct of_device_id msmsdcc_dt_match[] = {
5678 {.compatible = "qcom,msm-sdcc"},
5679
5680};
5681MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5682
San Mehat9d2bd732009-09-22 16:44:22 -07005683static struct platform_driver msmsdcc_driver = {
5684 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005685 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005686 .driver = {
5687 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005688 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305689 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005690 },
5691};
5692
5693static int __init msmsdcc_init(void)
5694{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005695#if defined(CONFIG_DEBUG_FS)
5696 int ret = 0;
5697 ret = msmsdcc_dbg_init();
5698 if (ret) {
5699 pr_err("Failed to create debug fs dir \n");
5700 return ret;
5701 }
5702#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005703 return platform_driver_register(&msmsdcc_driver);
5704}
San Mehat9d2bd732009-09-22 16:44:22 -07005705
San Mehat9d2bd732009-09-22 16:44:22 -07005706static void __exit msmsdcc_exit(void)
5707{
5708 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005709
5710#if defined(CONFIG_DEBUG_FS)
5711 debugfs_remove(debugfs_file);
5712 debugfs_remove(debugfs_dir);
5713#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005714}
5715
5716module_init(msmsdcc_init);
5717module_exit(msmsdcc_exit);
5718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005719MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005720MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005721
5722#if defined(CONFIG_DEBUG_FS)
5723
5724static int
5725msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5726{
5727 file->private_data = inode->i_private;
5728 return 0;
5729}
5730
5731static ssize_t
5732msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5733 size_t count, loff_t *ppos)
5734{
5735 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005736 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005737 int max, i;
5738
5739 i = 0;
5740 max = sizeof(buf) - 1;
5741
5742 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5743 host->curr.cmd, host->curr.data);
5744 if (host->curr.cmd) {
5745 struct mmc_command *cmd = host->curr.cmd;
5746
5747 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5748 cmd->opcode, cmd->arg, cmd->flags);
5749 }
5750 if (host->curr.data) {
5751 struct mmc_data *data = host->curr.data;
5752 i += scnprintf(buf + i, max - i,
5753 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5754 data->timeout_ns, data->timeout_clks,
5755 data->blksz, data->blocks, data->error,
5756 data->flags);
5757 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5758 host->curr.xfer_size, host->curr.xfer_remain,
5759 host->curr.data_xfered, host->dma.sg);
5760 }
5761
5762 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5763}
5764
5765static const struct file_operations msmsdcc_dbg_state_ops = {
5766 .read = msmsdcc_dbg_state_read,
5767 .open = msmsdcc_dbg_state_open,
5768};
5769
5770static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5771{
5772 if (debugfs_dir) {
5773 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5774 0644, debugfs_dir, host,
5775 &msmsdcc_dbg_state_ops);
5776 }
5777}
5778
5779static int __init msmsdcc_dbg_init(void)
5780{
5781 int err;
5782
5783 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5784 if (IS_ERR(debugfs_dir)) {
5785 err = PTR_ERR(debugfs_dir);
5786 debugfs_dir = NULL;
5787 return err;
5788 }
5789
5790 return 0;
5791}
5792#endif