blob: e84d87b3599e46914531f824621331c963b43c68 [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) {
2880 spin_unlock_irqrestore(&host->lock, flags);
2881 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302883 host->sdcc_irq_disabled = 1;
2884 }
San Mehatd0719e52009-12-03 10:58:54 -08002885 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002886
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302887 pwr = msmsdcc_setup_pwr(host, ios);
2888
2889 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002890 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302892 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002893 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302894 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302896 writel_relaxed(host->mci_irqenable,
2897 host->base + MMCIMASK0);
2898 mb();
2899 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002900 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901
2902 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2903 /*
2904 * For DDR50 mode, controller needs clock rate to be
2905 * double than what is required on the SD card CLK pin.
2906 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302907 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002908 /*
2909 * Make sure that we don't double the clock if
2910 * doubled clock rate is already set
2911 */
2912 if (!host->ddr_doubled_clk_rate ||
2913 (host->ddr_doubled_clk_rate &&
2914 (host->ddr_doubled_clk_rate != ios->clock))) {
2915 host->ddr_doubled_clk_rate =
2916 msmsdcc_get_sup_clk_rate(
2917 host, (ios->clock * 2));
2918 clock = host->ddr_doubled_clk_rate;
2919 }
2920 } else {
2921 host->ddr_doubled_clk_rate = 0;
2922 }
2923
2924 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302925 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302927 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302929 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930 mmc_hostname(mmc), clock);
2931 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302932 host->reg_write_delay =
2933 (1 + ((3 * USEC_PER_SEC) /
2934 (host->clk_rate ? host->clk_rate :
2935 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 }
2937 /*
2938 * give atleast 2 MCLK cycles delay for clocks
2939 * and SDCC core to stabilize
2940 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302941 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002943 clk |= MCI_CLK_ENABLE;
2944 }
2945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002946 if (ios->bus_width == MMC_BUS_WIDTH_8)
2947 clk |= MCI_CLK_WIDEBUS_8;
2948 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2949 clk |= MCI_CLK_WIDEBUS_4;
2950 else
2951 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002953 if (msmsdcc_is_pwrsave(host))
2954 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002956 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958 host->tuning_needed = 0;
2959 /*
2960 * Select the controller timing mode according
2961 * to current bus speed mode
2962 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302963 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2964 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 clk |= (4 << 14);
2966 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302967 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002968 clk |= (3 << 14);
2969 } else {
2970 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07002971 }
2972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2974 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07002975
Subhash Jadavani00083572012-02-15 16:18:01 +05302976 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2977 if (!ios->vdd)
2978 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07002979
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980 if (host->io_pad_pwr_switch)
2981 clk |= IO_PAD_PWR_SWITCH;
2982
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302983 /* Don't write into registers if clocks are disabled */
2984 if (host->clks_on) {
2985 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2986 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302987 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302989 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2990 host->pwr = pwr;
2991 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302992 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 }
San Mehat9d2bd732009-09-22 16:44:22 -07002994 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002995
2996 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302997 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302998 spin_unlock_irqrestore(&host->lock, flags);
2999 /*
3000 * May get a wake-up interrupt the instant we disable the
3001 * clocks. This would disable the wake-up interrupt.
3002 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303004 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 host->clks_on = 0;
3006 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303007
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303008 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303009 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303010 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303011
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303012 /* Let interrupts be disabled if the host is powered off */
3013 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3014 enable_irq(host->core_irqres->start);
3015 host->sdcc_irq_disabled = 0;
3016 }
3017
San Mehat4adbbcc2009-11-08 13:00:37 -08003018 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303019 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003020}
3021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3023{
3024 struct msmsdcc_host *host = mmc_priv(mmc);
3025 u32 clk;
3026
3027 clk = readl_relaxed(host->base + MMCICLOCK);
3028 pr_debug("Changing to pwr_save=%d", pwrsave);
3029 if (pwrsave && msmsdcc_is_pwrsave(host))
3030 clk |= MCI_CLK_PWRSAVE;
3031 else
3032 clk &= ~MCI_CLK_PWRSAVE;
3033 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303034 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035
3036 return 0;
3037}
3038
3039static int msmsdcc_get_ro(struct mmc_host *mmc)
3040{
3041 int status = -ENOSYS;
3042 struct msmsdcc_host *host = mmc_priv(mmc);
3043
3044 if (host->plat->wpswitch) {
3045 status = host->plat->wpswitch(mmc_dev(mmc));
3046 } else if (host->plat->wpswitch_gpio) {
3047 status = gpio_request(host->plat->wpswitch_gpio,
3048 "SD_WP_Switch");
3049 if (status) {
3050 pr_err("%s: %s: Failed to request GPIO %d\n",
3051 mmc_hostname(mmc), __func__,
3052 host->plat->wpswitch_gpio);
3053 } else {
3054 status = gpio_direction_input(
3055 host->plat->wpswitch_gpio);
3056 if (!status) {
3057 /*
3058 * Wait for atleast 300ms as debounce
3059 * time for GPIO input to stabilize.
3060 */
3061 msleep(300);
3062 status = gpio_get_value_cansleep(
3063 host->plat->wpswitch_gpio);
3064 status ^= !host->plat->wpswitch_polarity;
3065 }
3066 gpio_free(host->plat->wpswitch_gpio);
3067 }
3068 }
3069
3070 if (status < 0)
3071 status = -ENOSYS;
3072 pr_debug("%s: Card read-only status %d\n", __func__, status);
3073
3074 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003075}
3076
3077static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3078{
3079 struct msmsdcc_host *host = mmc_priv(mmc);
3080 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303082 /*
3083 * We may come here with clocks turned off in that case don't
3084 * attempt to write into MASK0 register. While turning on the
3085 * clocks mci_irqenable will be written to MASK0 register.
3086 */
San Mehat9d2bd732009-09-22 16:44:22 -07003087
3088 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003090 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303091 if (host->clks_on) {
3092 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003093 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303094 mb();
3095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096 } else {
3097 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303098 if (host->clks_on) {
3099 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303101 mb();
3102 }
San Mehat9d2bd732009-09-22 16:44:22 -07003103 }
3104 spin_unlock_irqrestore(&host->lock, flags);
3105}
3106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303108static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003109{
subhashj245831e2012-04-30 18:46:17 +05303110 struct device *dev = mmc_dev(host->mmc);
3111
3112 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3113 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3114 " request_pending=%d, request=%d\n",
3115 mmc_hostname(host->mmc), dev->power.runtime_status,
3116 atomic_read(&dev->power.usage_count),
3117 dev->power.is_suspended, dev->power.disable_depth,
3118 dev->power.runtime_error, dev->power.request_pending,
3119 dev->power.request);
3120}
3121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122static int msmsdcc_enable(struct mmc_host *mmc)
3123{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003124 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003126 struct msmsdcc_host *host = mmc_priv(mmc);
3127
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303128 msmsdcc_pm_qos_update_latency(host, 1);
3129
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003130 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303131 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003132
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003133 if (host->sdcc_suspended && host->pending_resume &&
3134 !pm_runtime_suspended(dev)) {
3135 host->pending_resume = false;
3136 pm_runtime_get_noresume(dev);
3137 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303138 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003139 }
3140
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303141 if (dev->power.runtime_status == RPM_SUSPENDING) {
3142 if (mmc->suspend_task == current) {
3143 pm_runtime_get_noresume(dev);
3144 goto out;
3145 }
3146 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003147
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303148 rc = pm_runtime_get_sync(dev);
3149
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303150skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303151 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3153 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303154 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303155 return rc;
3156 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303157out:
3158 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303159 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003160}
3161
Steve Mucklef132c6c2012-06-06 18:30:57 -07003162static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163{
3164 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303165 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003166
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303167 msmsdcc_pm_qos_update_latency(host, 0);
3168
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303169 if (mmc->card && mmc_card_sdio(mmc->card)) {
3170 rc = 0;
3171 goto out;
3172 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303173
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303174 if (host->plat->disable_runtime_pm)
3175 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003176
3177 rc = pm_runtime_put_sync(mmc->parent);
3178
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003179 /*
3180 * Ignore -EAGAIN as that is not fatal, it means that
3181 * either runtime usage count is non-zero or the runtime
3182 * pm itself is disabled or not in proper state to process
3183 * idle notification.
3184 */
3185 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3187 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303188 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003189 return rc;
3190 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303191
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303192out:
3193 msmsdcc_msm_bus_queue_work(host);
3194 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003195}
3196#else
subhashj245831e2012-04-30 18:46:17 +05303197static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3198
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303199static int msmsdcc_enable(struct mmc_host *mmc)
3200{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003201 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303202 struct msmsdcc_host *host = mmc_priv(mmc);
3203 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303204 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303205
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303206 msmsdcc_pm_qos_update_latency(host, 1);
3207
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303208 if (mmc->card && mmc_card_sdio(mmc->card)) {
3209 rc = 0;
3210 goto out;
3211 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003212
3213 if (host->sdcc_suspended && host->pending_resume) {
3214 host->pending_resume = false;
3215 rc = msmsdcc_runtime_resume(dev);
3216 goto out;
3217 }
3218
Asutosh Dasf5298c32012-04-03 14:51:47 +05303219 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303220 spin_lock_irqsave(&host->lock, flags);
3221 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303222 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303223 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303224 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303225 host->clks_on = 1;
3226 }
3227 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303228 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303229
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003230out:
3231 if (rc < 0) {
3232 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3233 __func__, rc);
3234 return rc;
3235 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303236 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303237 return 0;
3238}
3239
Steve Mucklef132c6c2012-06-06 18:30:57 -07003240static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303241{
3242 struct msmsdcc_host *host = mmc_priv(mmc);
3243 unsigned long flags;
3244
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303245 msmsdcc_pm_qos_update_latency(host, 0);
3246
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303247 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303248 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303249
Asutosh Dasf5298c32012-04-03 14:51:47 +05303250 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303251 spin_lock_irqsave(&host->lock, flags);
3252 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303253 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303254 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303255 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303256 host->clks_on = 0;
3257 }
3258 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303259 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303260
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303261out:
3262 msmsdcc_msm_bus_queue_work(host);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303263 return 0;
3264}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003265#endif
3266
Subhash Jadavani937c7502012-06-01 15:34:46 +05303267static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3268 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269{
3270 struct msmsdcc_host *host = mmc_priv(mmc);
3271 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303272 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273
Subhash Jadavani00083572012-02-15 16:18:01 +05303274 spin_lock_irqsave(&host->lock, flags);
3275 host->io_pad_pwr_switch = 0;
3276 spin_unlock_irqrestore(&host->lock, flags);
3277
Subhash Jadavani937c7502012-06-01 15:34:46 +05303278 switch (ios->signal_voltage) {
3279 case MMC_SIGNAL_VOLTAGE_330:
3280 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3281 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303282 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303283 case MMC_SIGNAL_VOLTAGE_180:
3284 break;
3285 case MMC_SIGNAL_VOLTAGE_120:
3286 /*
3287 * For eMMC cards, VDD_IO voltage range must be changed
3288 * only if it operates in HS200 SDR 1.2V mode or in
3289 * DDR 1.2V mode.
3290 */
3291 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003292 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303293 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003294 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303295 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003296 goto out;
3297 }
San Mehat9d2bd732009-09-22 16:44:22 -07003298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003299 /*
3300 * If we are here means voltage switch from high voltage to
3301 * low voltage is required
3302 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303303 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003304
3305 /*
3306 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3307 * register until they become all zeros.
3308 */
3309 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303310 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3312 mmc_hostname(mmc), __func__);
3313 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003314 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003315
3316 /* Stop SD CLK output. */
3317 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3318 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303319 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003320 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003321
3322 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303323 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3324 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303326 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303327 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003328 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003329
3330 spin_lock_irqsave(&host->lock, flags);
3331 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3332 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303333 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 host->io_pad_pwr_switch = 1;
3335 spin_unlock_irqrestore(&host->lock, flags);
3336
3337 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3338 usleep_range(5000, 5500);
3339
3340 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303341 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003342 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3343 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303344 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345 spin_unlock_irqrestore(&host->lock, flags);
3346
3347 /*
3348 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3349 * don't become all ones within 1 ms then a Voltage Switch
3350 * sequence has failed and a power cycle to the card is required.
3351 * Otherwise Voltage Switch sequence is completed successfully.
3352 */
3353 usleep_range(1000, 1500);
3354
3355 spin_lock_irqsave(&host->lock, flags);
3356 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3357 != (0xF << 1)) {
3358 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3359 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303360 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 goto out_unlock;
3362 }
3363
3364out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303365 /* Enable PWRSAVE */
3366 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3367 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303368 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 spin_unlock_irqrestore(&host->lock, flags);
3370out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303371 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372}
3373
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303374static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377
3378 /* Program the MCLK value to MCLK_FREQ bit field */
3379 if (host->clk_rate <= 112000000)
3380 mclk_freq = 0;
3381 else if (host->clk_rate <= 125000000)
3382 mclk_freq = 1;
3383 else if (host->clk_rate <= 137000000)
3384 mclk_freq = 2;
3385 else if (host->clk_rate <= 150000000)
3386 mclk_freq = 3;
3387 else if (host->clk_rate <= 162000000)
3388 mclk_freq = 4;
3389 else if (host->clk_rate <= 175000000)
3390 mclk_freq = 5;
3391 else if (host->clk_rate <= 187000000)
3392 mclk_freq = 6;
3393 else if (host->clk_rate <= 200000000)
3394 mclk_freq = 7;
3395
3396 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3397 & ~(7 << 24)) | (mclk_freq << 24)),
3398 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399}
3400
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303401/* Initialize the DLL (Programmable Delay Line ) */
3402static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003404 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303405 unsigned long flags;
3406 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003407
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303408 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409 /*
3410 * Make sure that clock is always enabled when DLL
3411 * tuning is in progress. Keeping PWRSAVE ON may
3412 * turn off the clock. So let's disable the PWRSAVE
3413 * here and re-enable it once tuning is completed.
3414 */
3415 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3416 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303417 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303418
3419 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3420 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3421 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3422
3423 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3424 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3425 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3426
3427 msmsdcc_cm_sdc4_dll_set_freq(host);
3428
3429 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3430 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3431 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3432
3433 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3434 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3435 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3436
3437 /* Set DLL_EN bit to 1. */
3438 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3439 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3440
3441 /* Set CK_OUT_EN bit to 1. */
3442 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3443 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3444
3445 wait_cnt = 50;
3446 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3447 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3448 /* max. wait for 50us sec for LOCK bit to be set */
3449 if (--wait_cnt == 0) {
3450 pr_err("%s: %s: DLL failed to LOCK\n",
3451 mmc_hostname(host->mmc), __func__);
3452 rc = -ETIMEDOUT;
3453 goto out;
3454 }
3455 /* wait for 1us before polling again */
3456 udelay(1);
3457 }
3458
3459out:
3460 /* re-enable PWRSAVE */
3461 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3462 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303463 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303464 spin_unlock_irqrestore(&host->lock, flags);
3465
3466 return rc;
3467}
3468
3469static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3470 u8 poll)
3471{
3472 int rc = 0;
3473 u32 wait_cnt = 50;
3474 u8 ck_out_en = 0;
3475
3476 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3477 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3478 MCI_CK_OUT_EN);
3479
3480 while (ck_out_en != poll) {
3481 if (--wait_cnt == 0) {
3482 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3483 mmc_hostname(host->mmc), __func__, poll);
3484 rc = -ETIMEDOUT;
3485 goto out;
3486 }
3487 udelay(1);
3488
3489 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3490 MCI_CK_OUT_EN);
3491 }
3492out:
3493 return rc;
3494}
3495
3496/*
3497 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3498 * calibration sequence. This function should be called before
3499 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3500 * commands (CMD17/CMD18).
3501 *
3502 * This function gets called when host spinlock acquired.
3503 */
3504static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3505{
3506 int rc = 0;
3507 u32 config;
3508
3509 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3510 config |= MCI_CDR_EN;
3511 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3512 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3513
3514 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3515 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3516 if (rc)
3517 goto err_out;
3518
3519 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3520 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3521 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3522
3523 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3524 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3525 if (rc)
3526 goto err_out;
3527
3528 goto out;
3529
3530err_out:
3531 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3532out:
3533 return rc;
3534}
3535
3536static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3537 u8 phase)
3538{
3539 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303540 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3541 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3542 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303543 unsigned long flags;
3544 u32 config;
3545
3546 spin_lock_irqsave(&host->lock, flags);
3547
3548 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3549 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3550 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3551 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3552
3553 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3554 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3555 if (rc)
3556 goto err_out;
3557
3558 /*
3559 * Write the selected DLL clock output phase (0 ... 15)
3560 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3561 */
3562 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3563 & ~(0xF << 20))
3564 | (grey_coded_phase_table[phase] << 20)),
3565 host->base + MCI_DLL_CONFIG);
3566
3567 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3568 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3569 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3570
3571 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3572 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3573 if (rc)
3574 goto err_out;
3575
3576 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3577 config |= MCI_CDR_EN;
3578 config &= ~MCI_CDR_EXT_EN;
3579 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3580 goto out;
3581
3582err_out:
3583 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3584 mmc_hostname(host->mmc), __func__, phase);
3585out:
3586 spin_unlock_irqrestore(&host->lock, flags);
3587 return rc;
3588}
3589
3590/*
3591 * Find out the greatest range of consecuitive selected
3592 * DLL clock output phases that can be used as sampling
3593 * setting for SD3.0 UHS-I card read operation (in SDR104
3594 * timing mode) or for eMMC4.5 card read operation (in HS200
3595 * timing mode).
3596 * Select the 3/4 of the range and configure the DLL with the
3597 * selected DLL clock output phase.
3598*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303599static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303600 u8 *phase_table, u8 total_phases)
3601{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303602 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303603 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303604 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3605 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303606 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303607 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3608 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303609
Subhash Jadavani6159c622012-03-15 19:05:55 +05303610 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303611 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3612 mmc_hostname(host->mmc), __func__, total_phases);
3613 return -EINVAL;
3614 }
3615
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303616 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303617 ranges[row_index][col_index] = phase_table[cnt];
3618 phases_per_row[row_index] += 1;
3619 col_index++;
3620
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303621 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303622 continue;
3623 /* check if next phase in phase_table is consecutive or not */
3624 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3625 row_index++;
3626 col_index = 0;
3627 }
3628 }
3629
Subhash Jadavani6159c622012-03-15 19:05:55 +05303630 if (row_index >= MAX_PHASES)
3631 return -EINVAL;
3632
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303633 /* Check if phase-0 is present in first valid window? */
3634 if (!ranges[0][0]) {
3635 phase_0_found = true;
3636 phase_0_raw_index = 0;
3637 /* Check if cycle exist between 2 valid windows */
3638 for (cnt = 1; cnt <= row_index; cnt++) {
3639 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303640 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303641 if (ranges[cnt][i] == 15) {
3642 phase_15_found = true;
3643 phase_15_raw_index = cnt;
3644 break;
3645 }
3646 }
3647 }
3648 }
3649 }
3650
3651 /* If 2 valid windows form cycle then merge them as single window */
3652 if (phase_0_found && phase_15_found) {
3653 /* number of phases in raw where phase 0 is present */
3654 u8 phases_0 = phases_per_row[phase_0_raw_index];
3655 /* number of phases in raw where phase 15 is present */
3656 u8 phases_15 = phases_per_row[phase_15_raw_index];
3657
Subhash Jadavani6159c622012-03-15 19:05:55 +05303658 if (phases_0 + phases_15 >= MAX_PHASES)
3659 /*
3660 * If there are more than 1 phase windows then total
3661 * number of phases in both the windows should not be
3662 * more than or equal to MAX_PHASES.
3663 */
3664 return -EINVAL;
3665
3666 /* Merge 2 cyclic windows */
3667 i = phases_15;
3668 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303669 ranges[phase_15_raw_index][i] =
3670 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303671 if (++i >= MAX_PHASES)
3672 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303673 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303674
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303675 phases_per_row[phase_0_raw_index] = 0;
3676 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3677 }
3678
3679 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303680 if (phases_per_row[cnt] > curr_max) {
3681 curr_max = phases_per_row[cnt];
3682 selected_row_index = cnt;
3683 }
3684 }
3685
Subhash Jadavani6159c622012-03-15 19:05:55 +05303686 i = ((curr_max * 3) / 4);
3687 if (i)
3688 i--;
3689
Subhash Jadavani34187042012-03-02 10:59:49 +05303690 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303691
Subhash Jadavani6159c622012-03-15 19:05:55 +05303692 if (ret >= MAX_PHASES) {
3693 ret = -EINVAL;
3694 pr_err("%s: %s: invalid phase selected=%d\n",
3695 mmc_hostname(host->mmc), __func__, ret);
3696 }
3697
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303698 return ret;
3699}
3700
Girish K Sa3f41692012-02-29 12:00:09 +05303701static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303702{
3703 int rc = 0;
3704 struct msmsdcc_host *host = mmc_priv(mmc);
3705 unsigned long flags;
3706 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303707 const u32 *tuning_block_pattern = tuning_block_64;
3708 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303709
3710 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3711
3712 /* Tuning is only required for SDR104 modes */
3713 if (!host->tuning_needed) {
3714 rc = 0;
3715 goto exit;
3716 }
3717
3718 spin_lock_irqsave(&host->lock, flags);
3719 WARN(!host->pwr, "SDCC power is turned off\n");
3720 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3721 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3722
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303723 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303724 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3725 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3726 tuning_block_pattern = tuning_block_128;
3727 size = sizeof(tuning_block_128);
3728 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303729 spin_unlock_irqrestore(&host->lock, flags);
3730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003731 /* first of all reset the tuning block */
3732 rc = msmsdcc_init_cm_sdc4_dll(host);
3733 if (rc)
3734 goto out;
3735
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303736 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737 if (!data_buf) {
3738 rc = -ENOMEM;
3739 goto out;
3740 }
3741
3742 phase = 0;
3743 do {
3744 struct mmc_command cmd = {0};
3745 struct mmc_data data = {0};
3746 struct mmc_request mrq = {
3747 .cmd = &cmd,
3748 .data = &data
3749 };
3750 struct scatterlist sg;
3751
3752 /* set the phase in delay line hw block */
3753 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3754 if (rc)
3755 goto kfree;
3756
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303757 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003758 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3759
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303760 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761 data.blocks = 1;
3762 data.flags = MMC_DATA_READ;
3763 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3764
3765 data.sg = &sg;
3766 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303767 sg_init_one(&sg, data_buf, size);
3768 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 mmc_wait_for_req(mmc, &mrq);
3770
3771 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303772 !memcmp(data_buf, tuning_block_pattern, size)) {
3773 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003774 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303775 pr_debug("%s: %s: found good phase = %d\n",
3776 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003777 }
3778 } while (++phase < 16);
3779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303781 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303782 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303783 if (rc < 0)
3784 goto kfree;
3785 else
3786 phase = (u8)rc;
3787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003788 /*
3789 * Finally set the selected phase in delay
3790 * line hw block.
3791 */
3792 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3793 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303794 goto kfree;
3795 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3796 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003797 } else {
3798 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303799 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003800 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303801 msmsdcc_dump_sdcc_state(host);
3802 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003804
3805kfree:
3806 kfree(data_buf);
3807out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303808 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303809 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303810 spin_unlock_irqrestore(&host->lock, flags);
3811exit:
3812 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003814}
3815
San Mehat9d2bd732009-09-22 16:44:22 -07003816static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003817 .enable = msmsdcc_enable,
3818 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303819 .pre_req = msmsdcc_pre_req,
3820 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003821 .request = msmsdcc_request,
3822 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003823 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003824 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303825 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003826 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003827};
3828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003829static unsigned int
3830msmsdcc_slot_status(struct msmsdcc_host *host)
3831{
3832 int status;
3833 unsigned int gpio_no = host->plat->status_gpio;
3834
3835 status = gpio_request(gpio_no, "SD_HW_Detect");
3836 if (status) {
3837 pr_err("%s: %s: Failed to request GPIO %d\n",
3838 mmc_hostname(host->mmc), __func__, gpio_no);
3839 } else {
3840 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003841 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003842 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003843 if (host->plat->is_status_gpio_active_low)
3844 status = !status;
3845 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846 gpio_free(gpio_no);
3847 }
3848 return status;
3849}
3850
San Mehat9d2bd732009-09-22 16:44:22 -07003851static void
3852msmsdcc_check_status(unsigned long data)
3853{
3854 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3855 unsigned int status;
3856
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003857 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003858 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003860 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003861 status = msmsdcc_slot_status(host);
3862
Krishna Konda941604a2012-01-10 17:46:34 -08003863 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003865 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003866 if (host->plat->status)
3867 pr_info("%s: Slot status change detected "
3868 "(%d -> %d)\n",
3869 mmc_hostname(host->mmc),
3870 host->oldstat, status);
3871 else if (host->plat->is_status_gpio_active_low)
3872 pr_info("%s: Slot status change detected "
3873 "(%d -> %d) and the card detect GPIO"
3874 " is ACTIVE_LOW\n",
3875 mmc_hostname(host->mmc),
3876 host->oldstat, status);
3877 else
3878 pr_info("%s: Slot status change detected "
3879 "(%d -> %d) and the card detect GPIO"
3880 " is ACTIVE_HIGH\n",
3881 mmc_hostname(host->mmc),
3882 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003883 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884 }
3885 host->oldstat = status;
3886 } else {
3887 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003888 }
San Mehat9d2bd732009-09-22 16:44:22 -07003889}
3890
3891static irqreturn_t
3892msmsdcc_platform_status_irq(int irq, void *dev_id)
3893{
3894 struct msmsdcc_host *host = dev_id;
3895
Girish K Sa3c76eb2011-10-11 11:44:09 +05303896 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003897 msmsdcc_check_status((unsigned long) host);
3898 return IRQ_HANDLED;
3899}
3900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003901static irqreturn_t
3902msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3903{
3904 struct msmsdcc_host *host = dev_id;
3905
3906 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3907 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303908 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303910 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003911 wake_lock(&host->sdio_wlock);
3912 msmsdcc_disable_irq_wake(host);
3913 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303914 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 }
3916 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303918 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303919 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303920 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921 }
3922 spin_unlock(&host->lock);
3923
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303924out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003925 return IRQ_HANDLED;
3926}
3927
San Mehat9d2bd732009-09-22 16:44:22 -07003928static void
3929msmsdcc_status_notify_cb(int card_present, void *dev_id)
3930{
3931 struct msmsdcc_host *host = dev_id;
3932
Girish K Sa3c76eb2011-10-11 11:44:09 +05303933 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003934 card_present);
3935 msmsdcc_check_status((unsigned long) host);
3936}
3937
San Mehat9d2bd732009-09-22 16:44:22 -07003938static int
3939msmsdcc_init_dma(struct msmsdcc_host *host)
3940{
3941 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3942 host->dma.host = host;
3943 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003944 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003945
3946 if (!host->dmares)
3947 return -ENODEV;
3948
3949 host->dma.nc = dma_alloc_coherent(NULL,
3950 sizeof(struct msmsdcc_nc_dmadata),
3951 &host->dma.nc_busaddr,
3952 GFP_KERNEL);
3953 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003954 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003955 return -ENOMEM;
3956 }
3957 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3958 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3959 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3960 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3961 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003962 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003963
3964 return 0;
3965}
3966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003967#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3968/**
3969 * Allocate and Connect a SDCC peripheral's SPS endpoint
3970 *
3971 * This function allocates endpoint context and
3972 * connect it with memory endpoint by calling
3973 * appropriate SPS driver APIs.
3974 *
3975 * Also registers a SPS callback function with
3976 * SPS driver
3977 *
3978 * This function should only be called once typically
3979 * during driver probe.
3980 *
3981 * @host - Pointer to sdcc host structure
3982 * @ep - Pointer to sps endpoint data structure
3983 * @is_produce - 1 means Producer endpoint
3984 * 0 means Consumer endpoint
3985 *
3986 * @return - 0 if successful else negative value.
3987 *
3988 */
3989static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3990 struct msmsdcc_sps_ep_conn_data *ep,
3991 bool is_producer)
3992{
3993 int rc = 0;
3994 struct sps_pipe *sps_pipe_handle;
3995 struct sps_connect *sps_config = &ep->config;
3996 struct sps_register_event *sps_event = &ep->event;
3997
3998 /* Allocate endpoint context */
3999 sps_pipe_handle = sps_alloc_endpoint();
4000 if (!sps_pipe_handle) {
4001 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4002 mmc_hostname(host->mmc), is_producer);
4003 rc = -ENOMEM;
4004 goto out;
4005 }
4006
4007 /* Get default connection configuration for an endpoint */
4008 rc = sps_get_config(sps_pipe_handle, sps_config);
4009 if (rc) {
4010 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4011 " rc=%d", mmc_hostname(host->mmc),
4012 (u32)sps_pipe_handle, rc);
4013 goto get_config_err;
4014 }
4015
4016 /* Modify the default connection configuration */
4017 if (is_producer) {
4018 /*
4019 * For SDCC producer transfer, source should be
4020 * SDCC peripheral where as destination should
4021 * be system memory.
4022 */
4023 sps_config->source = host->sps.bam_handle;
4024 sps_config->destination = SPS_DEV_HANDLE_MEM;
4025 /* Producer pipe will handle this connection */
4026 sps_config->mode = SPS_MODE_SRC;
4027 sps_config->options =
4028 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4029 } else {
4030 /*
4031 * For SDCC consumer transfer, source should be
4032 * system memory where as destination should
4033 * SDCC peripheral
4034 */
4035 sps_config->source = SPS_DEV_HANDLE_MEM;
4036 sps_config->destination = host->sps.bam_handle;
4037 sps_config->mode = SPS_MODE_DEST;
4038 sps_config->options =
4039 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4040 }
4041
4042 /* Producer pipe index */
4043 sps_config->src_pipe_index = host->sps.src_pipe_index;
4044 /* Consumer pipe index */
4045 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4046 /*
4047 * This event thresold value is only significant for BAM-to-BAM
4048 * transfer. It's ignored for BAM-to-System mode transfer.
4049 */
4050 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304051
4052 /* Allocate maximum descriptor fifo size */
4053 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4054 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4056 sps_config->desc.size,
4057 &sps_config->desc.phys_base,
4058 GFP_KERNEL);
4059
Pratibhasagar V00b94332011-10-18 14:57:27 +05304060 if (!sps_config->desc.base) {
4061 rc = -ENOMEM;
4062 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4063 , mmc_hostname(host->mmc));
4064 goto get_config_err;
4065 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004066 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4067
4068 /* Establish connection between peripheral and memory endpoint */
4069 rc = sps_connect(sps_pipe_handle, sps_config);
4070 if (rc) {
4071 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4072 " rc=%d", mmc_hostname(host->mmc),
4073 (u32)sps_pipe_handle, rc);
4074 goto sps_connect_err;
4075 }
4076
4077 sps_event->mode = SPS_TRIGGER_CALLBACK;
4078 sps_event->options = SPS_O_EOT;
4079 sps_event->callback = msmsdcc_sps_complete_cb;
4080 sps_event->xfer_done = NULL;
4081 sps_event->user = (void *)host;
4082
4083 /* Register callback event for EOT (End of transfer) event. */
4084 rc = sps_register_event(sps_pipe_handle, sps_event);
4085 if (rc) {
4086 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4087 " rc=%d", mmc_hostname(host->mmc),
4088 (u32)sps_pipe_handle, rc);
4089 goto reg_event_err;
4090 }
4091 /* Now save the sps pipe handle */
4092 ep->pipe_handle = sps_pipe_handle;
4093 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4094 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4095 __func__, is_producer ? "READ" : "WRITE",
4096 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4097 goto out;
4098
4099reg_event_err:
4100 sps_disconnect(sps_pipe_handle);
4101sps_connect_err:
4102 dma_free_coherent(mmc_dev(host->mmc),
4103 sps_config->desc.size,
4104 sps_config->desc.base,
4105 sps_config->desc.phys_base);
4106get_config_err:
4107 sps_free_endpoint(sps_pipe_handle);
4108out:
4109 return rc;
4110}
4111
4112/**
4113 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4114 *
4115 * This function disconnect endpoint and deallocates
4116 * endpoint context.
4117 *
4118 * This function should only be called once typically
4119 * during driver remove.
4120 *
4121 * @host - Pointer to sdcc host structure
4122 * @ep - Pointer to sps endpoint data structure
4123 *
4124 */
4125static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4126 struct msmsdcc_sps_ep_conn_data *ep)
4127{
4128 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4129 struct sps_connect *sps_config = &ep->config;
4130 struct sps_register_event *sps_event = &ep->event;
4131
4132 sps_event->xfer_done = NULL;
4133 sps_event->callback = NULL;
4134 sps_register_event(sps_pipe_handle, sps_event);
4135 sps_disconnect(sps_pipe_handle);
4136 dma_free_coherent(mmc_dev(host->mmc),
4137 sps_config->desc.size,
4138 sps_config->desc.base,
4139 sps_config->desc.phys_base);
4140 sps_free_endpoint(sps_pipe_handle);
4141}
4142
4143/**
4144 * Reset SDCC peripheral's SPS endpoint
4145 *
4146 * This function disconnects an endpoint.
4147 *
4148 * This function should be called for reseting
4149 * SPS endpoint when data transfer error is
4150 * encountered during data transfer. This
4151 * can be considered as soft reset to endpoint.
4152 *
4153 * This function should only be called if
4154 * msmsdcc_sps_init() is already called.
4155 *
4156 * @host - Pointer to sdcc host structure
4157 * @ep - Pointer to sps endpoint data structure
4158 *
4159 * @return - 0 if successful else negative value.
4160 */
4161static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4162 struct msmsdcc_sps_ep_conn_data *ep)
4163{
4164 int rc = 0;
4165 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4166
4167 rc = sps_disconnect(sps_pipe_handle);
4168 if (rc) {
4169 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4170 " rc=%d", mmc_hostname(host->mmc), __func__,
4171 (u32)sps_pipe_handle, rc);
4172 goto out;
4173 }
4174 out:
4175 return rc;
4176}
4177
4178/**
4179 * Restore SDCC peripheral's SPS endpoint
4180 *
4181 * This function connects an endpoint.
4182 *
4183 * This function should be called for restoring
4184 * SPS endpoint after data transfer error is
4185 * encountered during data transfer. This
4186 * can be considered as soft reset to endpoint.
4187 *
4188 * This function should only be called if
4189 * msmsdcc_sps_reset_ep() is called before.
4190 *
4191 * @host - Pointer to sdcc host structure
4192 * @ep - Pointer to sps endpoint data structure
4193 *
4194 * @return - 0 if successful else negative value.
4195 */
4196static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4197 struct msmsdcc_sps_ep_conn_data *ep)
4198{
4199 int rc = 0;
4200 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4201 struct sps_connect *sps_config = &ep->config;
4202 struct sps_register_event *sps_event = &ep->event;
4203
4204 /* Establish connection between peripheral and memory endpoint */
4205 rc = sps_connect(sps_pipe_handle, sps_config);
4206 if (rc) {
4207 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4208 " rc=%d", mmc_hostname(host->mmc), __func__,
4209 (u32)sps_pipe_handle, rc);
4210 goto out;
4211 }
4212
4213 /* Register callback event for EOT (End of transfer) event. */
4214 rc = sps_register_event(sps_pipe_handle, sps_event);
4215 if (rc) {
4216 pr_err("%s: %s: sps_register_event() failed!!!"
4217 " pipe_handle=0x%x, rc=%d",
4218 mmc_hostname(host->mmc), __func__,
4219 (u32)sps_pipe_handle, rc);
4220 goto reg_event_err;
4221 }
4222 goto out;
4223
4224reg_event_err:
4225 sps_disconnect(sps_pipe_handle);
4226out:
4227 return rc;
4228}
4229
4230/**
4231 * Initialize SPS HW connected with SDCC core
4232 *
4233 * This function register BAM HW resources with
4234 * SPS driver and then initialize 2 SPS endpoints
4235 *
4236 * This function should only be called once typically
4237 * during driver probe.
4238 *
4239 * @host - Pointer to sdcc host structure
4240 *
4241 * @return - 0 if successful else negative value.
4242 *
4243 */
4244static int msmsdcc_sps_init(struct msmsdcc_host *host)
4245{
4246 int rc = 0;
4247 struct sps_bam_props bam = {0};
4248
4249 host->bam_base = ioremap(host->bam_memres->start,
4250 resource_size(host->bam_memres));
4251 if (!host->bam_base) {
4252 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4253 " size=0x%x", mmc_hostname(host->mmc),
4254 host->bam_memres->start,
4255 (host->bam_memres->end -
4256 host->bam_memres->start));
4257 rc = -ENOMEM;
4258 goto out;
4259 }
4260
4261 bam.phys_addr = host->bam_memres->start;
4262 bam.virt_addr = host->bam_base;
4263 /*
4264 * This event thresold value is only significant for BAM-to-BAM
4265 * transfer. It's ignored for BAM-to-System mode transfer.
4266 */
4267 bam.event_threshold = 0x10; /* Pipe event threshold */
4268 /*
4269 * This threshold controls when the BAM publish
4270 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304271 * SPS HW will be used for data transfer size even
4272 * less than SDCC FIFO size. So let's set BAM summing
4273 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004274 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304275 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004276 /* SPS driver wll handle the SDCC BAM IRQ */
4277 bam.irq = (u32)host->bam_irqres->start;
4278 bam.manage = SPS_BAM_MGR_LOCAL;
4279
4280 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4281 (u32)bam.phys_addr);
4282 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4283 (u32)bam.virt_addr);
4284
4285 /* Register SDCC Peripheral BAM device to SPS driver */
4286 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4287 if (rc) {
4288 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4289 mmc_hostname(host->mmc), rc);
4290 goto reg_bam_err;
4291 }
4292 pr_info("%s: BAM device registered. bam_handle=0x%x",
4293 mmc_hostname(host->mmc), host->sps.bam_handle);
4294
4295 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4296 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4297
4298 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4299 SPS_PROD_PERIPHERAL);
4300 if (rc)
4301 goto sps_reset_err;
4302 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4303 SPS_CONS_PERIPHERAL);
4304 if (rc)
4305 goto cons_conn_err;
4306
4307 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4308 mmc_hostname(host->mmc),
4309 (unsigned long long)host->bam_memres->start,
4310 (unsigned int)host->bam_irqres->start);
4311 goto out;
4312
4313cons_conn_err:
4314 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4315sps_reset_err:
4316 sps_deregister_bam_device(host->sps.bam_handle);
4317reg_bam_err:
4318 iounmap(host->bam_base);
4319out:
4320 return rc;
4321}
4322
4323/**
4324 * De-initialize SPS HW connected with SDCC core
4325 *
4326 * This function deinitialize SPS endpoints and then
4327 * deregisters BAM resources from SPS driver.
4328 *
4329 * This function should only be called once typically
4330 * during driver remove.
4331 *
4332 * @host - Pointer to sdcc host structure
4333 *
4334 */
4335static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4336{
4337 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4338 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4339 sps_deregister_bam_device(host->sps.bam_handle);
4340 iounmap(host->bam_base);
4341}
4342#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4343
4344static ssize_t
4345show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4346{
4347 struct mmc_host *mmc = dev_get_drvdata(dev);
4348 struct msmsdcc_host *host = mmc_priv(mmc);
4349 int poll;
4350 unsigned long flags;
4351
4352 spin_lock_irqsave(&host->lock, flags);
4353 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4354 spin_unlock_irqrestore(&host->lock, flags);
4355
4356 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4357}
4358
4359static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304360store_polling(struct device *dev, struct device_attribute *attr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361 const char *buf, size_t count)
4362{
4363 struct mmc_host *mmc = dev_get_drvdata(dev);
4364 struct msmsdcc_host *host = mmc_priv(mmc);
4365 int value;
4366 unsigned long flags;
4367
4368 sscanf(buf, "%d", &value);
4369
4370 spin_lock_irqsave(&host->lock, flags);
4371 if (value) {
4372 mmc->caps |= MMC_CAP_NEEDS_POLL;
4373 mmc_detect_change(host->mmc, 0);
4374 } else {
4375 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4376 }
4377#ifdef CONFIG_HAS_EARLYSUSPEND
4378 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4379#endif
4380 spin_unlock_irqrestore(&host->lock, flags);
4381 return count;
4382}
4383
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304384static ssize_t
4385show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4386 char *buf)
4387{
4388 struct mmc_host *mmc = dev_get_drvdata(dev);
4389 struct msmsdcc_host *host = mmc_priv(mmc);
4390
4391 return snprintf(buf, PAGE_SIZE, "%u\n",
4392 host->msm_bus_vote.is_max_bw_needed);
4393}
4394
4395static ssize_t
Subhash Jadavanie363cc42012-06-05 18:01:08 +05304396store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304397 const char *buf, size_t count)
4398{
4399 struct mmc_host *mmc = dev_get_drvdata(dev);
4400 struct msmsdcc_host *host = mmc_priv(mmc);
4401 uint32_t value;
4402 unsigned long flags;
4403
4404 if (!kstrtou32(buf, 0, &value)) {
4405 spin_lock_irqsave(&host->lock, flags);
4406 host->msm_bus_vote.is_max_bw_needed = !!value;
4407 spin_unlock_irqrestore(&host->lock, flags);
4408 }
4409
4410 return count;
4411}
4412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004413#ifdef CONFIG_HAS_EARLYSUSPEND
4414static void msmsdcc_early_suspend(struct early_suspend *h)
4415{
4416 struct msmsdcc_host *host =
4417 container_of(h, struct msmsdcc_host, early_suspend);
4418 unsigned long flags;
4419
4420 spin_lock_irqsave(&host->lock, flags);
4421 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4422 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4423 spin_unlock_irqrestore(&host->lock, flags);
4424};
4425static void msmsdcc_late_resume(struct early_suspend *h)
4426{
4427 struct msmsdcc_host *host =
4428 container_of(h, struct msmsdcc_host, early_suspend);
4429 unsigned long flags;
4430
4431 if (host->polling_enabled) {
4432 spin_lock_irqsave(&host->lock, flags);
4433 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4434 mmc_detect_change(host->mmc, 0);
4435 spin_unlock_irqrestore(&host->lock, flags);
4436 }
4437};
4438#endif
4439
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304440static void msmsdcc_print_regs(const char *name, void __iomem *base,
4441 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304442{
4443 unsigned int i;
4444
4445 if (!base)
4446 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304447
4448 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4449 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304450 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304451 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4452 (u32)readl_relaxed(base + i*4),
4453 (u32)readl_relaxed(base + ((i+1)*4)),
4454 (u32)readl_relaxed(base + ((i+2)*4)),
4455 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304456 }
4457}
4458
4459static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4460{
4461 /* Dump current state of SDCC clocks, power and irq */
4462 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304463 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304464 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304465 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4466 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304467 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4468 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4469
4470 /* Now dump SDCC registers. Don't print FIFO registers */
4471 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304472 msmsdcc_print_regs("SDCC-CORE", host->base,
4473 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304474
4475 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304476 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304477 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4478 else if (host->is_dma_mode)
4479 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4480 mmc_hostname(host->mmc), host->dma.busy,
4481 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304482 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304483 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304484 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4485 host->dml_memres->start,
4486 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304487 pr_info("%s: SPS mode: busy=%d\n",
4488 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304489 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304490
4491 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4492 mmc_hostname(host->mmc), host->curr.xfer_size,
4493 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304494 }
4495
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304496 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304497 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4498 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4499 host->curr.got_dataend, host->prog_enable,
4500 host->curr.wait_for_auto_prog_done,
4501 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304502 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304503}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4506{
4507 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4508 struct mmc_request *mrq;
4509 unsigned long flags;
4510
4511 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004512 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004513 pr_info("%s: %s: dummy CMD52 timeout\n",
4514 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004515 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004516 }
4517
4518 mrq = host->curr.mrq;
4519
4520 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304521 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4522 mrq->cmd->opcode);
4523 msmsdcc_dump_sdcc_state(host);
4524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004525 if (!mrq->cmd->error)
4526 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304527 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004529 if (mrq->data && !mrq->data->error)
4530 mrq->data->error = -ETIMEDOUT;
4531 host->curr.data_xfered = 0;
4532 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004533 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004534 } else if (host->sps.sg && host->is_sps_mode) {
4535 /* Stop current SPS transfer */
4536 msmsdcc_sps_exit_curr_xfer(host);
4537 } else {
4538 msmsdcc_reset_and_restore(host);
4539 msmsdcc_stop_data(host);
4540 if (mrq->data && mrq->data->stop)
4541 msmsdcc_start_command(host,
4542 mrq->data->stop, 0);
4543 else
4544 msmsdcc_request_end(host, mrq);
4545 }
4546 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304547 host->prog_enable = 0;
Subhash Jadavanid5d59dc2012-05-22 19:38:33 +05304548 host->curr.wait_for_auto_prog_done = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004549 msmsdcc_reset_and_restore(host);
4550 msmsdcc_request_end(host, mrq);
4551 }
4552 }
4553 spin_unlock_irqrestore(&host->lock, flags);
4554}
4555
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304556static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4557{
4558 int i, ret;
4559 struct mmc_platform_data *pdata;
4560 struct device_node *np = dev->of_node;
4561 u32 bus_width = 0;
4562 u32 *clk_table;
4563 int clk_table_len;
4564 u32 *sup_voltages;
4565 int sup_volt_len;
4566
4567 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4568 if (!pdata) {
4569 dev_err(dev, "could not allocate memory for platform data\n");
4570 goto err;
4571 }
4572
4573 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4574 if (bus_width == 8) {
4575 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4576 } else if (bus_width == 4) {
4577 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4578 } else {
4579 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4580 pdata->mmc_bus_width = 0;
4581 }
4582
4583 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4584 size_t sz;
4585 sz = sup_volt_len / sizeof(*sup_voltages);
4586 if (sz > 0) {
4587 sup_voltages = devm_kzalloc(dev,
4588 sz * sizeof(*sup_voltages), GFP_KERNEL);
4589 if (!sup_voltages) {
4590 dev_err(dev, "No memory for supported voltage\n");
4591 goto err;
4592 }
4593
4594 ret = of_property_read_u32_array(np,
4595 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4596 if (ret < 0) {
4597 dev_err(dev, "error while reading voltage"
4598 "ranges %d\n", ret);
4599 goto err;
4600 }
4601 } else {
4602 dev_err(dev, "No supported voltages\n");
4603 goto err;
4604 }
4605 for (i = 0; i < sz; i += 2) {
4606 u32 mask;
4607
4608 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4609 sup_voltages[i + 1]);
4610 if (!mask)
4611 dev_err(dev, "Invalide voltage range %d\n", i);
4612 pdata->ocr_mask |= mask;
4613 }
4614 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4615 } else {
4616 dev_err(dev, "Supported voltage range not specified\n");
4617 }
4618
4619 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4620 size_t sz;
4621 sz = clk_table_len / sizeof(*clk_table);
4622
4623 if (sz > 0) {
4624 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4625 GFP_KERNEL);
4626 if (!clk_table) {
4627 dev_err(dev, "No memory for clock table\n");
4628 goto err;
4629 }
4630
4631 ret = of_property_read_u32_array(np,
4632 "qcom,sdcc-clk-rates", clk_table, sz);
4633 if (ret < 0) {
4634 dev_err(dev, "error while reading clk"
4635 "table %d\n", ret);
4636 goto err;
4637 }
4638 } else {
4639 dev_err(dev, "clk_table not specified\n");
4640 goto err;
4641 }
4642 pdata->sup_clk_table = clk_table;
4643 pdata->sup_clk_cnt = sz;
4644 } else {
4645 dev_err(dev, "Supported clock rates not specified\n");
4646 }
4647
4648 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4649 pdata->nonremovable = true;
4650 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4651 pdata->disable_cmd23 = true;
4652
4653 return pdata;
4654err:
4655 return NULL;
4656}
4657
San Mehat9d2bd732009-09-22 16:44:22 -07004658static int
4659msmsdcc_probe(struct platform_device *pdev)
4660{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304661 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004662 struct msmsdcc_host *host;
4663 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004664 unsigned long flags;
4665 struct resource *core_irqres = NULL;
4666 struct resource *bam_irqres = NULL;
4667 struct resource *core_memres = NULL;
4668 struct resource *dml_memres = NULL;
4669 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004670 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004671 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304672 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004673 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004674
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304675 if (pdev->dev.of_node) {
4676 plat = msmsdcc_populate_pdata(&pdev->dev);
4677 of_property_read_u32((&pdev->dev)->of_node,
4678 "cell-index", &pdev->id);
4679 } else {
4680 plat = pdev->dev.platform_data;
4681 }
San Mehat9d2bd732009-09-22 16:44:22 -07004682
4683 /* must have platform data */
4684 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004685 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004686 ret = -EINVAL;
4687 goto out;
4688 }
4689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004690 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004691 return -EINVAL;
4692
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304693 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4694 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4695 return -EINVAL;
4696 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004697
San Mehat9d2bd732009-09-22 16:44:22 -07004698 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004699 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004700 return -ENXIO;
4701 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304702 if (pdev->dev.of_node) {
4703 /*
4704 * Device tree iomem resources are only accessible by index.
4705 * index = 0 -> SDCC register interface
4706 * index = 1 -> DML register interface
4707 * index = 2 -> BAM register interface
4708 * IRQ resources:
4709 * index = 0 -> SDCC IRQ
4710 * index = 1 -> BAM IRQ
4711 */
4712 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4713 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4714 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4715 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4716 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4717 } else {
4718 for (i = 0; i < pdev->num_resources; i++) {
4719 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4720 if (!strncmp(pdev->resource[i].name,
4721 "sdcc_dml_addr",
4722 sizeof("sdcc_dml_addr")))
4723 dml_memres = &pdev->resource[i];
4724 else if (!strncmp(pdev->resource[i].name,
4725 "sdcc_bam_addr",
4726 sizeof("sdcc_bam_addr")))
4727 bam_memres = &pdev->resource[i];
4728 else
4729 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004730
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304731 }
4732 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4733 if (!strncmp(pdev->resource[i].name,
4734 "sdcc_bam_irq",
4735 sizeof("sdcc_bam_irq")))
4736 bam_irqres = &pdev->resource[i];
4737 else
4738 core_irqres = &pdev->resource[i];
4739 }
4740 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4741 if (!strncmp(pdev->resource[i].name,
4742 "sdcc_dma_chnl",
4743 sizeof("sdcc_dma_chnl")))
4744 dmares = &pdev->resource[i];
4745 else if (!strncmp(pdev->resource[i].name,
4746 "sdcc_dma_crci",
4747 sizeof("sdcc_dma_crci")))
4748 dma_crci_res = &pdev->resource[i];
4749 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004750 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 }
San Mehat9d2bd732009-09-22 16:44:22 -07004752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004753 if (!core_irqres || !core_memres) {
4754 pr_err("%s: Invalid sdcc core resource\n", __func__);
4755 return -ENXIO;
4756 }
4757
4758 /*
4759 * Both BAM and DML memory resource should be preset.
4760 * BAM IRQ resource should also be present.
4761 */
4762 if ((bam_memres && !dml_memres) ||
4763 (!bam_memres && dml_memres) ||
4764 ((bam_memres && dml_memres) && !bam_irqres)) {
4765 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004766 return -ENXIO;
4767 }
4768
4769 /*
4770 * Setup our host structure
4771 */
San Mehat9d2bd732009-09-22 16:44:22 -07004772 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4773 if (!mmc) {
4774 ret = -ENOMEM;
4775 goto out;
4776 }
4777
4778 host = mmc_priv(mmc);
4779 host->pdev_id = pdev->id;
4780 host->plat = plat;
4781 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004782 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05304783
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304784 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785 host->is_sps_mode = 1;
4786 else if (dmares)
4787 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789 host->base = ioremap(core_memres->start,
4790 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004791 if (!host->base) {
4792 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05304793 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004794 }
4795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796 host->core_irqres = core_irqres;
4797 host->bam_irqres = bam_irqres;
4798 host->core_memres = core_memres;
4799 host->dml_memres = dml_memres;
4800 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004801 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004802 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004803 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304804 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004806#ifdef CONFIG_MMC_EMBEDDED_SDIO
4807 if (plat->embedded_sdio)
4808 mmc_set_embedded_sdio_data(mmc,
4809 &plat->embedded_sdio->cis,
4810 &plat->embedded_sdio->cccr,
4811 plat->embedded_sdio->funcs,
4812 plat->embedded_sdio->num_funcs);
4813#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004814
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304815 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4816 (unsigned long)host);
4817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004818 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4819 (unsigned long)host);
4820 if (host->is_dma_mode) {
4821 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05304822 ret = msmsdcc_init_dma(host);
4823 if (ret)
4824 goto ioremap_free;
4825 } else {
4826 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004827 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05304828 }
San Mehat9d2bd732009-09-22 16:44:22 -07004829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004830 /*
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05304831 * Setup SDCC bus voter clock.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 */
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05304833 host->bus_clk = clk_get(&pdev->dev, "bus_clk");
4834 if (!IS_ERR_OR_NULL(host->bus_clk)) {
4835 /* Vote for max. clk rate for max. performance */
4836 ret = clk_set_rate(host->bus_clk, INT_MAX);
4837 if (ret)
4838 goto bus_clk_put;
4839 ret = clk_prepare_enable(host->bus_clk);
4840 if (ret)
4841 goto bus_clk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07004842 }
4843
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004844 /*
4845 * Setup main peripheral bus clock
4846 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004847 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004848 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304849 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004850 if (ret)
4851 goto pclk_put;
4852
4853 host->pclk_rate = clk_get_rate(host->pclk);
4854 }
4855
4856 /*
4857 * Setup SDC MMC clock
4858 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004859 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004860 if (IS_ERR(host->clk)) {
4861 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004862 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004863 }
4864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004865 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05304866 if (ret) {
4867 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4868 goto clk_put;
4869 }
4870
Asutosh Dasf5298c32012-04-03 14:51:47 +05304871 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004872 if (ret)
4873 goto clk_put;
4874
San Mehat9d2bd732009-09-22 16:44:22 -07004875 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304876 if (!host->clk_rate)
4877 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304878
4879 /*
4880 * Lookup the Controller Version, to identify the supported features
4881 * Version number read as 0 would indicate SDCC3 or earlier versions
4882 */
4883 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4884 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4885 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304886 /*
4887 * Set the register write delay according to min. clock frequency
4888 * supported and update later when the host->clk_rate changes.
4889 */
4890 host->reg_write_delay =
4891 (1 + ((3 * USEC_PER_SEC) /
4892 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004893
4894 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304895 /* Apply Hard reset to SDCC to put it in power on default state */
4896 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004897
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004898#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304899 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004900 if (host->plat->cpu_dma_latency)
4901 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4902 else
4903 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4904 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304905 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4906
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304907 ret = msmsdcc_msm_bus_register(host);
4908 if (ret)
4909 goto pm_qos_remove;
4910
4911 if (host->msm_bus_vote.client_handle)
4912 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4913 msmsdcc_msm_bus_work);
4914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004915 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004916 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004917 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004918 goto clk_disable;
4919 }
4920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004921
4922 /* Clocks has to be running before accessing SPS/DML HW blocks */
4923 if (host->is_sps_mode) {
4924 /* Initialize SPS */
4925 ret = msmsdcc_sps_init(host);
4926 if (ret)
4927 goto vreg_deinit;
4928 /* Initialize DML */
4929 ret = msmsdcc_dml_init(host);
4930 if (ret)
4931 goto sps_exit;
4932 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304933 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004934
San Mehat9d2bd732009-09-22 16:44:22 -07004935 /*
4936 * Setup MMC host structure
4937 */
4938 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004939 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4940 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004941 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004942 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4943 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004944
San Mehat9d2bd732009-09-22 16:44:22 -07004945 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304946 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07004947
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304948 /*
4949 * If we send the CMD23 before multi block write/read command
4950 * then we need not to send CMD12 at the end of the transfer.
4951 * If we don't send the CMD12 then only way to detect the PROG_DONE
4952 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4953 * controller. So let's enable the CMD23 for SDCC4 only.
4954 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304955 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304956 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07004957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004958 mmc->caps |= plat->uhs_caps;
4959 /*
4960 * XPC controls the maximum current in the default speed mode of SDXC
4961 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4962 * XPC=1 means 150mA (max.) and speed class is supported.
4963 */
4964 if (plat->xpc_cap)
4965 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4966 MMC_CAP_SET_XPC_180);
4967
Maya Erez25e22612012-05-20 08:45:01 +03004968 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03004969 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304970 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03004971 mmc->caps2 |= MMC_CAP2_SANITIZE;
4972
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304973 if (pdev->dev.of_node) {
4974 if (of_get_property((&pdev->dev)->of_node,
4975 "qcom,sdcc-hs200", NULL))
4976 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4977 }
4978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004979 if (plat->nonremovable)
4980 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004981 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004982
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03004983 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
4984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004985 if (plat->is_sdio_al_client)
4986 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004987
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304988 mmc->max_segs = msmsdcc_get_nr_sg(host);
4989 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4990 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004991
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304992 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07004993 mmc->max_seg_size = mmc->max_req_size;
4994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004995 writel_relaxed(0, host->base + MMCIMASK0);
4996 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304997 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004999 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5000 mb();
5001 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005003 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5004 DRIVER_NAME " (cmd)", host);
5005 if (ret)
5006 goto dml_exit;
5007
5008 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5009 DRIVER_NAME " (pio)", host);
5010 if (ret)
5011 goto irq_free;
5012
5013 /*
5014 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5015 * IRQ is un-necessarily being monitored by MPM (Modem power
5016 * management block) during idle-power collapse. The MPM will be
5017 * configured to monitor the DATA1 GPIO line with level-low trigger
5018 * and thus depending on the GPIO status, it prevents TCXO shutdown
5019 * during idle-power collapse.
5020 */
5021 disable_irq(core_irqres->start);
5022 host->sdcc_irq_disabled = 1;
5023
5024 if (plat->sdiowakeup_irq) {
5025 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5026 mmc_hostname(mmc));
5027 ret = request_irq(plat->sdiowakeup_irq,
5028 msmsdcc_platform_sdiowakeup_irq,
5029 IRQF_SHARED | IRQF_TRIGGER_LOW,
5030 DRIVER_NAME "sdiowakeup", host);
5031 if (ret) {
5032 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5033 plat->sdiowakeup_irq, ret);
5034 goto pio_irq_free;
5035 } else {
5036 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305037 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005038 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305039 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005040 }
5041 spin_unlock_irqrestore(&host->lock, flags);
5042 }
5043 }
5044
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305045 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005046 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5047 mmc_hostname(mmc));
5048 }
5049
5050 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5051 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005052 /*
5053 * Setup card detect change
5054 */
5055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005056 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005057 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005059 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005060 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005061
Krishna Konda941604a2012-01-10 17:46:34 -08005062 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005063 }
San Mehat9d2bd732009-09-22 16:44:22 -07005064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 if (plat->status_irq) {
5066 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005067 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005068 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005069 DRIVER_NAME " (slot)",
5070 host);
5071 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005072 pr_err("Unable to get slot IRQ %d (%d)\n",
5073 plat->status_irq, ret);
5074 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005075 }
5076 } else if (plat->register_status_notify) {
5077 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5078 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005079 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005080 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005081
5082 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005083
5084 ret = pm_runtime_set_active(&(pdev)->dev);
5085 if (ret < 0)
5086 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5087 __func__, ret);
5088 /*
5089 * There is no notion of suspend/resume for SD/MMC/SDIO
5090 * cards. So host can be suspended/resumed with out
5091 * worrying about its children.
5092 */
5093 pm_suspend_ignore_children(&(pdev)->dev, true);
5094
5095 /*
5096 * MMC/SD/SDIO bus suspend/resume operations are defined
5097 * only for the slots that will be used for non-removable
5098 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5099 * defined. Otherwise, they simply become card removal and
5100 * insertion events during suspend and resume respectively.
5101 * Hence, enable run-time PM only for slots for which bus
5102 * suspend/resume operations are defined.
5103 */
5104#ifdef CONFIG_MMC_UNSAFE_RESUME
5105 /*
5106 * If this capability is set, MMC core will enable/disable host
5107 * for every claim/release operation on a host. We use this
5108 * notification to increment/decrement runtime pm usage count.
5109 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005110 pm_runtime_enable(&(pdev)->dev);
5111#else
5112 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005113 pm_runtime_enable(&(pdev)->dev);
5114 }
5115#endif
5116 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5117 (unsigned long)host);
5118
San Mehat9d2bd732009-09-22 16:44:22 -07005119 mmc_add_host(mmc);
5120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005121#ifdef CONFIG_HAS_EARLYSUSPEND
5122 host->early_suspend.suspend = msmsdcc_early_suspend;
5123 host->early_suspend.resume = msmsdcc_late_resume;
5124 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5125 register_early_suspend(&host->early_suspend);
5126#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005127
Krishna Konda25786ec2011-07-25 16:21:36 -07005128 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5129 " dmacrcri %d\n", mmc_hostname(mmc),
5130 (unsigned long long)core_memres->start,
5131 (unsigned int) core_irqres->start,
5132 (unsigned int) plat->status_irq, host->dma.channel,
5133 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005134
5135 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5136 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5137 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5138 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5139 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5140 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5141 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5142 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5143 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5144 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5145 host->eject);
5146 pr_info("%s: Power save feature enable = %d\n",
5147 mmc_hostname(mmc), msmsdcc_pwrsave);
5148
Krishna Konda25786ec2011-07-25 16:21:36 -07005149 if (host->is_dma_mode && host->dma.channel != -1
5150 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005151 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005152 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005153 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005154 mmc_hostname(mmc), host->dma.cmd_busaddr,
5155 host->dma.cmdptr_busaddr);
5156 } else if (host->is_sps_mode) {
5157 pr_info("%s: SPS-BAM data transfer mode available\n",
5158 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005159 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005160 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005162#if defined(CONFIG_DEBUG_FS)
5163 msmsdcc_dbg_createhost(host);
5164#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305165
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305166 host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
5167 host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
5168 sysfs_attr_init(&host->max_bus_bw.attr);
5169 host->max_bus_bw.attr.name = "max_bus_bw";
5170 host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
5171 ret = device_create_file(&pdev->dev, &host->max_bus_bw);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305172 if (ret)
5173 goto platform_irq_free;
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305174
5175 if (!plat->status_irq) {
5176 host->polling.show = show_polling;
5177 host->polling.store = store_polling;
5178 sysfs_attr_init(&host->polling.attr);
5179 host->polling.attr.name = "polling";
5180 host->polling.attr.mode = S_IRUGO | S_IWUSR;
5181 ret = device_create_file(&pdev->dev, &host->polling);
5182 if (ret)
5183 goto remove_max_bus_bw_file;
5184 }
San Mehat9d2bd732009-09-22 16:44:22 -07005185 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005186
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305187 remove_max_bus_bw_file:
5188 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189 platform_irq_free:
5190 del_timer_sync(&host->req_tout_timer);
5191 pm_runtime_disable(&(pdev)->dev);
5192 pm_runtime_set_suspended(&(pdev)->dev);
5193
5194 if (plat->status_irq)
5195 free_irq(plat->status_irq, host);
5196 sdiowakeup_irq_free:
5197 wake_lock_destroy(&host->sdio_suspend_wlock);
5198 if (plat->sdiowakeup_irq)
5199 free_irq(plat->sdiowakeup_irq, host);
5200 pio_irq_free:
5201 if (plat->sdiowakeup_irq)
5202 wake_lock_destroy(&host->sdio_wlock);
5203 free_irq(core_irqres->start, host);
5204 irq_free:
5205 free_irq(core_irqres->start, host);
5206 dml_exit:
5207 if (host->is_sps_mode)
5208 msmsdcc_dml_exit(host);
5209 sps_exit:
5210 if (host->is_sps_mode)
5211 msmsdcc_sps_exit(host);
5212 vreg_deinit:
5213 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005214 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005215 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305216 msmsdcc_msm_bus_unregister(host);
5217 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005218 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305219 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005220 clk_put:
5221 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005222 pclk_disable:
5223 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305224 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005225 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005226 if (!IS_ERR(host->pclk))
5227 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305228 if (!IS_ERR_OR_NULL(host->bus_clk))
5229 clk_disable_unprepare(host->bus_clk);
5230 bus_clk_put:
5231 if (!IS_ERR_OR_NULL(host->bus_clk))
5232 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005233 if (host->is_dma_mode) {
5234 if (host->dmares)
5235 dma_free_coherent(NULL,
5236 sizeof(struct msmsdcc_nc_dmadata),
5237 host->dma.nc, host->dma.nc_busaddr);
5238 }
5239 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305240 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005241 host_free:
5242 mmc_free_host(mmc);
5243 out:
5244 return ret;
5245}
5246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005247static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005248{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005249 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5250 struct mmc_platform_data *plat;
5251 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005253 if (!mmc)
5254 return -ENXIO;
5255
5256 if (pm_runtime_suspended(&(pdev)->dev))
5257 pm_runtime_resume(&(pdev)->dev);
5258
5259 host = mmc_priv(mmc);
5260
5261 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5262 plat = host->plat;
5263
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305264 device_remove_file(&pdev->dev, &host->max_bus_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005265 if (!plat->status_irq)
Subhash Jadavanie363cc42012-06-05 18:01:08 +05305266 device_remove_file(&pdev->dev, &host->polling);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005267
5268 del_timer_sync(&host->req_tout_timer);
5269 tasklet_kill(&host->dma_tlet);
5270 tasklet_kill(&host->sps.tlet);
5271 mmc_remove_host(mmc);
5272
5273 if (plat->status_irq)
5274 free_irq(plat->status_irq, host);
5275
5276 wake_lock_destroy(&host->sdio_suspend_wlock);
5277 if (plat->sdiowakeup_irq) {
5278 wake_lock_destroy(&host->sdio_wlock);
5279 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5280 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005282
5283 free_irq(host->core_irqres->start, host);
5284 free_irq(host->core_irqres->start, host);
5285
5286 clk_put(host->clk);
5287 if (!IS_ERR(host->pclk))
5288 clk_put(host->pclk);
Sujit Reddy Thumma8d08c142012-06-12 22:52:29 +05305289 if (!IS_ERR_OR_NULL(host->bus_clk))
5290 clk_put(host->bus_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005291
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005292 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305293 pm_qos_remove_request(&host->pm_qos_req_dma);
5294
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305295 if (host->msm_bus_vote.client_handle) {
5296 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5297 msmsdcc_msm_bus_unregister(host);
5298 }
5299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005300 msmsdcc_vreg_init(host, false);
5301
5302 if (host->is_dma_mode) {
5303 if (host->dmares)
5304 dma_free_coherent(NULL,
5305 sizeof(struct msmsdcc_nc_dmadata),
5306 host->dma.nc, host->dma.nc_busaddr);
5307 }
5308
5309 if (host->is_sps_mode) {
5310 msmsdcc_dml_exit(host);
5311 msmsdcc_sps_exit(host);
5312 }
5313
5314 iounmap(host->base);
5315 mmc_free_host(mmc);
5316
5317#ifdef CONFIG_HAS_EARLYSUSPEND
5318 unregister_early_suspend(&host->early_suspend);
5319#endif
5320 pm_runtime_disable(&(pdev)->dev);
5321 pm_runtime_set_suspended(&(pdev)->dev);
5322
5323 return 0;
5324}
5325
5326#ifdef CONFIG_MSM_SDIO_AL
5327int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5328{
5329 struct msmsdcc_host *host = mmc_priv(mmc);
5330 unsigned long flags;
5331
Asutosh Dasf5298c32012-04-03 14:51:47 +05305332 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005333 spin_lock_irqsave(&host->lock, flags);
5334 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5335 enable ? "En" : "Dis");
5336
5337 if (enable) {
5338 if (!host->sdcc_irq_disabled) {
5339 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305340 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005341 host->sdcc_irq_disabled = 1;
5342 }
5343
5344 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305345 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005346 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305347 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005348 host->clks_on = 0;
5349 }
5350
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305351 if (host->plat->sdio_lpm_gpio_setup &&
5352 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005353 spin_unlock_irqrestore(&host->lock, flags);
5354 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5355 spin_lock_irqsave(&host->lock, flags);
5356 host->sdio_gpio_lpm = 1;
5357 }
5358
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305359 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005360 msmsdcc_enable_irq_wake(host);
5361 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305362 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005363 }
5364 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305365 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005366 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305367 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005368 msmsdcc_disable_irq_wake(host);
5369 }
5370
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305371 if (host->plat->sdio_lpm_gpio_setup &&
5372 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005373 spin_unlock_irqrestore(&host->lock, flags);
5374 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5375 spin_lock_irqsave(&host->lock, flags);
5376 host->sdio_gpio_lpm = 0;
5377 }
5378
5379 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305380 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005381 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305382 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005383 host->clks_on = 1;
5384 }
5385
5386 if (host->sdcc_irq_disabled) {
5387 writel_relaxed(host->mci_irqenable,
5388 host->base + MMCIMASK0);
5389 mb();
5390 enable_irq(host->core_irqres->start);
5391 host->sdcc_irq_disabled = 0;
5392 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005393 }
5394 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305395 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005396 return 0;
5397}
5398#else
5399int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5400{
5401 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005402}
5403#endif
5404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005405#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005406static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005407msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005408{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005409 struct mmc_host *mmc = dev_get_drvdata(dev);
5410 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005411 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305412 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005413
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305414 if (host->plat->is_sdio_al_client) {
5415 rc = 0;
5416 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07005417 }
San Mehat9d2bd732009-09-22 16:44:22 -07005418
Sahitya Tummala7661a452011-07-18 13:28:35 +05305419 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005420 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005421 host->sdcc_suspending = 1;
5422 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005424 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005425 * MMC core thinks that host is disabled by now since
5426 * runtime suspend is scheduled after msmsdcc_disable()
5427 * is called. Thus, MMC core will try to enable the host
5428 * while suspending it. This results in a synchronous
5429 * runtime resume request while in runtime suspending
5430 * context and hence inorder to complete this resume
5431 * requet, it will wait for suspend to be complete,
5432 * but runtime suspend also can not proceed further
5433 * until the host is resumed. Thus, it leads to a hang.
5434 * Hence, increase the pm usage count before suspending
5435 * the host so that any resume requests after this will
5436 * simple become pm usage counter increment operations.
5437 */
5438 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305439 /* If there is pending detect work abort runtime suspend */
5440 if (unlikely(work_busy(&mmc->detect.work)))
5441 rc = -EAGAIN;
5442 else
5443 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005444 pm_runtime_put_noidle(dev);
5445
5446 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305447 spin_lock_irqsave(&host->lock, flags);
5448 host->sdcc_suspended = true;
5449 spin_unlock_irqrestore(&host->lock, flags);
5450 if (mmc->card && mmc_card_sdio(mmc->card) &&
5451 mmc->ios.clock) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07005452#ifdef CONFIG_MMC_CLKGATE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005453 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305454 * If SDIO function driver doesn't want
5455 * to power off the card, atleast turn off
5456 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005457 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305458 mmc_host_clk_hold(mmc);
5459 spin_lock_irqsave(&mmc->clk_lock, flags);
5460 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005461 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305462 mmc->clk_gated = true;
5463 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5464 mmc_set_ios(mmc);
5465 mmc_host_clk_release(mmc);
Steve Mucklef132c6c2012-06-06 18:30:57 -07005466#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005467 }
5468 }
5469 host->sdcc_suspending = 0;
5470 mmc->suspend_task = NULL;
5471 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5472 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005473 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305474 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305475out:
5476 /* set bus bandwidth to 0 immediately */
5477 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005478 return rc;
5479}
5480
5481static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005482msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005483{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005484 struct mmc_host *mmc = dev_get_drvdata(dev);
5485 struct msmsdcc_host *host = mmc_priv(mmc);
5486 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005488 if (host->plat->is_sdio_al_client)
5489 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005490
Sahitya Tummala7661a452011-07-18 13:28:35 +05305491 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005492 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305493 if (mmc->card && mmc_card_sdio(mmc->card) &&
5494 mmc_card_keep_power(mmc)) {
5495 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305496 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305497 mmc_set_ios(mmc);
5498 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305499 }
San Mehat9d2bd732009-09-22 16:44:22 -07005500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005501 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005503 /*
5504 * FIXME: Clearing of flags must be handled in clients
5505 * resume handler.
5506 */
5507 spin_lock_irqsave(&host->lock, flags);
5508 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305509 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005510 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07005511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005512 /*
5513 * After resuming the host wait for sometime so that
5514 * the SDIO work will be processed.
5515 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305516 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305517 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005518 host->plat->sdiowakeup_irq) &&
5519 wake_lock_active(&host->sdio_wlock))
5520 wake_lock_timeout(&host->sdio_wlock, 1);
5521 }
5522
5523 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005524 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305525 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005526 return 0;
5527}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005528
5529static int msmsdcc_runtime_idle(struct device *dev)
5530{
5531 struct mmc_host *mmc = dev_get_drvdata(dev);
5532 struct msmsdcc_host *host = mmc_priv(mmc);
5533
5534 if (host->plat->is_sdio_al_client)
5535 return 0;
5536
5537 /* Idle timeout is not configurable for now */
5538 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5539
5540 return -EAGAIN;
5541}
5542
5543static int msmsdcc_pm_suspend(struct device *dev)
5544{
5545 struct mmc_host *mmc = dev_get_drvdata(dev);
5546 struct msmsdcc_host *host = mmc_priv(mmc);
5547 int rc = 0;
5548
5549 if (host->plat->is_sdio_al_client)
5550 return 0;
5551
5552
5553 if (host->plat->status_irq)
5554 disable_irq(host->plat->status_irq);
5555
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005556 if (!pm_runtime_suspended(dev))
5557 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005558
5559 return rc;
5560}
5561
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305562static int msmsdcc_suspend_noirq(struct device *dev)
5563{
5564 struct mmc_host *mmc = dev_get_drvdata(dev);
5565 struct msmsdcc_host *host = mmc_priv(mmc);
5566 int rc = 0;
5567
5568 /*
5569 * After platform suspend there may be active request
5570 * which might have enabled clocks. For example, in SDIO
5571 * case, ksdioirq thread might have scheduled after sdcc
5572 * suspend but before system freeze. In that case abort
5573 * suspend and retry instead of keeping the clocks on
5574 * during suspend and not allowing TCXO.
5575 */
5576
Asutosh Dasf5298c32012-04-03 14:51:47 +05305577 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305578 pr_warn("%s: clocks are on after suspend, aborting system "
5579 "suspend\n", mmc_hostname(mmc));
5580 rc = -EAGAIN;
5581 }
5582
5583 return rc;
5584}
5585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005586static int msmsdcc_pm_resume(struct device *dev)
5587{
5588 struct mmc_host *mmc = dev_get_drvdata(dev);
5589 struct msmsdcc_host *host = mmc_priv(mmc);
5590 int rc = 0;
5591
5592 if (host->plat->is_sdio_al_client)
5593 return 0;
5594
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005595 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305596 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005597 else
5598 host->pending_resume = true;
5599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005600 if (host->plat->status_irq) {
5601 msmsdcc_check_status((unsigned long)host);
5602 enable_irq(host->plat->status_irq);
5603 }
5604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005605 return rc;
5606}
5607
Daniel Walker08ecfde2010-06-23 12:32:20 -07005608#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005609static int msmsdcc_runtime_suspend(struct device *dev)
5610{
5611 return 0;
5612}
5613static int msmsdcc_runtime_idle(struct device *dev)
5614{
5615 return 0;
5616}
5617static int msmsdcc_pm_suspend(struct device *dev)
5618{
5619 return 0;
5620}
5621static int msmsdcc_pm_resume(struct device *dev)
5622{
5623 return 0;
5624}
5625static int msmsdcc_suspend_noirq(struct device *dev)
5626{
5627 return 0;
5628}
5629static int msmsdcc_runtime_resume(struct device *dev)
5630{
5631 return 0;
5632}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005633#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005635static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5636 .runtime_suspend = msmsdcc_runtime_suspend,
5637 .runtime_resume = msmsdcc_runtime_resume,
5638 .runtime_idle = msmsdcc_runtime_idle,
5639 .suspend = msmsdcc_pm_suspend,
5640 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305641 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005642};
5643
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305644static const struct of_device_id msmsdcc_dt_match[] = {
5645 {.compatible = "qcom,msm-sdcc"},
5646
5647};
5648MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5649
San Mehat9d2bd732009-09-22 16:44:22 -07005650static struct platform_driver msmsdcc_driver = {
5651 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005652 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005653 .driver = {
5654 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005655 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305656 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005657 },
5658};
5659
5660static int __init msmsdcc_init(void)
5661{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005662#if defined(CONFIG_DEBUG_FS)
5663 int ret = 0;
5664 ret = msmsdcc_dbg_init();
5665 if (ret) {
5666 pr_err("Failed to create debug fs dir \n");
5667 return ret;
5668 }
5669#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005670 return platform_driver_register(&msmsdcc_driver);
5671}
San Mehat9d2bd732009-09-22 16:44:22 -07005672
San Mehat9d2bd732009-09-22 16:44:22 -07005673static void __exit msmsdcc_exit(void)
5674{
5675 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005676
5677#if defined(CONFIG_DEBUG_FS)
5678 debugfs_remove(debugfs_file);
5679 debugfs_remove(debugfs_dir);
5680#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005681}
5682
5683module_init(msmsdcc_init);
5684module_exit(msmsdcc_exit);
5685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005686MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005687MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005688
5689#if defined(CONFIG_DEBUG_FS)
5690
5691static int
5692msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5693{
5694 file->private_data = inode->i_private;
5695 return 0;
5696}
5697
5698static ssize_t
5699msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5700 size_t count, loff_t *ppos)
5701{
5702 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005703 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005704 int max, i;
5705
5706 i = 0;
5707 max = sizeof(buf) - 1;
5708
5709 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5710 host->curr.cmd, host->curr.data);
5711 if (host->curr.cmd) {
5712 struct mmc_command *cmd = host->curr.cmd;
5713
5714 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5715 cmd->opcode, cmd->arg, cmd->flags);
5716 }
5717 if (host->curr.data) {
5718 struct mmc_data *data = host->curr.data;
5719 i += scnprintf(buf + i, max - i,
5720 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5721 data->timeout_ns, data->timeout_clks,
5722 data->blksz, data->blocks, data->error,
5723 data->flags);
5724 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5725 host->curr.xfer_size, host->curr.xfer_remain,
5726 host->curr.data_xfered, host->dma.sg);
5727 }
5728
5729 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5730}
5731
5732static const struct file_operations msmsdcc_dbg_state_ops = {
5733 .read = msmsdcc_dbg_state_read,
5734 .open = msmsdcc_dbg_state_open,
5735};
5736
5737static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5738{
5739 if (debugfs_dir) {
5740 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5741 0644, debugfs_dir, host,
5742 &msmsdcc_dbg_state_ops);
5743 }
5744}
5745
5746static int __init msmsdcc_dbg_init(void)
5747{
5748 int err;
5749
5750 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5751 if (IS_ERR(debugfs_dir)) {
5752 err = PTR_ERR(debugfs_dir);
5753 debugfs_dir = NULL;
5754 return err;
5755 }
5756
5757 return 0;
5758}
5759#endif