blob: 02d15816b799eba713c6d7b8d2513a02cbe19a46 [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 Jadavani7a651aa2011-08-03 20:44:58 +0530379 host->curr.wait_for_auto_prog_done = 0;
380 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700381 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
382 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530383 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700384}
385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700387{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 return host->core_memres->start + MMCIFIFO;
389}
390
391static inline unsigned int msmsdcc_get_min_sup_clk_rate(
392 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530393
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395{
396 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530397 if (!host->sdcc_version)
398 udelay(host->reg_write_delay);
399 else if (readl_relaxed(host->base + MCI_STATUS2) &
400 MCI_MCLK_REG_WR_ACTIVE) {
401 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530402
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530403 start = ktime_get();
404 while (readl_relaxed(host->base + MCI_STATUS2) &
405 MCI_MCLK_REG_WR_ACTIVE) {
406 diff = ktime_sub(ktime_get(), start);
407 /* poll for max. 1 ms */
408 if (ktime_to_us(diff) > 1000) {
409 pr_warning("%s: previous reg. write is"
410 " still active\n",
411 mmc_hostname(host->mmc));
412 break;
413 }
414 }
415 }
San Mehat9d2bd732009-09-22 16:44:22 -0700416}
417
Subhash Jadavanidd432952012-03-28 11:25:56 +0530418static inline void msmsdcc_delay(struct msmsdcc_host *host)
419{
420 udelay(host->reg_write_delay);
421
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 Jadavani7a651aa2011-08-03 20:44:58 +05301121 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001122
San Mehat9d2bd732009-09-22 16:44:22 -07001123 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1124
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301125 if (host->curr.wait_for_auto_prog_done)
1126 datactrl |= MCI_AUTO_PROG_DONE;
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 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1178 /* Use ADM (Application Data Mover) HW for Data transfer */
1179 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001180 host->cmd_timeout = timeout;
1181 host->cmd_pio_irqmask = pio_irqmask;
1182 host->cmd_datactrl = datactrl;
1183 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1186 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001187 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001188
1189 if (cmd) {
1190 msmsdcc_start_command_deferred(host, cmd, &c);
1191 host->cmd_c = c;
1192 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1194 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1195 host->base + MMCIMASK0);
1196 mb();
1197 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001198 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1205 (~(MCI_IRQ_PIO))) | pio_irqmask,
1206 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001208
1209 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301210 /* Delay between data/command */
1211 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001212 /* Daisy-chain the command if requested */
1213 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301214 } else {
1215 /*
1216 * We don't need delay after writing to DATA_CTRL
1217 * register if we are not writing to CMD register
1218 * immediately after this. As we already have delay
1219 * before sending the command, we just need mb() here.
1220 */
1221 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001222 }
San Mehat9d2bd732009-09-22 16:44:22 -07001223 }
1224}
1225
1226static void
1227msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1228{
San Mehat56a8b5b2009-11-21 12:29:46 -08001229 msmsdcc_start_command_deferred(host, cmd, &c);
1230 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001231}
1232
1233static void
1234msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1235 unsigned int status)
1236{
1237 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301239 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1240 || data->mrq->cmd->opcode ==
1241 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 pr_err("%s: Data CRC error\n",
1243 mmc_hostname(host->mmc));
1244 pr_err("%s: opcode 0x%.8x\n", __func__,
1245 data->mrq->cmd->opcode);
1246 pr_err("%s: blksz %d, blocks %d\n", __func__,
1247 data->blksz, data->blocks);
1248 data->error = -EILSEQ;
1249 }
San Mehat9d2bd732009-09-22 16:44:22 -07001250 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 /* CRC is optional for the bus test commands, not all
1252 * cards respond back with CRC. However controller
1253 * waits for the CRC and times out. Hence ignore the
1254 * data timeouts during the Bustest.
1255 */
1256 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1257 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301258 pr_err("%s: CMD%d: Data timeout\n",
1259 mmc_hostname(host->mmc),
1260 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301262 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 }
San Mehat9d2bd732009-09-22 16:44:22 -07001264 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001265 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001266 data->error = -EIO;
1267 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001268 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001269 data->error = -EIO;
1270 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001271 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001273 data->error = -EIO;
1274 }
San Mehat9d2bd732009-09-22 16:44:22 -07001275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001277 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 host->dummy_52_needed = 0;
1279}
San Mehat9d2bd732009-09-22 16:44:22 -07001280
1281static int
1282msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1283{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001285 uint32_t *ptr = (uint32_t *) buffer;
1286 int count = 0;
1287
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301288 if (remain % 4)
1289 remain = ((remain >> 2) + 1) << 2;
1290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1292
1293 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001294 ptr++;
1295 count += sizeof(uint32_t);
1296
1297 remain -= sizeof(uint32_t);
1298 if (remain == 0)
1299 break;
1300 }
1301 return count;
1302}
1303
1304static int
1305msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001307{
1308 void __iomem *base = host->base;
1309 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 while (readl_relaxed(base + MMCISTATUS) &
1313 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1314 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001315
San Mehat9d2bd732009-09-22 16:44:22 -07001316 count = min(remain, maxcnt);
1317
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301318 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1319 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001320 ptr += count;
1321 remain -= count;
1322
1323 if (remain == 0)
1324 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 }
1326 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001327
1328 return ptr - buffer;
1329}
1330
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001331/*
1332 * Copy up to a word (4 bytes) between a scatterlist
1333 * and a temporary bounce buffer when the word lies across
1334 * two pages. The temporary buffer can then be read to/
1335 * written from the FIFO once.
1336 */
1337static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -07001338{
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001339 struct msmsdcc_pio_data *pio = &host->pio;
1340 unsigned int bytes_avail;
1341
1342 if (host->curr.data->flags & MMC_DATA_READ)
1343 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1344 pio->bounce_buf_len);
1345 else
1346 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1347 pio->bounce_buf_len);
1348
1349 while (pio->bounce_buf_len != 4) {
1350 if (!sg_miter_next(&pio->sg_miter))
1351 break;
1352 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1353 4 - pio->bounce_buf_len);
1354 if (host->curr.data->flags & MMC_DATA_READ)
1355 memcpy(pio->sg_miter.addr,
1356 &pio->bounce_buf[pio->bounce_buf_len],
1357 bytes_avail);
1358 else
1359 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1360 pio->sg_miter.addr, bytes_avail);
1361
1362 pio->sg_miter.consumed = bytes_avail;
1363 pio->bounce_buf_len += bytes_avail;
San Mehat9d2bd732009-09-22 16:44:22 -07001364 }
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001365}
1366
1367/*
1368 * Use sg_miter_next to return as many 4-byte aligned
1369 * chunks as possible, using a temporary 4 byte buffer
1370 * for alignment if necessary
1371 */
1372static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1373{
1374 struct msmsdcc_pio_data *pio = &host->pio;
1375 unsigned int length, rlength;
1376 char *buffer;
1377
1378 if (!sg_miter_next(&pio->sg_miter))
1379 return 0;
1380
1381 buffer = pio->sg_miter.addr;
1382 length = pio->sg_miter.length;
1383
1384 if (length < host->curr.xfer_remain) {
1385 rlength = round_down(length, 4);
1386 if (rlength) {
1387 /*
1388 * We have a 4-byte aligned chunk.
1389 * The rounding will be reflected by
1390 * a call to msmsdcc_sg_consumed
1391 */
1392 length = rlength;
1393 goto sg_next_end;
1394 }
1395 /*
1396 * We have a length less than 4 bytes. Check to
1397 * see if more buffer is available, and combine
1398 * to make 4 bytes if possible.
1399 */
1400 pio->bounce_buf_len = length;
1401 memset(pio->bounce_buf, 0, 4);
1402
1403 /*
1404 * On a read, get 4 bytes from FIFO, and distribute
1405 * (4-bouce_buf_len) bytes into consecutive
1406 * sgl buffers when msmsdcc_sg_consumed is called
1407 */
1408 if (host->curr.data->flags & MMC_DATA_READ) {
1409 buffer = pio->bounce_buf;
1410 length = 4;
1411 goto sg_next_end;
1412 } else {
1413 _msmsdcc_sg_consume_word(host);
1414 buffer = pio->bounce_buf;
1415 length = pio->bounce_buf_len;
1416 }
1417 }
1418
1419sg_next_end:
1420 *buf = buffer;
1421 *len = length;
1422 return 1;
1423}
1424
1425/*
1426 * Update sg_miter.consumed based on how many bytes were
1427 * consumed. If the bounce buffer was used to read from FIFO,
1428 * redistribute into sgls.
1429 */
1430static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1431 unsigned int length)
1432{
1433 struct msmsdcc_pio_data *pio = &host->pio;
1434
1435 if (host->curr.data->flags & MMC_DATA_READ) {
1436 if (length > pio->sg_miter.consumed)
1437 /*
1438 * consumed 4 bytes, but sgl
1439 * describes < 4 bytes
1440 */
1441 _msmsdcc_sg_consume_word(host);
1442 else
1443 pio->sg_miter.consumed = length;
1444 } else
1445 if (length < pio->sg_miter.consumed)
1446 pio->sg_miter.consumed = length;
1447}
1448
1449static void msmsdcc_sg_start(struct msmsdcc_host *host)
1450{
1451 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1452
1453 host->pio.bounce_buf_len = 0;
1454
1455 if (host->curr.data->flags & MMC_DATA_READ)
1456 sg_miter_flags |= SG_MITER_TO_SG;
1457 else
1458 sg_miter_flags |= SG_MITER_FROM_SG;
1459
1460 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1461 host->curr.data->sg_len, sg_miter_flags);
1462}
1463
1464static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1465{
1466 sg_miter_stop(&host->pio.sg_miter);
San Mehat9d2bd732009-09-22 16:44:22 -07001467}
1468
San Mehat1cd22962010-02-03 12:59:29 -08001469static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001470msmsdcc_pio_irq(int irq, void *dev_id)
1471{
1472 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001474 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001475 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001476 unsigned int remain;
1477 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001478
Murali Palnati36448a42011-09-02 15:06:18 +05301479 spin_lock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301484 (MCI_IRQ_PIO)) == 0) {
1485 spin_unlock(&host->lock);
Sahitya Tummala4a268e02011-05-02 18:09:18 +05301486 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488#if IRQ_DEBUG
1489 msmsdcc_print_status(host, "irq1-r", status);
1490#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001491 local_irq_save(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001492
1493 do {
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001494 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1497 | MCI_RXDATAAVLBL)))
1498 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001499
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001500 if (!msmsdcc_sg_next(host, &buffer, &remain))
1501 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001502
San Mehat9d2bd732009-09-22 16:44:22 -07001503 len = 0;
1504 if (status & MCI_RXACTIVE)
1505 len = msmsdcc_pio_read(host, buffer, remain);
1506 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001508
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301509 /* len might have aligned to 32bits above */
1510 if (len > remain)
1511 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001512
San Mehat9d2bd732009-09-22 16:44:22 -07001513 host->curr.xfer_remain -= len;
1514 host->curr.data_xfered += len;
1515 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001516 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 if (remain) /* Done with this page? */
1519 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001522 } while (1);
1523
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001524 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001525 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1528 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1529 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1530 host->base + MMCIMASK0);
1531 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301532 /*
1533 * back to back write to MASK0 register don't need
1534 * synchronization delay.
1535 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1537 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1538 }
1539 mb();
1540 } else if (!host->curr.xfer_remain) {
1541 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1542 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1543 mb();
1544 }
San Mehat9d2bd732009-09-22 16:44:22 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001547
1548 return IRQ_HANDLED;
1549}
1550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551static void
1552msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1553
1554static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1555 struct mmc_data *data)
1556{
1557 u32 loop_cnt = 0;
1558
1559 /*
1560 * For read commands with data less than fifo size, it is possible to
1561 * get DATAEND first and RXDATA_AVAIL might be set later because of
1562 * synchronization delay through the asynchronous RX FIFO. Thus, for
1563 * such cases, even after DATAEND interrupt is received software
1564 * should poll for RXDATA_AVAIL until the requested data is read out
1565 * of FIFO. This change is needed to get around this abnormal but
1566 * sometimes expected behavior of SDCC3 controller.
1567 *
1568 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1569 * after the data is loaded into RX FIFO. This would amount to less
1570 * than a microsecond and thus looping for 1000 times is good enough
1571 * for that delay.
1572 */
1573 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1574 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1575 spin_unlock(&host->lock);
1576 msmsdcc_pio_irq(1, host);
1577 spin_lock(&host->lock);
1578 }
1579 }
1580 if (loop_cnt == 1000) {
1581 pr_info("%s: Timed out while polling for Rx Data\n",
1582 mmc_hostname(host->mmc));
1583 data->error = -ETIMEDOUT;
1584 msmsdcc_reset_and_restore(host);
1585 }
1586}
1587
San Mehat9d2bd732009-09-22 16:44:22 -07001588static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1589{
1590 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001591
1592 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301593 if (mmc_resp_type(cmd))
1594 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1595 /*
1596 * Read rest of the response registers only if
1597 * long response is expected for this command
1598 */
1599 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1600 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1601 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1602 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1603 }
San Mehat9d2bd732009-09-22 16:44:22 -07001604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301606 pr_debug("%s: CMD%d: Command timeout\n",
1607 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001608 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301610 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301611 pr_err("%s: CMD%d: Command CRC error\n",
1612 mmc_hostname(host->mmc), cmd->opcode);
1613 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001614 cmd->error = -EILSEQ;
1615 }
1616
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301617 if (!cmd->error) {
1618 if (cmd->cmd_timeout_ms > host->curr.req_tout_ms) {
1619 host->curr.req_tout_ms = cmd->cmd_timeout_ms;
1620 mod_timer(&host->req_tout_timer, (jiffies +
1621 msecs_to_jiffies(host->curr.req_tout_ms)));
1622 }
1623 }
1624
San Mehat9d2bd732009-09-22 16:44:22 -07001625 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 if (host->curr.data && host->dma.sg &&
1627 host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001628 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 else if (host->curr.data && host->sps.sg &&
1630 host->is_sps_mode){
1631 /* Stop current SPS transfer */
1632 msmsdcc_sps_exit_curr_xfer(host);
1633 }
San Mehat9d2bd732009-09-22 16:44:22 -07001634 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301635 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001636 msmsdcc_stop_data(host);
1637 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301638 } else { /* host->data == NULL */
1639 if (!cmd->error && host->prog_enable) {
1640 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 host->prog_enable = 0;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301642 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301644 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301645 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301646 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301647 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001648 if (host->dummy_52_needed)
1649 host->dummy_52_needed = 0;
1650 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301652 msmsdcc_request_end(host, cmd->mrq);
1653 }
1654 }
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301655 } else if (cmd->data) {
Subhash Jadavanif5277752011-10-12 16:47:52 +05301656 if (cmd == host->curr.mrq->sbc)
1657 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1658 else if ((cmd->data->flags & MMC_DATA_WRITE) &&
1659 !host->curr.use_wr_data_pend)
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301660 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001661 }
1662}
1663
San Mehat9d2bd732009-09-22 16:44:22 -07001664static irqreturn_t
1665msmsdcc_irq(int irq, void *dev_id)
1666{
1667 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001668 u32 status;
1669 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001671
1672 spin_lock(&host->lock);
1673
1674 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 struct mmc_command *cmd;
1676 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 if (timer) {
1679 timer = 0;
1680 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001681 }
San Mehat9d2bd732009-09-22 16:44:22 -07001682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 if (!host->clks_on) {
1684 pr_debug("%s: %s: SDIO async irq received\n",
1685 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301686
1687 /*
1688 * Only async interrupt can come when clocks are off,
1689 * disable further interrupts and enable them when
1690 * clocks are on.
1691 */
1692 if (!host->sdcc_irq_disabled) {
1693 disable_irq_nosync(irq);
1694 host->sdcc_irq_disabled = 1;
1695 }
1696
1697 /*
1698 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1699 * will take care of signaling sdio irq during
1700 * mmc_sdio_resume().
1701 */
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301702 if (host->sdcc_suspended) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301703 /*
1704 * This is a wakeup interrupt so hold wakelock
1705 * until SDCC resume is handled.
1706 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301708 } else {
1709 spin_unlock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301710 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301711 spin_lock(&host->lock);
1712 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301713 ret = 1;
1714 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715 }
1716
1717 status = readl_relaxed(host->base + MMCISTATUS);
1718
1719 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1720 (~(MCI_IRQ_PIO))) == 0)
San Mehat9d2bd732009-09-22 16:44:22 -07001721 break;
1722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723#if IRQ_DEBUG
1724 msmsdcc_print_status(host, "irq0-r", status);
1725#endif
1726 status &= readl_relaxed(host->base + MMCIMASK0);
1727 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301728 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301729 if (host->clk_rate <=
1730 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301731 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732#if IRQ_DEBUG
1733 msmsdcc_print_status(host, "irq0-p", status);
1734#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 if (status & MCI_SDIOINTROPE) {
1737 if (host->sdcc_suspending)
1738 wake_lock(&host->sdio_suspend_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301739 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05301741 spin_lock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001742 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001743 data = host->curr.data;
1744
1745 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1747 MCI_CMDTIMEOUT)) {
1748 if (status & MCI_CMDTIMEOUT)
1749 pr_debug("%s: dummy CMD52 timeout\n",
1750 mmc_hostname(host->mmc));
1751 if (status & MCI_CMDCRCFAIL)
1752 pr_debug("%s: dummy CMD52 CRC failed\n",
1753 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001754 host->dummy_52_sent = 0;
1755 host->dummy_52_needed = 0;
1756 if (data) {
1757 msmsdcc_stop_data(host);
1758 msmsdcc_request_end(host, data->mrq);
1759 }
1760 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 spin_unlock(&host->lock);
1762 return IRQ_HANDLED;
1763 }
1764 break;
1765 }
1766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 /*
1768 * Check for proper command response
1769 */
1770 cmd = host->curr.cmd;
1771 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1772 MCI_CMDTIMEOUT | MCI_PROGDONE |
1773 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1774 msmsdcc_do_cmdirq(host, status);
1775 }
1776
Sathish Ambley081d7842011-11-29 11:19:41 -08001777 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 /* Check for data errors */
1779 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1780 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1781 msmsdcc_data_err(host, data, status);
1782 host->curr.data_xfered = 0;
1783 if (host->dma.sg && host->is_dma_mode)
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07001784 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 else if (host->sps.sg && host->is_sps_mode) {
1786 /* Stop current SPS transfer */
1787 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301788 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001789 msmsdcc_reset_and_restore(host);
1790 if (host->curr.data)
1791 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301792 if (!data->stop || (host->curr.mrq->sbc
1793 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 timer |=
1795 msmsdcc_request_end(host,
1796 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301797 else if ((host->curr.mrq->sbc
1798 && data->error) ||
1799 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 msmsdcc_start_command(host,
1801 data->stop,
1802 0);
1803 timer = 1;
1804 }
1805 }
1806 }
1807
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301808 /* Check for prog done */
1809 if (host->curr.wait_for_auto_prog_done &&
1810 (status & MCI_PROGDONE))
1811 host->curr.got_auto_prog_done = 1;
1812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 /* Check for data done */
1814 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1815 host->curr.got_dataend = 1;
1816
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301817 if (host->curr.got_dataend &&
1818 (!host->curr.wait_for_auto_prog_done ||
1819 (host->curr.wait_for_auto_prog_done &&
1820 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 /*
1822 * If DMA is still in progress, we complete
1823 * via the completion handler
1824 */
1825 if (!host->dma.busy && !host->sps.busy) {
1826 /*
1827 * There appears to be an issue in the
1828 * controller where if you request a
1829 * small block transfer (< fifo size),
1830 * you may get your DATAEND/DATABLKEND
1831 * irq without the PIO data irq.
1832 *
1833 * Check to see if theres still data
1834 * to be read, and simulate a PIO irq.
1835 */
1836 if (data->flags & MMC_DATA_READ)
1837 msmsdcc_wait_for_rxdata(host,
1838 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 if (!data->error) {
1840 host->curr.data_xfered =
1841 host->curr.xfer_size;
1842 host->curr.xfer_remain -=
1843 host->curr.xfer_size;
1844 }
1845
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001846 if (!host->dummy_52_needed) {
1847 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301848 if (!data->stop ||
1849 (host->curr.mrq->sbc
1850 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001851 msmsdcc_request_end(
1852 host,
1853 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301854 else if ((host->curr.mrq->sbc
1855 && data->error) ||
1856 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001857 msmsdcc_start_command(
1858 host,
1859 data->stop, 0);
1860 timer = 1;
1861 }
1862 } else {
1863 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001865 &dummy52cmd,
1866 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 }
1868 }
1869 }
1870 }
1871
San Mehat9d2bd732009-09-22 16:44:22 -07001872 ret = 1;
1873 } while (status);
1874
1875 spin_unlock(&host->lock);
1876
San Mehat9d2bd732009-09-22 16:44:22 -07001877 return IRQ_RETVAL(ret);
1878}
1879
1880static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301881msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1882 bool is_first_request)
1883{
1884 struct msmsdcc_host *host = mmc_priv(mmc);
1885 struct mmc_data *data = mrq->data;
1886 int rc = 0;
1887
1888 if (unlikely(!data)) {
1889 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1890 __func__);
1891 return;
1892 }
1893 if (unlikely(data->host_cookie)) {
1894 /* Very wrong */
1895 data->host_cookie = 0;
1896 pr_err("%s: %s Request reposted for prepare\n",
1897 mmc_hostname(mmc), __func__);
1898 return;
1899 }
1900
1901 if (!msmsdcc_is_dma_possible(host, data))
1902 return;
1903
1904 rc = msmsdcc_prep_xfer(host, data);
1905 if (unlikely(rc < 0)) {
1906 data->host_cookie = 0;
1907 return;
1908 }
1909
1910 data->host_cookie = 1;
1911}
1912
1913static void
1914msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1915{
1916 struct msmsdcc_host *host = mmc_priv(mmc);
1917 unsigned int dir;
1918 struct mmc_data *data = mrq->data;
1919
1920 if (unlikely(!data)) {
1921 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1922 __func__);
1923 return;
1924 }
1925 if (data->flags & MMC_DATA_READ)
1926 dir = DMA_FROM_DEVICE;
1927 else
1928 dir = DMA_TO_DEVICE;
1929
1930 if (data->host_cookie)
1931 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1932 data->sg_len, dir);
1933
1934 data->host_cookie = 0;
1935}
1936
1937static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001938msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1939{
Subhash Jadavanif5277752011-10-12 16:47:52 +05301940 if (mrq->data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 /* Queue/read data, daisy-chain command when data starts */
Subhash Jadavanif5277752011-10-12 16:47:52 +05301942 if ((mrq->data->flags & MMC_DATA_READ) ||
1943 host->curr.use_wr_data_pend)
1944 msmsdcc_start_data(host, mrq->data,
1945 mrq->sbc ? mrq->sbc : mrq->cmd,
1946 0);
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301947 else
Subhash Jadavanif5277752011-10-12 16:47:52 +05301948 msmsdcc_start_command(host,
1949 mrq->sbc ? mrq->sbc : mrq->cmd,
1950 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 } else {
1952 msmsdcc_start_command(host, mrq->cmd, 0);
1953 }
1954}
1955
1956static void
San Mehat9d2bd732009-09-22 16:44:22 -07001957msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1958{
1959 struct msmsdcc_host *host = mmc_priv(mmc);
Subhash Jadavani8706ced2012-05-25 16:09:21 +05301960 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 /*
1963 * Get the SDIO AL client out of LPM.
1964 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001965 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 if (host->plat->is_sdio_al_client)
1967 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001968
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301969 /* check if sps pipe reset is pending? */
1970 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1971 msmsdcc_sps_pipes_reset_and_restore(host);
1972 host->sps.pipe_reset_pending = false;
1973 }
San Mehat9d2bd732009-09-22 16:44:22 -07001974
1975 spin_lock_irqsave(&host->lock, flags);
1976
San Mehat9d2bd732009-09-22 16:44:22 -07001977 if (host->eject) {
1978 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1979 mrq->cmd->error = 0;
1980 mrq->data->bytes_xfered = mrq->data->blksz *
1981 mrq->data->blocks;
1982 } else
1983 mrq->cmd->error = -ENOMEDIUM;
1984
1985 spin_unlock_irqrestore(&host->lock, flags);
1986 mmc_request_done(mmc, mrq);
1987 return;
1988 }
1989
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301990 /*
subhashjf181c292012-05-02 13:07:40 +05301991 * Don't start the request if SDCC is not in proper state to handle it
1992 */
1993 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1994 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1995 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1996 __func__, mrq->cmd->opcode);
1997 msmsdcc_dump_sdcc_state(host);
1998 mrq->cmd->error = -EIO;
1999 if (mrq->data) {
2000 mrq->data->error = -EIO;
2001 mrq->data->bytes_xfered = 0;
2002 }
2003 spin_unlock_irqrestore(&host->lock, flags);
2004 mmc_request_done(mmc, mrq);
2005 return;
2006 }
2007
2008 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
2009 " other request (CMD%d) is in progress\n",
2010 mmc_hostname(host->mmc), __func__,
2011 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
2012
2013 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302014 * Set timeout value to 10 secs (or more in case of buggy cards)
2015 */
2016 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302017 host->curr.req_tout_ms = 20000;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302018 else
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302019 host->curr.req_tout_ms = MSM_MMC_REQ_TIMEOUT;
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302020 /*
2021 * Kick the software request timeout timer here with the timeout
2022 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302023 */
2024 mod_timer(&host->req_tout_timer,
Subhash Jadavani8706ced2012-05-25 16:09:21 +05302025 (jiffies +
2026 msecs_to_jiffies(host->curr.req_tout_ms)));
San Mehat9d2bd732009-09-22 16:44:22 -07002027
San Mehat9d2bd732009-09-22 16:44:22 -07002028 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302029 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302030 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
2031 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05302032 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302034 else
2035 /*
2036 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
2037 * write operations using CMD53 and CMD54.
2038 * Setting this bit with CMD53 would
2039 * automatically triggers PROG_DONE interrupt
2040 * without the need of sending dummy CMD52.
2041 */
2042 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05302043 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
2044 host->sdcc_version) {
2045 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302047 if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
2048 (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
2049 host->curr.use_wr_data_pend = true;
San Mehat9d2bd732009-09-22 16:44:22 -07002050 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302051
Pratibhasagar V00b94332011-10-18 14:57:27 +05302052 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302053 mrq->sbc->mrq = mrq;
2054 mrq->sbc->data = mrq->data;
Subhash Jadavanif5277752011-10-12 16:47:52 +05302055 if (mrq->data->flags & MMC_DATA_WRITE)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302056 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302057 }
Subhash Jadavanif5277752011-10-12 16:47:52 +05302058 msmsdcc_request_start(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302059
San Mehat9d2bd732009-09-22 16:44:22 -07002060 spin_unlock_irqrestore(&host->lock, flags);
2061}
2062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002063static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2064 int min_uV, int max_uV)
2065{
2066 int rc = 0;
2067
2068 if (vreg->set_voltage_sup) {
2069 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2070 if (rc) {
2071 pr_err("%s: regulator_set_voltage(%s) failed."
2072 " min_uV=%d, max_uV=%d, rc=%d\n",
2073 __func__, vreg->name, min_uV, max_uV, rc);
2074 }
2075 }
2076
2077 return rc;
2078}
2079
2080static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2081 int uA_load)
2082{
2083 int rc = 0;
2084
Krishna Kondafea60182011-11-01 16:01:34 -07002085 /* regulators that do not support regulator_set_voltage also
2086 do not support regulator_set_optimum_mode */
2087 if (vreg->set_voltage_sup) {
2088 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2089 if (rc < 0)
2090 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2091 "uA_load=%d) failed. rc=%d\n", __func__,
2092 vreg->name, uA_load, rc);
2093 else
2094 /* regulator_set_optimum_mode() can return non zero
2095 * value even for success case.
2096 */
2097 rc = 0;
2098 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099
2100 return rc;
2101}
2102
2103static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2104 struct device *dev)
2105{
2106 int rc = 0;
2107
2108 /* check if regulator is already initialized? */
2109 if (vreg->reg)
2110 goto out;
2111
2112 /* Get the regulator handle */
2113 vreg->reg = regulator_get(dev, vreg->name);
2114 if (IS_ERR(vreg->reg)) {
2115 rc = PTR_ERR(vreg->reg);
2116 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2117 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002118 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002120
2121 if (regulator_count_voltages(vreg->reg) > 0)
2122 vreg->set_voltage_sup = 1;
2123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124out:
2125 return rc;
2126}
2127
2128static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2129{
2130 if (vreg->reg)
2131 regulator_put(vreg->reg);
2132}
2133
2134/* This init function should be called only once for each SDCC slot */
2135static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2136{
2137 int rc = 0;
2138 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302139 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140 struct device *dev = mmc_dev(host->mmc);
2141
2142 curr_slot = host->plat->vreg_data;
2143 if (!curr_slot)
2144 goto out;
2145
2146 curr_vdd_reg = curr_slot->vdd_data;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302147 curr_vdd_io_reg = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148
2149 if (is_init) {
2150 /*
2151 * Get the regulator handle from voltage regulator framework
2152 * and then try to set the voltage level for the regulator
2153 */
2154 if (curr_vdd_reg) {
2155 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2156 if (rc)
2157 goto out;
2158 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302159 if (curr_vdd_io_reg) {
2160 rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161 if (rc)
2162 goto vdd_reg_deinit;
2163 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002164 rc = msmsdcc_vreg_reset(host);
2165 if (rc)
2166 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2167 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168 goto out;
2169 } else {
2170 /* Deregister all regulators from regulator framework */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302171 goto vdd_io_reg_deinit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002172 }
Subhash Jadavani937c7502012-06-01 15:34:46 +05302173vdd_io_reg_deinit:
2174 if (curr_vdd_io_reg)
2175 msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176vdd_reg_deinit:
2177 if (curr_vdd_reg)
2178 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2179out:
2180 return rc;
2181}
2182
2183static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2184{
2185 int rc = 0;
2186
Subhash Jadavanicc922692011-08-01 23:05:01 +05302187 /* Put regulator in HPM (high power mode) */
2188 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2189 if (rc < 0)
2190 goto out;
2191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 if (!vreg->is_enabled) {
2193 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302194 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2195 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 if (rc)
2197 goto out;
2198
2199 rc = regulator_enable(vreg->reg);
2200 if (rc) {
2201 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2202 __func__, vreg->name, rc);
2203 goto out;
2204 }
2205 vreg->is_enabled = true;
2206 }
2207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208out:
2209 return rc;
2210}
2211
2212static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2213{
2214 int rc = 0;
2215
2216 /* Never disable regulator marked as always_on */
2217 if (vreg->is_enabled && !vreg->always_on) {
2218 rc = regulator_disable(vreg->reg);
2219 if (rc) {
2220 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2221 __func__, vreg->name, rc);
2222 goto out;
2223 }
2224 vreg->is_enabled = false;
2225
2226 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2227 if (rc < 0)
2228 goto out;
2229
2230 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302231 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 if (rc)
2233 goto out;
2234 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2235 /* Put always_on regulator in LPM (low power mode) */
2236 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2237 if (rc < 0)
2238 goto out;
2239 }
2240out:
2241 return rc;
2242}
2243
2244static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2245{
2246 int rc = 0, i;
2247 struct msm_mmc_slot_reg_data *curr_slot;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302248 struct msm_mmc_reg_data *vreg_table[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249
2250 curr_slot = host->plat->vreg_data;
2251 if (!curr_slot)
2252 goto out;
2253
Subhash Jadavani937c7502012-06-01 15:34:46 +05302254 vreg_table[0] = curr_slot->vdd_data;
2255 vreg_table[1] = curr_slot->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256
2257 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2258 if (vreg_table[i]) {
2259 if (enable)
2260 rc = msmsdcc_vreg_enable(vreg_table[i]);
2261 else
2262 rc = msmsdcc_vreg_disable(vreg_table[i]);
2263 if (rc)
2264 goto out;
2265 }
2266 }
2267out:
2268 return rc;
2269}
2270
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002271/*
2272 * Reset vreg by ensuring it is off during probe. A call
2273 * to enable vreg is needed to balance disable vreg
2274 */
2275static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2276{
2277 int rc;
2278
2279 rc = msmsdcc_setup_vreg(host, 1);
2280 if (rc)
2281 return rc;
2282 rc = msmsdcc_setup_vreg(host, 0);
2283 return rc;
2284}
2285
Subhash Jadavani937c7502012-06-01 15:34:46 +05302286enum vdd_io_level {
2287 /* set vdd_io_data->low_vol_level */
2288 VDD_IO_LOW,
2289 /* set vdd_io_data->high_vol_level */
2290 VDD_IO_HIGH,
2291 /*
2292 * set whatever there in voltage_level (third argument) of
2293 * msmsdcc_set_vdd_io_vol() function.
2294 */
2295 VDD_IO_SET_LEVEL,
2296};
2297
2298static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
2299 enum vdd_io_level level,
2300 unsigned int voltage_level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301{
2302 int rc = 0;
Subhash Jadavani937c7502012-06-01 15:34:46 +05302303 int set_level;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304
2305 if (host->plat->vreg_data) {
Subhash Jadavani937c7502012-06-01 15:34:46 +05302306 struct msm_mmc_reg_data *vdd_io_reg =
2307 host->plat->vreg_data->vdd_io_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002308
Subhash Jadavani937c7502012-06-01 15:34:46 +05302309 if (vdd_io_reg && vdd_io_reg->is_enabled) {
2310 switch (level) {
2311 case VDD_IO_LOW:
2312 set_level = vdd_io_reg->low_vol_level;
2313 break;
2314 case VDD_IO_HIGH:
2315 set_level = vdd_io_reg->high_vol_level;
2316 break;
2317 case VDD_IO_SET_LEVEL:
2318 set_level = voltage_level;
2319 break;
2320 default:
2321 pr_err("%s: %s: invalid argument level = %d",
2322 mmc_hostname(host->mmc), __func__,
2323 level);
2324 rc = -EINVAL;
2325 goto out;
2326 }
2327 rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
2328 set_level, set_level);
2329 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330 }
2331
Subhash Jadavani937c7502012-06-01 15:34:46 +05302332out:
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302333 return rc;
2334}
2335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2337{
2338 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2339 return 1;
2340 return 0;
2341}
2342
Asutosh Dasf5298c32012-04-03 14:51:47 +05302343/*
2344 * Any function calling msmsdcc_setup_clocks must
2345 * acquire clk_mutex. May sleep.
2346 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2348{
2349 if (enable) {
2350 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302351 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302353 clk_prepare_enable(host->pclk);
2354 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302355 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302356 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302358 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302359 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302360 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302362 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302364 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002365 }
2366}
2367
2368static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2369 unsigned int req_clk)
2370{
2371 unsigned int sel_clk = -1;
2372
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302373 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2374 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2375 goto out;
2376 }
2377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2379 unsigned char cnt;
2380
2381 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2382 if (host->plat->sup_clk_table[cnt] > req_clk)
2383 break;
2384 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2385 sel_clk = host->plat->sup_clk_table[cnt];
2386 break;
2387 } else
2388 sel_clk = host->plat->sup_clk_table[cnt];
2389 }
2390 } else {
2391 if ((req_clk < host->plat->msmsdcc_fmax) &&
2392 (req_clk > host->plat->msmsdcc_fmid))
2393 sel_clk = host->plat->msmsdcc_fmid;
2394 else
2395 sel_clk = req_clk;
2396 }
2397
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302398out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 return sel_clk;
2400}
2401
2402static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2403 struct msmsdcc_host *host)
2404{
2405 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2406 return host->plat->sup_clk_table[0];
2407 else
2408 return host->plat->msmsdcc_fmin;
2409}
2410
2411static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2412 struct msmsdcc_host *host)
2413{
2414 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2415 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2416 else
2417 return host->plat->msmsdcc_fmax;
2418}
2419
2420static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302421{
2422 struct msm_mmc_gpio_data *curr;
2423 int i, rc = 0;
2424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302426 for (i = 0; i < curr->size; i++) {
2427 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 if (curr->gpio[i].is_always_on &&
2429 curr->gpio[i].is_enabled)
2430 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302431 rc = gpio_request(curr->gpio[i].no,
2432 curr->gpio[i].name);
2433 if (rc) {
2434 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2435 mmc_hostname(host->mmc),
2436 curr->gpio[i].no,
2437 curr->gpio[i].name, rc);
2438 goto free_gpios;
2439 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302441 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 if (curr->gpio[i].is_always_on)
2443 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302444 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302446 }
2447 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302449
2450free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302452 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 curr->gpio[i].is_enabled = false;
2454 }
2455out:
2456 return rc;
2457}
2458
2459static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2460{
2461 struct msm_mmc_pad_data *curr;
2462 int i;
2463
2464 curr = host->plat->pin_data->pad_data;
2465 for (i = 0; i < curr->drv->size; i++) {
2466 if (enable)
2467 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2468 curr->drv->on[i].val);
2469 else
2470 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2471 curr->drv->off[i].val);
2472 }
2473
2474 for (i = 0; i < curr->pull->size; i++) {
2475 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002476 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 curr->pull->on[i].val);
2478 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002479 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 curr->pull->off[i].val);
2481 }
2482
2483 return 0;
2484}
2485
2486static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2487{
2488 int rc = 0;
2489
2490 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2491 return 0;
2492
2493 if (host->plat->pin_data->is_gpio)
2494 rc = msmsdcc_setup_gpio(host, enable);
2495 else
2496 rc = msmsdcc_setup_pad(host, enable);
2497
2498 if (!rc)
2499 host->plat->pin_data->cfg_sts = enable;
2500
2501 return rc;
2502}
2503
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302504static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2505 unsigned mode)
2506{
2507 int ret = 0;
2508 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2509
2510 if (!pin)
2511 return 0;
2512
2513 switch (mode) {
2514 case SDC_DAT1_DISABLE:
2515 ret = msm_mpm_enable_pin(pin, 0);
2516 break;
2517 case SDC_DAT1_ENABLE:
2518 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2519 ret = msm_mpm_enable_pin(pin, 1);
2520 break;
2521 case SDC_DAT1_ENWAKE:
2522 ret = msm_mpm_set_pin_wake(pin, 1);
2523 break;
2524 case SDC_DAT1_DISWAKE:
2525 ret = msm_mpm_set_pin_wake(pin, 0);
2526 break;
2527 default:
2528 ret = -EINVAL;
2529 break;
2530 }
2531
2532 return ret;
2533}
2534
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302535static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2536{
2537 u32 pwr = 0;
2538 int ret = 0;
2539 struct mmc_host *mmc = host->mmc;
2540
2541 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2542 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2543 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2544 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2545
2546 if (ret) {
2547 pr_err("%s: Failed to setup voltage regulators\n",
2548 mmc_hostname(host->mmc));
2549 goto out;
2550 }
2551
2552 switch (ios->power_mode) {
2553 case MMC_POWER_OFF:
2554 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302555 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302556 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05302557 * If VDD IO rail is always on, set low voltage for VDD
2558 * IO rail when slot is not in use (like when card is not
2559 * present or during system suspend).
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302560 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05302561 msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302562 msmsdcc_setup_pins(host, false);
2563 break;
2564 case MMC_POWER_UP:
2565 /* writing PWR_UP bit is redundant */
2566 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302567 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302568
Subhash Jadavani937c7502012-06-01 15:34:46 +05302569 msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302570 msmsdcc_setup_pins(host, true);
2571 break;
2572 case MMC_POWER_ON:
2573 pwr = MCI_PWR_ON;
2574 break;
2575 }
2576
2577out:
2578 return pwr;
2579}
2580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002581static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2582{
2583 unsigned int wakeup_irq;
2584
2585 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2586 host->plat->sdiowakeup_irq :
2587 host->core_irqres->start;
2588
2589 if (!host->irq_wake_enabled) {
2590 enable_irq_wake(wakeup_irq);
2591 host->irq_wake_enabled = true;
2592 }
2593}
2594
2595static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2596{
2597 unsigned int wakeup_irq;
2598
2599 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2600 host->plat->sdiowakeup_irq :
2601 host->core_irqres->start;
2602
2603 if (host->irq_wake_enabled) {
2604 disable_irq_wake(wakeup_irq);
2605 host->irq_wake_enabled = false;
2606 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302607}
2608
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05302609/* Returns required bandwidth in Bytes per Sec */
2610static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
2611 struct mmc_ios *ios)
2612{
2613 unsigned int bw;
2614
2615 bw = host->clk_rate;
2616 /*
2617 * For DDR mode, SDCC controller clock will be at
2618 * the double rate than the actual clock that goes to card.
2619 */
2620 if (ios->bus_width == MMC_BUS_WIDTH_4)
2621 bw /= 2;
2622 else if (ios->bus_width == MMC_BUS_WIDTH_1)
2623 bw /= 8;
2624
2625 return bw;
2626}
2627
2628static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
2629 unsigned int bw)
2630{
2631 unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
2632 unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
2633 int i;
2634
2635 if (host->msm_bus_vote.is_max_bw_needed && bw)
2636 return host->msm_bus_vote.max_bw_vote;
2637
2638 for (i = 0; i < size; i++) {
2639 if (bw <= table[i])
2640 break;
2641 }
2642
2643 if (i && (i == size))
2644 i--;
2645
2646 return i;
2647}
2648
2649static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
2650{
2651 int rc = 0;
2652 struct msm_bus_scale_pdata *use_cases;
2653
2654 if (host->plat->msm_bus_voting_data &&
2655 host->plat->msm_bus_voting_data->use_cases &&
2656 host->plat->msm_bus_voting_data->bw_vecs &&
2657 host->plat->msm_bus_voting_data->bw_vecs_size) {
2658 use_cases = host->plat->msm_bus_voting_data->use_cases;
2659 host->msm_bus_vote.client_handle =
2660 msm_bus_scale_register_client(use_cases);
2661 } else {
2662 return 0;
2663 }
2664
2665 if (!host->msm_bus_vote.client_handle) {
2666 pr_err("%s: msm_bus_scale_register_client() failed\n",
2667 mmc_hostname(host->mmc));
2668 rc = -EFAULT;
2669 } else {
2670 /* cache the vote index for minimum and maximum bandwidth */
2671 host->msm_bus_vote.min_bw_vote =
2672 msmsdcc_msm_bus_get_vote_for_bw(host, 0);
2673 host->msm_bus_vote.max_bw_vote =
2674 msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
2675 }
2676
2677 return rc;
2678}
2679
2680static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
2681{
2682 if (host->msm_bus_vote.client_handle)
2683 msm_bus_scale_unregister_client(
2684 host->msm_bus_vote.client_handle);
2685}
2686
2687/*
2688 * This function must be called with host lock acquired.
2689 * Caller of this function should also ensure that msm bus client
2690 * handle is not null.
2691 */
2692static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
2693 int vote,
2694 unsigned long flags)
2695{
2696 int rc = 0;
2697
2698 if (vote != host->msm_bus_vote.curr_vote) {
2699 spin_unlock_irqrestore(&host->lock, flags);
2700 rc = msm_bus_scale_client_update_request(
2701 host->msm_bus_vote.client_handle, vote);
2702 if (rc)
2703 pr_err("%s: msm_bus_scale_client_update_request() failed."
2704 " bus_client_handle=0x%x, vote=%d, err=%d\n",
2705 mmc_hostname(host->mmc),
2706 host->msm_bus_vote.client_handle, vote, rc);
2707 spin_lock_irqsave(&host->lock, flags);
2708 if (!rc)
2709 host->msm_bus_vote.curr_vote = vote;
2710 }
2711
2712 return rc;
2713}
2714
2715/*
2716 * Internal work. Work to set 0 bandwidth for msm bus.
2717 */
2718static void msmsdcc_msm_bus_work(struct work_struct *work)
2719{
2720 struct msmsdcc_host *host = container_of(work,
2721 struct msmsdcc_host,
2722 msm_bus_vote.vote_work.work);
2723 unsigned long flags;
2724
2725 if (!host->msm_bus_vote.client_handle)
2726 return;
2727
2728 spin_lock_irqsave(&host->lock, flags);
2729 /* don't vote for 0 bandwidth if any request is in progress */
2730 if (!host->curr.mrq)
2731 msmsdcc_msm_bus_set_vote(host,
2732 host->msm_bus_vote.min_bw_vote, flags);
2733 else
2734 pr_warning("%s: %s: SDCC transfer in progress. skipping"
2735 " bus voting to 0 bandwidth\n",
2736 mmc_hostname(host->mmc), __func__);
2737 spin_unlock_irqrestore(&host->lock, flags);
2738}
2739
2740/*
2741 * This function cancels any scheduled delayed work
2742 * and sets the bus vote based on ios argument.
2743 * If "ios" argument is NULL, bandwidth required is 0 else
2744 * calculate the bandwidth based on ios parameters.
2745 */
2746static void msmsdcc_msm_bus_cancel_work_and_set_vote(
2747 struct msmsdcc_host *host,
2748 struct mmc_ios *ios)
2749{
2750 unsigned long flags;
2751 unsigned int bw;
2752 int vote;
2753
2754 if (!host->msm_bus_vote.client_handle)
2755 return;
2756
2757 bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
2758
2759 cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
2760 spin_lock_irqsave(&host->lock, flags);
2761 vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
2762 msmsdcc_msm_bus_set_vote(host, vote, flags);
2763 spin_unlock_irqrestore(&host->lock, flags);
2764}
2765
2766/* This function queues a work which will set the bandwidth requiement to 0 */
2767static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
2768{
2769 unsigned long flags;
2770
2771 if (!host->msm_bus_vote.client_handle)
2772 return;
2773
2774 spin_lock_irqsave(&host->lock, flags);
2775 if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
2776 queue_delayed_work(system_nrt_wq,
2777 &host->msm_bus_vote.vote_work,
2778 msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
2779 spin_unlock_irqrestore(&host->lock, flags);
2780}
2781
San Mehat9d2bd732009-09-22 16:44:22 -07002782static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302783msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2784{
2785 struct mmc_host *mmc = host->mmc;
2786
2787 /*
2788 * SDIO_AL clients has different mechanism of handling LPM through
2789 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2790 * part of that. Here, we are interested only in clients like WLAN.
2791 */
2792 if (!(mmc->card && mmc_card_sdio(mmc->card))
2793 || host->plat->is_sdio_al_client)
2794 goto out;
2795
2796 if (!host->sdcc_suspended) {
2797 /*
2798 * When MSM is not in power collapse and we
2799 * are disabling clocks, enable bit 22 in MASK0
2800 * to handle asynchronous SDIO interrupts.
2801 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302802 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302803 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302804 mb();
2805 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302806 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302807 msmsdcc_sync_reg_wr(host);
2808 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302809 goto out;
2810 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2811 /*
2812 * Wakeup MSM only if SDIO function drivers set
2813 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2814 */
2815 goto out;
2816 }
2817
2818 if (enable_wakeup_irq) {
2819 if (!host->plat->sdiowakeup_irq) {
2820 /*
2821 * When there is no gpio line that can be configured
2822 * as wakeup interrupt handle it by configuring
2823 * asynchronous sdio interrupts and DAT1 line.
2824 */
2825 writel_relaxed(MCI_SDIOINTMASK,
2826 host->base + MMCIMASK0);
2827 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302828 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302829 /* configure sdcc core interrupt as wakeup interrupt */
2830 msmsdcc_enable_irq_wake(host);
2831 } else {
2832 /* Let gpio line handle wakeup interrupt */
2833 writel_relaxed(0, host->base + MMCIMASK0);
2834 mb();
2835 if (host->sdio_wakeupirq_disabled) {
2836 host->sdio_wakeupirq_disabled = 0;
2837 /* configure gpio line as wakeup interrupt */
2838 msmsdcc_enable_irq_wake(host);
2839 enable_irq(host->plat->sdiowakeup_irq);
2840 }
2841 }
2842 } else {
2843 if (!host->plat->sdiowakeup_irq) {
2844 /*
2845 * We may not have cleared bit 22 in the interrupt
2846 * handler as the clocks might be off at that time.
2847 */
2848 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302849 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302850 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302851 msmsdcc_disable_irq_wake(host);
2852 } else if (!host->sdio_wakeupirq_disabled) {
2853 disable_irq_nosync(host->plat->sdiowakeup_irq);
2854 msmsdcc_disable_irq_wake(host);
2855 host->sdio_wakeupirq_disabled = 1;
2856 }
2857 }
2858out:
2859 return;
San Mehat9d2bd732009-09-22 16:44:22 -07002860}
2861
2862static void
2863msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2864{
2865 struct msmsdcc_host *host = mmc_priv(mmc);
2866 u32 clk = 0, pwr = 0;
2867 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002868 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002870
Sahitya Tummala7a892482011-01-18 11:22:49 +05302871
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302872 /*
2873 * Disable SDCC core interrupt until set_ios is completed.
2874 * This avoids any race conditions with interrupt raised
2875 * when turning on/off the clocks. One possible
2876 * scenario is SDIO operational interrupt while the clock
2877 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302878 * host->lock is being released intermittently below.
2879 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302880 */
2881
Asutosh Dasf5298c32012-04-03 14:51:47 +05302882 mutex_lock(&host->clk_mutex);
2883 DBG(host, "ios->clock = %u\n", ios->clock);
San Mehat9d2bd732009-09-22 16:44:22 -07002884 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302885 if (!host->sdcc_irq_disabled) {
2886 spin_unlock_irqrestore(&host->lock, flags);
2887 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302889 host->sdcc_irq_disabled = 1;
2890 }
San Mehatd0719e52009-12-03 10:58:54 -08002891 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002892
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302893 pwr = msmsdcc_setup_pwr(host, ios);
2894
2895 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002896 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002897 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302898 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302900 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302902 writel_relaxed(host->mci_irqenable,
2903 host->base + MMCIMASK0);
2904 mb();
2905 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002906 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907
2908 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2909 /*
2910 * For DDR50 mode, controller needs clock rate to be
2911 * double than what is required on the SD card CLK pin.
2912 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302913 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914 /*
2915 * Make sure that we don't double the clock if
2916 * doubled clock rate is already set
2917 */
2918 if (!host->ddr_doubled_clk_rate ||
2919 (host->ddr_doubled_clk_rate &&
2920 (host->ddr_doubled_clk_rate != ios->clock))) {
2921 host->ddr_doubled_clk_rate =
2922 msmsdcc_get_sup_clk_rate(
2923 host, (ios->clock * 2));
2924 clock = host->ddr_doubled_clk_rate;
2925 }
2926 } else {
2927 host->ddr_doubled_clk_rate = 0;
2928 }
2929
2930 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302931 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302933 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302935 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 mmc_hostname(mmc), clock);
2937 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302938 host->reg_write_delay =
2939 (1 + ((3 * USEC_PER_SEC) /
2940 (host->clk_rate ? host->clk_rate :
2941 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 }
2943 /*
2944 * give atleast 2 MCLK cycles delay for clocks
2945 * and SDCC core to stabilize
2946 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302947 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002949 clk |= MCI_CLK_ENABLE;
2950 }
2951
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002952 if (ios->bus_width == MMC_BUS_WIDTH_8)
2953 clk |= MCI_CLK_WIDEBUS_8;
2954 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2955 clk |= MCI_CLK_WIDEBUS_4;
2956 else
2957 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002959 if (msmsdcc_is_pwrsave(host))
2960 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002962 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964 host->tuning_needed = 0;
2965 /*
2966 * Select the controller timing mode according
2967 * to current bus speed mode
2968 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302969 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2970 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 clk |= (4 << 14);
2972 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302973 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974 clk |= (3 << 14);
2975 } else {
2976 clk |= (2 << 14); /* feedback clock */
San Mehat9d2bd732009-09-22 16:44:22 -07002977 }
2978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2980 clk |= (2 << 23);
San Mehat9d2bd732009-09-22 16:44:22 -07002981
Subhash Jadavani00083572012-02-15 16:18:01 +05302982 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2983 if (!ios->vdd)
2984 host->io_pad_pwr_switch = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07002985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986 if (host->io_pad_pwr_switch)
2987 clk |= IO_PAD_PWR_SWITCH;
2988
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302989 /* Don't write into registers if clocks are disabled */
2990 if (host->clks_on) {
2991 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2992 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302993 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302995 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2996 host->pwr = pwr;
2997 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302998 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999 }
San Mehat9d2bd732009-09-22 16:44:22 -07003000 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003001
3002 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303003 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303004 spin_unlock_irqrestore(&host->lock, flags);
3005 /*
3006 * May get a wake-up interrupt the instant we disable the
3007 * clocks. This would disable the wake-up interrupt.
3008 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003009 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303010 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003011 host->clks_on = 0;
3012 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303013
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303014 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303015 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303016 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303017
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303018 /* Let interrupts be disabled if the host is powered off */
3019 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
3020 enable_irq(host->core_irqres->start);
3021 host->sdcc_irq_disabled = 0;
3022 }
3023
San Mehat4adbbcc2009-11-08 13:00:37 -08003024 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303025 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07003026}
3027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
3029{
3030 struct msmsdcc_host *host = mmc_priv(mmc);
3031 u32 clk;
3032
3033 clk = readl_relaxed(host->base + MMCICLOCK);
3034 pr_debug("Changing to pwr_save=%d", pwrsave);
3035 if (pwrsave && msmsdcc_is_pwrsave(host))
3036 clk |= MCI_CLK_PWRSAVE;
3037 else
3038 clk &= ~MCI_CLK_PWRSAVE;
3039 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303040 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041
3042 return 0;
3043}
3044
3045static int msmsdcc_get_ro(struct mmc_host *mmc)
3046{
3047 int status = -ENOSYS;
3048 struct msmsdcc_host *host = mmc_priv(mmc);
3049
3050 if (host->plat->wpswitch) {
3051 status = host->plat->wpswitch(mmc_dev(mmc));
3052 } else if (host->plat->wpswitch_gpio) {
3053 status = gpio_request(host->plat->wpswitch_gpio,
3054 "SD_WP_Switch");
3055 if (status) {
3056 pr_err("%s: %s: Failed to request GPIO %d\n",
3057 mmc_hostname(mmc), __func__,
3058 host->plat->wpswitch_gpio);
3059 } else {
3060 status = gpio_direction_input(
3061 host->plat->wpswitch_gpio);
3062 if (!status) {
3063 /*
3064 * Wait for atleast 300ms as debounce
3065 * time for GPIO input to stabilize.
3066 */
3067 msleep(300);
3068 status = gpio_get_value_cansleep(
3069 host->plat->wpswitch_gpio);
3070 status ^= !host->plat->wpswitch_polarity;
3071 }
3072 gpio_free(host->plat->wpswitch_gpio);
3073 }
3074 }
3075
3076 if (status < 0)
3077 status = -ENOSYS;
3078 pr_debug("%s: Card read-only status %d\n", __func__, status);
3079
3080 return status;
San Mehat9d2bd732009-09-22 16:44:22 -07003081}
3082
3083static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
3084{
3085 struct msmsdcc_host *host = mmc_priv(mmc);
3086 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003087
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303088 /*
3089 * We may come here with clocks turned off in that case don't
3090 * attempt to write into MASK0 register. While turning on the
3091 * clocks mci_irqenable will be written to MASK0 register.
3092 */
San Mehat9d2bd732009-09-22 16:44:22 -07003093
3094 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303097 if (host->clks_on) {
3098 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003099 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303100 mb();
3101 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003102 } else {
3103 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303104 if (host->clks_on) {
3105 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303107 mb();
3108 }
San Mehat9d2bd732009-09-22 16:44:22 -07003109 }
3110 spin_unlock_irqrestore(&host->lock, flags);
3111}
3112
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05303114static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003115{
subhashj245831e2012-04-30 18:46:17 +05303116 struct device *dev = mmc_dev(host->mmc);
3117
3118 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
3119 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
3120 " request_pending=%d, request=%d\n",
3121 mmc_hostname(host->mmc), dev->power.runtime_status,
3122 atomic_read(&dev->power.usage_count),
3123 dev->power.is_suspended, dev->power.disable_depth,
3124 dev->power.runtime_error, dev->power.request_pending,
3125 dev->power.request);
3126}
3127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128static int msmsdcc_enable(struct mmc_host *mmc)
3129{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003130 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003131 struct device *dev = mmc->parent;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003132 struct msmsdcc_host *host = mmc_priv(mmc);
3133
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303134 msmsdcc_pm_qos_update_latency(host, 1);
3135
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003136 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303137 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003138
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003139 if (host->sdcc_suspended && host->pending_resume &&
3140 !pm_runtime_suspended(dev)) {
3141 host->pending_resume = false;
3142 pm_runtime_get_noresume(dev);
3143 rc = msmsdcc_runtime_resume(dev);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303144 goto skip_get_sync;
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003145 }
3146
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303147 if (dev->power.runtime_status == RPM_SUSPENDING) {
3148 if (mmc->suspend_task == current) {
3149 pm_runtime_get_noresume(dev);
3150 goto out;
3151 }
3152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303154 rc = pm_runtime_get_sync(dev);
3155
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303156skip_get_sync:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303157 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003158 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3159 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303160 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303161 return rc;
3162 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303163out:
3164 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303165 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003166}
3167
Steve Mucklef132c6c2012-06-06 18:30:57 -07003168static int msmsdcc_disable(struct mmc_host *mmc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169{
3170 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303171 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303173 msmsdcc_pm_qos_update_latency(host, 0);
3174
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303175 if (mmc->card && mmc_card_sdio(mmc->card)) {
3176 rc = 0;
3177 goto out;
3178 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303179
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303180 if (host->plat->disable_runtime_pm)
3181 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182
3183 rc = pm_runtime_put_sync(mmc->parent);
3184
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003185 /*
3186 * Ignore -EAGAIN as that is not fatal, it means that
3187 * either runtime usage count is non-zero or the runtime
3188 * pm itself is disabled or not in proper state to process
3189 * idle notification.
3190 */
3191 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3193 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303194 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003195 return rc;
3196 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303197
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303198out:
3199 msmsdcc_msm_bus_queue_work(host);
3200 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201}
3202#else
subhashj245831e2012-04-30 18:46:17 +05303203static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3204
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303205static int msmsdcc_enable(struct mmc_host *mmc)
3206{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003207 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303208 struct msmsdcc_host *host = mmc_priv(mmc);
3209 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303210 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303211
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303212 msmsdcc_pm_qos_update_latency(host, 1);
3213
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303214 if (mmc->card && mmc_card_sdio(mmc->card)) {
3215 rc = 0;
3216 goto out;
3217 }
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003218
3219 if (host->sdcc_suspended && host->pending_resume) {
3220 host->pending_resume = false;
3221 rc = msmsdcc_runtime_resume(dev);
3222 goto out;
3223 }
3224
Asutosh Dasf5298c32012-04-03 14:51:47 +05303225 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303226 spin_lock_irqsave(&host->lock, flags);
3227 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303228 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303229 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303230 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303231 host->clks_on = 1;
3232 }
3233 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303234 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303235
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003236out:
3237 if (rc < 0) {
3238 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3239 __func__, rc);
3240 return rc;
3241 }
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303242 msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303243 return 0;
3244}
3245
Steve Mucklef132c6c2012-06-06 18:30:57 -07003246static int msmsdcc_disable(struct mmc_host *mmc)
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303247{
3248 struct msmsdcc_host *host = mmc_priv(mmc);
3249 unsigned long flags;
3250
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303251 msmsdcc_pm_qos_update_latency(host, 0);
3252
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303253 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303254 goto out;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303255
Asutosh Dasf5298c32012-04-03 14:51:47 +05303256 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303257 spin_lock_irqsave(&host->lock, flags);
3258 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303259 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303260 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303261 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303262 host->clks_on = 0;
3263 }
3264 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303265 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303266
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05303267out:
3268 msmsdcc_msm_bus_queue_work(host);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303269 return 0;
3270}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003271#endif
3272
Subhash Jadavani937c7502012-06-01 15:34:46 +05303273static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
3274 struct mmc_ios *ios)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003275{
3276 struct msmsdcc_host *host = mmc_priv(mmc);
3277 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303278 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003279
Subhash Jadavani00083572012-02-15 16:18:01 +05303280 spin_lock_irqsave(&host->lock, flags);
3281 host->io_pad_pwr_switch = 0;
3282 spin_unlock_irqrestore(&host->lock, flags);
3283
Subhash Jadavani937c7502012-06-01 15:34:46 +05303284 switch (ios->signal_voltage) {
3285 case MMC_SIGNAL_VOLTAGE_330:
3286 /* Set VDD IO to high voltage range (2.7v - 3.6v) */
3287 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303288 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303289 case MMC_SIGNAL_VOLTAGE_180:
3290 break;
3291 case MMC_SIGNAL_VOLTAGE_120:
3292 /*
3293 * For eMMC cards, VDD_IO voltage range must be changed
3294 * only if it operates in HS200 SDR 1.2V mode or in
3295 * DDR 1.2V mode.
3296 */
3297 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003298 goto out;
Subhash Jadavani937c7502012-06-01 15:34:46 +05303299 default:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003300 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303301 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302 goto out;
3303 }
San Mehat9d2bd732009-09-22 16:44:22 -07003304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305 /*
3306 * If we are here means voltage switch from high voltage to
3307 * low voltage is required
3308 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303309 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003310
3311 /*
3312 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3313 * register until they become all zeros.
3314 */
3315 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303316 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3318 mmc_hostname(mmc), __func__);
3319 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003320 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003321
3322 /* Stop SD CLK output. */
3323 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3324 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303325 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003326 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003327
3328 /*
Subhash Jadavani937c7502012-06-01 15:34:46 +05303329 * Switch VDD Io from high voltage range (2.7v - 3.6v) to
3330 * low voltage range (1.7v - 1.95v).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003331 */
Subhash Jadavani937c7502012-06-01 15:34:46 +05303332 rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303333 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335
3336 spin_lock_irqsave(&host->lock, flags);
3337 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3338 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303339 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003340 host->io_pad_pwr_switch = 1;
3341 spin_unlock_irqrestore(&host->lock, flags);
3342
3343 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3344 usleep_range(5000, 5500);
3345
3346 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303347 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003348 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3349 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303350 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003351 spin_unlock_irqrestore(&host->lock, flags);
3352
3353 /*
3354 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3355 * don't become all ones within 1 ms then a Voltage Switch
3356 * sequence has failed and a power cycle to the card is required.
3357 * Otherwise Voltage Switch sequence is completed successfully.
3358 */
3359 usleep_range(1000, 1500);
3360
3361 spin_lock_irqsave(&host->lock, flags);
3362 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3363 != (0xF << 1)) {
3364 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3365 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303366 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003367 goto out_unlock;
3368 }
3369
3370out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303371 /* Enable PWRSAVE */
3372 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3373 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303374 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375 spin_unlock_irqrestore(&host->lock, flags);
3376out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303377 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378}
3379
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303380static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003381{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383
3384 /* Program the MCLK value to MCLK_FREQ bit field */
3385 if (host->clk_rate <= 112000000)
3386 mclk_freq = 0;
3387 else if (host->clk_rate <= 125000000)
3388 mclk_freq = 1;
3389 else if (host->clk_rate <= 137000000)
3390 mclk_freq = 2;
3391 else if (host->clk_rate <= 150000000)
3392 mclk_freq = 3;
3393 else if (host->clk_rate <= 162000000)
3394 mclk_freq = 4;
3395 else if (host->clk_rate <= 175000000)
3396 mclk_freq = 5;
3397 else if (host->clk_rate <= 187000000)
3398 mclk_freq = 6;
3399 else if (host->clk_rate <= 200000000)
3400 mclk_freq = 7;
3401
3402 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3403 & ~(7 << 24)) | (mclk_freq << 24)),
3404 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405}
3406
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303407/* Initialize the DLL (Programmable Delay Line ) */
3408static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303411 unsigned long flags;
3412 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003413
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303414 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003415 /*
3416 * Make sure that clock is always enabled when DLL
3417 * tuning is in progress. Keeping PWRSAVE ON may
3418 * turn off the clock. So let's disable the PWRSAVE
3419 * here and re-enable it once tuning is completed.
3420 */
3421 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3422 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303423 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303424
3425 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3426 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3427 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3428
3429 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3430 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3431 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3432
3433 msmsdcc_cm_sdc4_dll_set_freq(host);
3434
3435 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3436 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3437 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3438
3439 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3440 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3441 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3442
3443 /* Set DLL_EN bit to 1. */
3444 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3445 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3446
3447 /* Set CK_OUT_EN bit to 1. */
3448 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3449 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3450
3451 wait_cnt = 50;
3452 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3453 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3454 /* max. wait for 50us sec for LOCK bit to be set */
3455 if (--wait_cnt == 0) {
3456 pr_err("%s: %s: DLL failed to LOCK\n",
3457 mmc_hostname(host->mmc), __func__);
3458 rc = -ETIMEDOUT;
3459 goto out;
3460 }
3461 /* wait for 1us before polling again */
3462 udelay(1);
3463 }
3464
3465out:
3466 /* re-enable PWRSAVE */
3467 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3468 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303469 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303470 spin_unlock_irqrestore(&host->lock, flags);
3471
3472 return rc;
3473}
3474
3475static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3476 u8 poll)
3477{
3478 int rc = 0;
3479 u32 wait_cnt = 50;
3480 u8 ck_out_en = 0;
3481
3482 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3483 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3484 MCI_CK_OUT_EN);
3485
3486 while (ck_out_en != poll) {
3487 if (--wait_cnt == 0) {
3488 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3489 mmc_hostname(host->mmc), __func__, poll);
3490 rc = -ETIMEDOUT;
3491 goto out;
3492 }
3493 udelay(1);
3494
3495 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3496 MCI_CK_OUT_EN);
3497 }
3498out:
3499 return rc;
3500}
3501
3502/*
3503 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3504 * calibration sequence. This function should be called before
3505 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3506 * commands (CMD17/CMD18).
3507 *
3508 * This function gets called when host spinlock acquired.
3509 */
3510static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3511{
3512 int rc = 0;
3513 u32 config;
3514
3515 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3516 config |= MCI_CDR_EN;
3517 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3518 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3519
3520 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3521 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3522 if (rc)
3523 goto err_out;
3524
3525 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3526 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3527 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3528
3529 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3530 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3531 if (rc)
3532 goto err_out;
3533
3534 goto out;
3535
3536err_out:
3537 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3538out:
3539 return rc;
3540}
3541
3542static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3543 u8 phase)
3544{
3545 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303546 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3547 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3548 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303549 unsigned long flags;
3550 u32 config;
3551
3552 spin_lock_irqsave(&host->lock, flags);
3553
3554 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3555 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3556 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3557 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3558
3559 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3560 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3561 if (rc)
3562 goto err_out;
3563
3564 /*
3565 * Write the selected DLL clock output phase (0 ... 15)
3566 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3567 */
3568 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3569 & ~(0xF << 20))
3570 | (grey_coded_phase_table[phase] << 20)),
3571 host->base + MCI_DLL_CONFIG);
3572
3573 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3574 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3575 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3576
3577 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3578 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3579 if (rc)
3580 goto err_out;
3581
3582 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3583 config |= MCI_CDR_EN;
3584 config &= ~MCI_CDR_EXT_EN;
3585 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3586 goto out;
3587
3588err_out:
3589 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3590 mmc_hostname(host->mmc), __func__, phase);
3591out:
3592 spin_unlock_irqrestore(&host->lock, flags);
3593 return rc;
3594}
3595
3596/*
3597 * Find out the greatest range of consecuitive selected
3598 * DLL clock output phases that can be used as sampling
3599 * setting for SD3.0 UHS-I card read operation (in SDR104
3600 * timing mode) or for eMMC4.5 card read operation (in HS200
3601 * timing mode).
3602 * Select the 3/4 of the range and configure the DLL with the
3603 * selected DLL clock output phase.
3604*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303605static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303606 u8 *phase_table, u8 total_phases)
3607{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303608 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303609 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303610 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3611 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303612 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303613 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3614 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303615
Subhash Jadavani6159c622012-03-15 19:05:55 +05303616 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303617 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3618 mmc_hostname(host->mmc), __func__, total_phases);
3619 return -EINVAL;
3620 }
3621
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303622 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303623 ranges[row_index][col_index] = phase_table[cnt];
3624 phases_per_row[row_index] += 1;
3625 col_index++;
3626
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303627 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303628 continue;
3629 /* check if next phase in phase_table is consecutive or not */
3630 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3631 row_index++;
3632 col_index = 0;
3633 }
3634 }
3635
Subhash Jadavani6159c622012-03-15 19:05:55 +05303636 if (row_index >= MAX_PHASES)
3637 return -EINVAL;
3638
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303639 /* Check if phase-0 is present in first valid window? */
3640 if (!ranges[0][0]) {
3641 phase_0_found = true;
3642 phase_0_raw_index = 0;
3643 /* Check if cycle exist between 2 valid windows */
3644 for (cnt = 1; cnt <= row_index; cnt++) {
3645 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303646 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303647 if (ranges[cnt][i] == 15) {
3648 phase_15_found = true;
3649 phase_15_raw_index = cnt;
3650 break;
3651 }
3652 }
3653 }
3654 }
3655 }
3656
3657 /* If 2 valid windows form cycle then merge them as single window */
3658 if (phase_0_found && phase_15_found) {
3659 /* number of phases in raw where phase 0 is present */
3660 u8 phases_0 = phases_per_row[phase_0_raw_index];
3661 /* number of phases in raw where phase 15 is present */
3662 u8 phases_15 = phases_per_row[phase_15_raw_index];
3663
Subhash Jadavani6159c622012-03-15 19:05:55 +05303664 if (phases_0 + phases_15 >= MAX_PHASES)
3665 /*
3666 * If there are more than 1 phase windows then total
3667 * number of phases in both the windows should not be
3668 * more than or equal to MAX_PHASES.
3669 */
3670 return -EINVAL;
3671
3672 /* Merge 2 cyclic windows */
3673 i = phases_15;
3674 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303675 ranges[phase_15_raw_index][i] =
3676 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303677 if (++i >= MAX_PHASES)
3678 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303679 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303680
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303681 phases_per_row[phase_0_raw_index] = 0;
3682 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3683 }
3684
3685 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303686 if (phases_per_row[cnt] > curr_max) {
3687 curr_max = phases_per_row[cnt];
3688 selected_row_index = cnt;
3689 }
3690 }
3691
Subhash Jadavani6159c622012-03-15 19:05:55 +05303692 i = ((curr_max * 3) / 4);
3693 if (i)
3694 i--;
3695
Subhash Jadavani34187042012-03-02 10:59:49 +05303696 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303697
Subhash Jadavani6159c622012-03-15 19:05:55 +05303698 if (ret >= MAX_PHASES) {
3699 ret = -EINVAL;
3700 pr_err("%s: %s: invalid phase selected=%d\n",
3701 mmc_hostname(host->mmc), __func__, ret);
3702 }
3703
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303704 return ret;
3705}
3706
Girish K Sa3f41692012-02-29 12:00:09 +05303707static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303708{
3709 int rc = 0;
3710 struct msmsdcc_host *host = mmc_priv(mmc);
3711 unsigned long flags;
3712 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303713 const u32 *tuning_block_pattern = tuning_block_64;
3714 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303715
3716 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3717
3718 /* Tuning is only required for SDR104 modes */
3719 if (!host->tuning_needed) {
3720 rc = 0;
3721 goto exit;
3722 }
3723
3724 spin_lock_irqsave(&host->lock, flags);
3725 WARN(!host->pwr, "SDCC power is turned off\n");
3726 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3727 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3728
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303729 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303730 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3731 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3732 tuning_block_pattern = tuning_block_128;
3733 size = sizeof(tuning_block_128);
3734 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303735 spin_unlock_irqrestore(&host->lock, flags);
3736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737 /* first of all reset the tuning block */
3738 rc = msmsdcc_init_cm_sdc4_dll(host);
3739 if (rc)
3740 goto out;
3741
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303742 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 if (!data_buf) {
3744 rc = -ENOMEM;
3745 goto out;
3746 }
3747
3748 phase = 0;
3749 do {
3750 struct mmc_command cmd = {0};
3751 struct mmc_data data = {0};
3752 struct mmc_request mrq = {
3753 .cmd = &cmd,
3754 .data = &data
3755 };
3756 struct scatterlist sg;
3757
3758 /* set the phase in delay line hw block */
3759 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3760 if (rc)
3761 goto kfree;
3762
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303763 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3765
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303766 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003767 data.blocks = 1;
3768 data.flags = MMC_DATA_READ;
3769 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3770
3771 data.sg = &sg;
3772 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303773 sg_init_one(&sg, data_buf, size);
3774 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 mmc_wait_for_req(mmc, &mrq);
3776
3777 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303778 !memcmp(data_buf, tuning_block_pattern, size)) {
3779 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303781 pr_debug("%s: %s: found good phase = %d\n",
3782 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003783 }
3784 } while (++phase < 16);
3785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003786 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303787 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303788 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303789 if (rc < 0)
3790 goto kfree;
3791 else
3792 phase = (u8)rc;
3793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003794 /*
3795 * Finally set the selected phase in delay
3796 * line hw block.
3797 */
3798 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3799 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303800 goto kfree;
3801 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3802 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 } else {
3804 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303805 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003806 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303807 msmsdcc_dump_sdcc_state(host);
3808 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810
3811kfree:
3812 kfree(data_buf);
3813out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303814 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303815 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303816 spin_unlock_irqrestore(&host->lock, flags);
3817exit:
3818 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819 return rc;
Alexander Tarasikove91957e2011-08-21 15:52:44 +04003820}
3821
San Mehat9d2bd732009-09-22 16:44:22 -07003822static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003823 .enable = msmsdcc_enable,
3824 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303825 .pre_req = msmsdcc_pre_req,
3826 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003827 .request = msmsdcc_request,
3828 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003829 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003830 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Subhash Jadavani937c7502012-06-01 15:34:46 +05303831 .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003832 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003833};
3834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003835static unsigned int
3836msmsdcc_slot_status(struct msmsdcc_host *host)
3837{
3838 int status;
3839 unsigned int gpio_no = host->plat->status_gpio;
3840
3841 status = gpio_request(gpio_no, "SD_HW_Detect");
3842 if (status) {
3843 pr_err("%s: %s: Failed to request GPIO %d\n",
3844 mmc_hostname(host->mmc), __func__, gpio_no);
3845 } else {
3846 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003847 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003848 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003849 if (host->plat->is_status_gpio_active_low)
3850 status = !status;
3851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852 gpio_free(gpio_no);
3853 }
3854 return status;
3855}
3856
San Mehat9d2bd732009-09-22 16:44:22 -07003857static void
3858msmsdcc_check_status(unsigned long data)
3859{
3860 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3861 unsigned int status;
3862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003864 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003865 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003866 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003867 status = msmsdcc_slot_status(host);
3868
Krishna Konda941604a2012-01-10 17:46:34 -08003869 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003871 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003872 if (host->plat->status)
3873 pr_info("%s: Slot status change detected "
3874 "(%d -> %d)\n",
3875 mmc_hostname(host->mmc),
3876 host->oldstat, status);
3877 else if (host->plat->is_status_gpio_active_low)
3878 pr_info("%s: Slot status change detected "
3879 "(%d -> %d) and the card detect GPIO"
3880 " is ACTIVE_LOW\n",
3881 mmc_hostname(host->mmc),
3882 host->oldstat, status);
3883 else
3884 pr_info("%s: Slot status change detected "
3885 "(%d -> %d) and the card detect GPIO"
3886 " is ACTIVE_HIGH\n",
3887 mmc_hostname(host->mmc),
3888 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003889 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890 }
3891 host->oldstat = status;
3892 } else {
3893 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003894 }
San Mehat9d2bd732009-09-22 16:44:22 -07003895}
3896
3897static irqreturn_t
3898msmsdcc_platform_status_irq(int irq, void *dev_id)
3899{
3900 struct msmsdcc_host *host = dev_id;
3901
Girish K Sa3c76eb2011-10-11 11:44:09 +05303902 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003903 msmsdcc_check_status((unsigned long) host);
3904 return IRQ_HANDLED;
3905}
3906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003907static irqreturn_t
3908msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3909{
3910 struct msmsdcc_host *host = dev_id;
3911
3912 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3913 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303914 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303916 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 wake_lock(&host->sdio_wlock);
3918 msmsdcc_disable_irq_wake(host);
3919 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303920 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921 }
3922 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003923 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303924 spin_unlock(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303925 mmc_signal_sdio_irq(host->mmc);
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303926 goto out_unlocked;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003927 }
3928 spin_unlock(&host->lock);
3929
Sujit Reddy Thummad15fa232012-04-03 15:50:59 +05303930out_unlocked:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 return IRQ_HANDLED;
3932}
3933
San Mehat9d2bd732009-09-22 16:44:22 -07003934static void
3935msmsdcc_status_notify_cb(int card_present, void *dev_id)
3936{
3937 struct msmsdcc_host *host = dev_id;
3938
Girish K Sa3c76eb2011-10-11 11:44:09 +05303939 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003940 card_present);
3941 msmsdcc_check_status((unsigned long) host);
3942}
3943
San Mehat9d2bd732009-09-22 16:44:22 -07003944static int
3945msmsdcc_init_dma(struct msmsdcc_host *host)
3946{
3947 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3948 host->dma.host = host;
3949 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003950 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003951
3952 if (!host->dmares)
3953 return -ENODEV;
3954
3955 host->dma.nc = dma_alloc_coherent(NULL,
3956 sizeof(struct msmsdcc_nc_dmadata),
3957 &host->dma.nc_busaddr,
3958 GFP_KERNEL);
3959 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003960 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003961 return -ENOMEM;
3962 }
3963 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3964 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3965 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3966 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3967 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003968 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003969
3970 return 0;
3971}
3972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003973#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3974/**
3975 * Allocate and Connect a SDCC peripheral's SPS endpoint
3976 *
3977 * This function allocates endpoint context and
3978 * connect it with memory endpoint by calling
3979 * appropriate SPS driver APIs.
3980 *
3981 * Also registers a SPS callback function with
3982 * SPS driver
3983 *
3984 * This function should only be called once typically
3985 * during driver probe.
3986 *
3987 * @host - Pointer to sdcc host structure
3988 * @ep - Pointer to sps endpoint data structure
3989 * @is_produce - 1 means Producer endpoint
3990 * 0 means Consumer endpoint
3991 *
3992 * @return - 0 if successful else negative value.
3993 *
3994 */
3995static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3996 struct msmsdcc_sps_ep_conn_data *ep,
3997 bool is_producer)
3998{
3999 int rc = 0;
4000 struct sps_pipe *sps_pipe_handle;
4001 struct sps_connect *sps_config = &ep->config;
4002 struct sps_register_event *sps_event = &ep->event;
4003
4004 /* Allocate endpoint context */
4005 sps_pipe_handle = sps_alloc_endpoint();
4006 if (!sps_pipe_handle) {
4007 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
4008 mmc_hostname(host->mmc), is_producer);
4009 rc = -ENOMEM;
4010 goto out;
4011 }
4012
4013 /* Get default connection configuration for an endpoint */
4014 rc = sps_get_config(sps_pipe_handle, sps_config);
4015 if (rc) {
4016 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
4017 " rc=%d", mmc_hostname(host->mmc),
4018 (u32)sps_pipe_handle, rc);
4019 goto get_config_err;
4020 }
4021
4022 /* Modify the default connection configuration */
4023 if (is_producer) {
4024 /*
4025 * For SDCC producer transfer, source should be
4026 * SDCC peripheral where as destination should
4027 * be system memory.
4028 */
4029 sps_config->source = host->sps.bam_handle;
4030 sps_config->destination = SPS_DEV_HANDLE_MEM;
4031 /* Producer pipe will handle this connection */
4032 sps_config->mode = SPS_MODE_SRC;
4033 sps_config->options =
4034 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4035 } else {
4036 /*
4037 * For SDCC consumer transfer, source should be
4038 * system memory where as destination should
4039 * SDCC peripheral
4040 */
4041 sps_config->source = SPS_DEV_HANDLE_MEM;
4042 sps_config->destination = host->sps.bam_handle;
4043 sps_config->mode = SPS_MODE_DEST;
4044 sps_config->options =
4045 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
4046 }
4047
4048 /* Producer pipe index */
4049 sps_config->src_pipe_index = host->sps.src_pipe_index;
4050 /* Consumer pipe index */
4051 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
4052 /*
4053 * This event thresold value is only significant for BAM-to-BAM
4054 * transfer. It's ignored for BAM-to-System mode transfer.
4055 */
4056 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304057
4058 /* Allocate maximum descriptor fifo size */
4059 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
4060 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
4062 sps_config->desc.size,
4063 &sps_config->desc.phys_base,
4064 GFP_KERNEL);
4065
Pratibhasagar V00b94332011-10-18 14:57:27 +05304066 if (!sps_config->desc.base) {
4067 rc = -ENOMEM;
4068 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
4069 , mmc_hostname(host->mmc));
4070 goto get_config_err;
4071 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004072 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
4073
4074 /* Establish connection between peripheral and memory endpoint */
4075 rc = sps_connect(sps_pipe_handle, sps_config);
4076 if (rc) {
4077 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4078 " rc=%d", mmc_hostname(host->mmc),
4079 (u32)sps_pipe_handle, rc);
4080 goto sps_connect_err;
4081 }
4082
4083 sps_event->mode = SPS_TRIGGER_CALLBACK;
4084 sps_event->options = SPS_O_EOT;
4085 sps_event->callback = msmsdcc_sps_complete_cb;
4086 sps_event->xfer_done = NULL;
4087 sps_event->user = (void *)host;
4088
4089 /* Register callback event for EOT (End of transfer) event. */
4090 rc = sps_register_event(sps_pipe_handle, sps_event);
4091 if (rc) {
4092 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
4093 " rc=%d", mmc_hostname(host->mmc),
4094 (u32)sps_pipe_handle, rc);
4095 goto reg_event_err;
4096 }
4097 /* Now save the sps pipe handle */
4098 ep->pipe_handle = sps_pipe_handle;
4099 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
4100 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
4101 __func__, is_producer ? "READ" : "WRITE",
4102 (u32)sps_pipe_handle, sps_config->desc.phys_base);
4103 goto out;
4104
4105reg_event_err:
4106 sps_disconnect(sps_pipe_handle);
4107sps_connect_err:
4108 dma_free_coherent(mmc_dev(host->mmc),
4109 sps_config->desc.size,
4110 sps_config->desc.base,
4111 sps_config->desc.phys_base);
4112get_config_err:
4113 sps_free_endpoint(sps_pipe_handle);
4114out:
4115 return rc;
4116}
4117
4118/**
4119 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
4120 *
4121 * This function disconnect endpoint and deallocates
4122 * endpoint context.
4123 *
4124 * This function should only be called once typically
4125 * during driver remove.
4126 *
4127 * @host - Pointer to sdcc host structure
4128 * @ep - Pointer to sps endpoint data structure
4129 *
4130 */
4131static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
4132 struct msmsdcc_sps_ep_conn_data *ep)
4133{
4134 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4135 struct sps_connect *sps_config = &ep->config;
4136 struct sps_register_event *sps_event = &ep->event;
4137
4138 sps_event->xfer_done = NULL;
4139 sps_event->callback = NULL;
4140 sps_register_event(sps_pipe_handle, sps_event);
4141 sps_disconnect(sps_pipe_handle);
4142 dma_free_coherent(mmc_dev(host->mmc),
4143 sps_config->desc.size,
4144 sps_config->desc.base,
4145 sps_config->desc.phys_base);
4146 sps_free_endpoint(sps_pipe_handle);
4147}
4148
4149/**
4150 * Reset SDCC peripheral's SPS endpoint
4151 *
4152 * This function disconnects an endpoint.
4153 *
4154 * This function should be called for reseting
4155 * SPS endpoint when data transfer error is
4156 * encountered during data transfer. This
4157 * can be considered as soft reset to endpoint.
4158 *
4159 * This function should only be called if
4160 * msmsdcc_sps_init() is already called.
4161 *
4162 * @host - Pointer to sdcc host structure
4163 * @ep - Pointer to sps endpoint data structure
4164 *
4165 * @return - 0 if successful else negative value.
4166 */
4167static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
4168 struct msmsdcc_sps_ep_conn_data *ep)
4169{
4170 int rc = 0;
4171 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4172
4173 rc = sps_disconnect(sps_pipe_handle);
4174 if (rc) {
4175 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4176 " rc=%d", mmc_hostname(host->mmc), __func__,
4177 (u32)sps_pipe_handle, rc);
4178 goto out;
4179 }
4180 out:
4181 return rc;
4182}
4183
4184/**
4185 * Restore SDCC peripheral's SPS endpoint
4186 *
4187 * This function connects an endpoint.
4188 *
4189 * This function should be called for restoring
4190 * SPS endpoint after data transfer error is
4191 * encountered during data transfer. This
4192 * can be considered as soft reset to endpoint.
4193 *
4194 * This function should only be called if
4195 * msmsdcc_sps_reset_ep() is called before.
4196 *
4197 * @host - Pointer to sdcc host structure
4198 * @ep - Pointer to sps endpoint data structure
4199 *
4200 * @return - 0 if successful else negative value.
4201 */
4202static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4203 struct msmsdcc_sps_ep_conn_data *ep)
4204{
4205 int rc = 0;
4206 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4207 struct sps_connect *sps_config = &ep->config;
4208 struct sps_register_event *sps_event = &ep->event;
4209
4210 /* Establish connection between peripheral and memory endpoint */
4211 rc = sps_connect(sps_pipe_handle, sps_config);
4212 if (rc) {
4213 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4214 " rc=%d", mmc_hostname(host->mmc), __func__,
4215 (u32)sps_pipe_handle, rc);
4216 goto out;
4217 }
4218
4219 /* Register callback event for EOT (End of transfer) event. */
4220 rc = sps_register_event(sps_pipe_handle, sps_event);
4221 if (rc) {
4222 pr_err("%s: %s: sps_register_event() failed!!!"
4223 " pipe_handle=0x%x, rc=%d",
4224 mmc_hostname(host->mmc), __func__,
4225 (u32)sps_pipe_handle, rc);
4226 goto reg_event_err;
4227 }
4228 goto out;
4229
4230reg_event_err:
4231 sps_disconnect(sps_pipe_handle);
4232out:
4233 return rc;
4234}
4235
4236/**
4237 * Initialize SPS HW connected with SDCC core
4238 *
4239 * This function register BAM HW resources with
4240 * SPS driver and then initialize 2 SPS endpoints
4241 *
4242 * This function should only be called once typically
4243 * during driver probe.
4244 *
4245 * @host - Pointer to sdcc host structure
4246 *
4247 * @return - 0 if successful else negative value.
4248 *
4249 */
4250static int msmsdcc_sps_init(struct msmsdcc_host *host)
4251{
4252 int rc = 0;
4253 struct sps_bam_props bam = {0};
4254
4255 host->bam_base = ioremap(host->bam_memres->start,
4256 resource_size(host->bam_memres));
4257 if (!host->bam_base) {
4258 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4259 " size=0x%x", mmc_hostname(host->mmc),
4260 host->bam_memres->start,
4261 (host->bam_memres->end -
4262 host->bam_memres->start));
4263 rc = -ENOMEM;
4264 goto out;
4265 }
4266
4267 bam.phys_addr = host->bam_memres->start;
4268 bam.virt_addr = host->bam_base;
4269 /*
4270 * This event thresold value is only significant for BAM-to-BAM
4271 * transfer. It's ignored for BAM-to-System mode transfer.
4272 */
4273 bam.event_threshold = 0x10; /* Pipe event threshold */
4274 /*
4275 * This threshold controls when the BAM publish
4276 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304277 * SPS HW will be used for data transfer size even
4278 * less than SDCC FIFO size. So let's set BAM summing
4279 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004280 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304281 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004282 /* SPS driver wll handle the SDCC BAM IRQ */
4283 bam.irq = (u32)host->bam_irqres->start;
4284 bam.manage = SPS_BAM_MGR_LOCAL;
4285
4286 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4287 (u32)bam.phys_addr);
4288 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4289 (u32)bam.virt_addr);
4290
4291 /* Register SDCC Peripheral BAM device to SPS driver */
4292 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4293 if (rc) {
4294 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4295 mmc_hostname(host->mmc), rc);
4296 goto reg_bam_err;
4297 }
4298 pr_info("%s: BAM device registered. bam_handle=0x%x",
4299 mmc_hostname(host->mmc), host->sps.bam_handle);
4300
4301 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4302 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4303
4304 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4305 SPS_PROD_PERIPHERAL);
4306 if (rc)
4307 goto sps_reset_err;
4308 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4309 SPS_CONS_PERIPHERAL);
4310 if (rc)
4311 goto cons_conn_err;
4312
4313 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4314 mmc_hostname(host->mmc),
4315 (unsigned long long)host->bam_memres->start,
4316 (unsigned int)host->bam_irqres->start);
4317 goto out;
4318
4319cons_conn_err:
4320 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4321sps_reset_err:
4322 sps_deregister_bam_device(host->sps.bam_handle);
4323reg_bam_err:
4324 iounmap(host->bam_base);
4325out:
4326 return rc;
4327}
4328
4329/**
4330 * De-initialize SPS HW connected with SDCC core
4331 *
4332 * This function deinitialize SPS endpoints and then
4333 * deregisters BAM resources from SPS driver.
4334 *
4335 * This function should only be called once typically
4336 * during driver remove.
4337 *
4338 * @host - Pointer to sdcc host structure
4339 *
4340 */
4341static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4342{
4343 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4344 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4345 sps_deregister_bam_device(host->sps.bam_handle);
4346 iounmap(host->bam_base);
4347}
4348#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4349
4350static ssize_t
4351show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4352{
4353 struct mmc_host *mmc = dev_get_drvdata(dev);
4354 struct msmsdcc_host *host = mmc_priv(mmc);
4355 int poll;
4356 unsigned long flags;
4357
4358 spin_lock_irqsave(&host->lock, flags);
4359 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4360 spin_unlock_irqrestore(&host->lock, flags);
4361
4362 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4363}
4364
4365static ssize_t
4366set_polling(struct device *dev, struct device_attribute *attr,
4367 const char *buf, size_t count)
4368{
4369 struct mmc_host *mmc = dev_get_drvdata(dev);
4370 struct msmsdcc_host *host = mmc_priv(mmc);
4371 int value;
4372 unsigned long flags;
4373
4374 sscanf(buf, "%d", &value);
4375
4376 spin_lock_irqsave(&host->lock, flags);
4377 if (value) {
4378 mmc->caps |= MMC_CAP_NEEDS_POLL;
4379 mmc_detect_change(host->mmc, 0);
4380 } else {
4381 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4382 }
4383#ifdef CONFIG_HAS_EARLYSUSPEND
4384 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4385#endif
4386 spin_unlock_irqrestore(&host->lock, flags);
4387 return count;
4388}
4389
4390static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4391 show_polling, set_polling);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304392
4393static ssize_t
4394show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4395 char *buf)
4396{
4397 struct mmc_host *mmc = dev_get_drvdata(dev);
4398 struct msmsdcc_host *host = mmc_priv(mmc);
4399
4400 return snprintf(buf, PAGE_SIZE, "%u\n",
4401 host->msm_bus_vote.is_max_bw_needed);
4402}
4403
4404static ssize_t
4405set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
4406 const char *buf, size_t count)
4407{
4408 struct mmc_host *mmc = dev_get_drvdata(dev);
4409 struct msmsdcc_host *host = mmc_priv(mmc);
4410 uint32_t value;
4411 unsigned long flags;
4412
4413 if (!kstrtou32(buf, 0, &value)) {
4414 spin_lock_irqsave(&host->lock, flags);
4415 host->msm_bus_vote.is_max_bw_needed = !!value;
4416 spin_unlock_irqrestore(&host->lock, flags);
4417 }
4418
4419 return count;
4420}
4421
4422static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
4423 show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
4424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004425static struct attribute *dev_attrs[] = {
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304426 &dev_attr_max_bus_bw.attr,
4427 /* if polling is enabled, this will be filled with dev_attr_polling */
4428 NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429 NULL,
4430};
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004432static struct attribute_group dev_attr_grp = {
4433 .attrs = dev_attrs,
4434};
4435
4436#ifdef CONFIG_HAS_EARLYSUSPEND
4437static void msmsdcc_early_suspend(struct early_suspend *h)
4438{
4439 struct msmsdcc_host *host =
4440 container_of(h, struct msmsdcc_host, early_suspend);
4441 unsigned long flags;
4442
4443 spin_lock_irqsave(&host->lock, flags);
4444 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4445 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4446 spin_unlock_irqrestore(&host->lock, flags);
4447};
4448static void msmsdcc_late_resume(struct early_suspend *h)
4449{
4450 struct msmsdcc_host *host =
4451 container_of(h, struct msmsdcc_host, early_suspend);
4452 unsigned long flags;
4453
4454 if (host->polling_enabled) {
4455 spin_lock_irqsave(&host->lock, flags);
4456 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4457 mmc_detect_change(host->mmc, 0);
4458 spin_unlock_irqrestore(&host->lock, flags);
4459 }
4460};
4461#endif
4462
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304463static void msmsdcc_print_regs(const char *name, void __iomem *base,
4464 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304465{
4466 unsigned int i;
4467
4468 if (!base)
4469 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304470
4471 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4472 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304473 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304474 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4475 (u32)readl_relaxed(base + i*4),
4476 (u32)readl_relaxed(base + ((i+1)*4)),
4477 (u32)readl_relaxed(base + ((i+2)*4)),
4478 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304479 }
4480}
4481
4482static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4483{
4484 /* Dump current state of SDCC clocks, power and irq */
4485 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304486 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304487 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304488 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4489 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304490 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4491 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4492
4493 /* Now dump SDCC registers. Don't print FIFO registers */
4494 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304495 msmsdcc_print_regs("SDCC-CORE", host->base,
4496 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304497
4498 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304499 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304500 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4501 else if (host->is_dma_mode)
4502 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4503 mmc_hostname(host->mmc), host->dma.busy,
4504 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304505 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304506 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304507 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4508 host->dml_memres->start,
4509 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304510 pr_info("%s: SPS mode: busy=%d\n",
4511 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304512 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304513
4514 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4515 mmc_hostname(host->mmc), host->curr.xfer_size,
4516 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304517 }
4518
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304519 pr_info("%s: got_dataend=%d, prog_enable=%d,"
Subhash Jadavani8706ced2012-05-25 16:09:21 +05304520 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
4521 " req_tout_ms=%d\n", mmc_hostname(host->mmc),
4522 host->curr.got_dataend, host->prog_enable,
4523 host->curr.wait_for_auto_prog_done,
4524 host->curr.got_auto_prog_done, host->curr.req_tout_ms);
subhashj245831e2012-04-30 18:46:17 +05304525 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304526}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4529{
4530 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4531 struct mmc_request *mrq;
4532 unsigned long flags;
4533
4534 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004535 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004536 pr_info("%s: %s: dummy CMD52 timeout\n",
4537 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004538 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004539 }
4540
4541 mrq = host->curr.mrq;
4542
4543 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304544 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4545 mrq->cmd->opcode);
4546 msmsdcc_dump_sdcc_state(host);
4547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548 if (!mrq->cmd->error)
4549 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304550 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 if (mrq->data && !mrq->data->error)
4553 mrq->data->error = -ETIMEDOUT;
4554 host->curr.data_xfered = 0;
4555 if (host->dma.sg && host->is_dma_mode) {
Jeff Ohlsteinc00383d2012-04-27 12:49:24 -07004556 msm_dmov_flush(host->dma.channel, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557 } else if (host->sps.sg && host->is_sps_mode) {
4558 /* Stop current SPS transfer */
4559 msmsdcc_sps_exit_curr_xfer(host);
4560 } else {
4561 msmsdcc_reset_and_restore(host);
4562 msmsdcc_stop_data(host);
4563 if (mrq->data && mrq->data->stop)
4564 msmsdcc_start_command(host,
4565 mrq->data->stop, 0);
4566 else
4567 msmsdcc_request_end(host, mrq);
4568 }
4569 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304570 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304571 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004572 msmsdcc_reset_and_restore(host);
4573 msmsdcc_request_end(host, mrq);
4574 }
4575 }
4576 spin_unlock_irqrestore(&host->lock, flags);
4577}
4578
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304579static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4580{
4581 int i, ret;
4582 struct mmc_platform_data *pdata;
4583 struct device_node *np = dev->of_node;
4584 u32 bus_width = 0;
4585 u32 *clk_table;
4586 int clk_table_len;
4587 u32 *sup_voltages;
4588 int sup_volt_len;
4589
4590 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4591 if (!pdata) {
4592 dev_err(dev, "could not allocate memory for platform data\n");
4593 goto err;
4594 }
4595
4596 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4597 if (bus_width == 8) {
4598 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4599 } else if (bus_width == 4) {
4600 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4601 } else {
4602 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4603 pdata->mmc_bus_width = 0;
4604 }
4605
4606 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4607 size_t sz;
4608 sz = sup_volt_len / sizeof(*sup_voltages);
4609 if (sz > 0) {
4610 sup_voltages = devm_kzalloc(dev,
4611 sz * sizeof(*sup_voltages), GFP_KERNEL);
4612 if (!sup_voltages) {
4613 dev_err(dev, "No memory for supported voltage\n");
4614 goto err;
4615 }
4616
4617 ret = of_property_read_u32_array(np,
4618 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4619 if (ret < 0) {
4620 dev_err(dev, "error while reading voltage"
4621 "ranges %d\n", ret);
4622 goto err;
4623 }
4624 } else {
4625 dev_err(dev, "No supported voltages\n");
4626 goto err;
4627 }
4628 for (i = 0; i < sz; i += 2) {
4629 u32 mask;
4630
4631 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4632 sup_voltages[i + 1]);
4633 if (!mask)
4634 dev_err(dev, "Invalide voltage range %d\n", i);
4635 pdata->ocr_mask |= mask;
4636 }
4637 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4638 } else {
4639 dev_err(dev, "Supported voltage range not specified\n");
4640 }
4641
4642 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4643 size_t sz;
4644 sz = clk_table_len / sizeof(*clk_table);
4645
4646 if (sz > 0) {
4647 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4648 GFP_KERNEL);
4649 if (!clk_table) {
4650 dev_err(dev, "No memory for clock table\n");
4651 goto err;
4652 }
4653
4654 ret = of_property_read_u32_array(np,
4655 "qcom,sdcc-clk-rates", clk_table, sz);
4656 if (ret < 0) {
4657 dev_err(dev, "error while reading clk"
4658 "table %d\n", ret);
4659 goto err;
4660 }
4661 } else {
4662 dev_err(dev, "clk_table not specified\n");
4663 goto err;
4664 }
4665 pdata->sup_clk_table = clk_table;
4666 pdata->sup_clk_cnt = sz;
4667 } else {
4668 dev_err(dev, "Supported clock rates not specified\n");
4669 }
4670
4671 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4672 pdata->nonremovable = true;
4673 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4674 pdata->disable_cmd23 = true;
4675
4676 return pdata;
4677err:
4678 return NULL;
4679}
4680
San Mehat9d2bd732009-09-22 16:44:22 -07004681static int
4682msmsdcc_probe(struct platform_device *pdev)
4683{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304684 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004685 struct msmsdcc_host *host;
4686 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687 unsigned long flags;
4688 struct resource *core_irqres = NULL;
4689 struct resource *bam_irqres = NULL;
4690 struct resource *core_memres = NULL;
4691 struct resource *dml_memres = NULL;
4692 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004693 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004694 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304695 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004696 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004697
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304698 if (pdev->dev.of_node) {
4699 plat = msmsdcc_populate_pdata(&pdev->dev);
4700 of_property_read_u32((&pdev->dev)->of_node,
4701 "cell-index", &pdev->id);
4702 } else {
4703 plat = pdev->dev.platform_data;
4704 }
San Mehat9d2bd732009-09-22 16:44:22 -07004705
4706 /* must have platform data */
4707 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004708 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004709 ret = -EINVAL;
4710 goto out;
4711 }
4712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004714 return -EINVAL;
4715
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304716 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4717 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4718 return -EINVAL;
4719 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004720
San Mehat9d2bd732009-09-22 16:44:22 -07004721 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004722 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004723 return -ENXIO;
4724 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304725 if (pdev->dev.of_node) {
4726 /*
4727 * Device tree iomem resources are only accessible by index.
4728 * index = 0 -> SDCC register interface
4729 * index = 1 -> DML register interface
4730 * index = 2 -> BAM register interface
4731 * IRQ resources:
4732 * index = 0 -> SDCC IRQ
4733 * index = 1 -> BAM IRQ
4734 */
4735 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4736 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4737 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4738 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4739 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4740 } else {
4741 for (i = 0; i < pdev->num_resources; i++) {
4742 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4743 if (!strncmp(pdev->resource[i].name,
4744 "sdcc_dml_addr",
4745 sizeof("sdcc_dml_addr")))
4746 dml_memres = &pdev->resource[i];
4747 else if (!strncmp(pdev->resource[i].name,
4748 "sdcc_bam_addr",
4749 sizeof("sdcc_bam_addr")))
4750 bam_memres = &pdev->resource[i];
4751 else
4752 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004753
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304754 }
4755 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4756 if (!strncmp(pdev->resource[i].name,
4757 "sdcc_bam_irq",
4758 sizeof("sdcc_bam_irq")))
4759 bam_irqres = &pdev->resource[i];
4760 else
4761 core_irqres = &pdev->resource[i];
4762 }
4763 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4764 if (!strncmp(pdev->resource[i].name,
4765 "sdcc_dma_chnl",
4766 sizeof("sdcc_dma_chnl")))
4767 dmares = &pdev->resource[i];
4768 else if (!strncmp(pdev->resource[i].name,
4769 "sdcc_dma_crci",
4770 sizeof("sdcc_dma_crci")))
4771 dma_crci_res = &pdev->resource[i];
4772 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 }
San Mehat9d2bd732009-09-22 16:44:22 -07004775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004776 if (!core_irqres || !core_memres) {
4777 pr_err("%s: Invalid sdcc core resource\n", __func__);
4778 return -ENXIO;
4779 }
4780
4781 /*
4782 * Both BAM and DML memory resource should be preset.
4783 * BAM IRQ resource should also be present.
4784 */
4785 if ((bam_memres && !dml_memres) ||
4786 (!bam_memres && dml_memres) ||
4787 ((bam_memres && dml_memres) && !bam_irqres)) {
4788 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004789 return -ENXIO;
4790 }
4791
4792 /*
4793 * Setup our host structure
4794 */
San Mehat9d2bd732009-09-22 16:44:22 -07004795 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4796 if (!mmc) {
4797 ret = -ENOMEM;
4798 goto out;
4799 }
4800
4801 host = mmc_priv(mmc);
4802 host->pdev_id = pdev->id;
4803 host->plat = plat;
4804 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004805 host->curr.cmd = NULL;
Sahitya Tummala19207f02011-05-02 18:10:01 +05304806
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304807 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808 host->is_sps_mode = 1;
4809 else if (dmares)
4810 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 host->base = ioremap(core_memres->start,
4813 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004814 if (!host->base) {
4815 ret = -ENOMEM;
Sahitya Tummaladce7c752011-05-02 18:06:05 +05304816 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004817 }
4818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004819 host->core_irqres = core_irqres;
4820 host->bam_irqres = bam_irqres;
4821 host->core_memres = core_memres;
4822 host->dml_memres = dml_memres;
4823 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004824 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004825 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004826 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304827 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829#ifdef CONFIG_MMC_EMBEDDED_SDIO
4830 if (plat->embedded_sdio)
4831 mmc_set_embedded_sdio_data(mmc,
4832 &plat->embedded_sdio->cis,
4833 &plat->embedded_sdio->cccr,
4834 plat->embedded_sdio->funcs,
4835 plat->embedded_sdio->num_funcs);
4836#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004837
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304838 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4839 (unsigned long)host);
4840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004841 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4842 (unsigned long)host);
4843 if (host->is_dma_mode) {
4844 /* Setup DMA */
Subhash Jadavani190657c2011-05-02 18:10:40 +05304845 ret = msmsdcc_init_dma(host);
4846 if (ret)
4847 goto ioremap_free;
4848 } else {
4849 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004850 host->dma.crci = -1;
Subhash Jadavani190657c2011-05-02 18:10:40 +05304851 }
San Mehat9d2bd732009-09-22 16:44:22 -07004852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004853 /*
4854 * Setup SDCC clock if derived from Dayatona
4855 * fabric core clock.
4856 */
4857 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004858 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004859 if (!IS_ERR(host->dfab_pclk)) {
4860 /* Set the clock rate to 64MHz for max. performance */
4861 ret = clk_set_rate(host->dfab_pclk, 64000000);
4862 if (ret)
4863 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304864 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004865 if (ret)
4866 goto dfab_pclk_put;
4867 } else
4868 goto dma_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004869 }
4870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004871 /*
4872 * Setup main peripheral bus clock
4873 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004874 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004875 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304876 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004877 if (ret)
4878 goto pclk_put;
4879
4880 host->pclk_rate = clk_get_rate(host->pclk);
4881 }
4882
4883 /*
4884 * Setup SDC MMC clock
4885 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004886 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004887 if (IS_ERR(host->clk)) {
4888 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004889 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004890 }
4891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004892 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
Sahitya Tummala514d9ed2011-05-02 18:07:01 +05304893 if (ret) {
4894 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4895 goto clk_put;
4896 }
4897
Asutosh Dasf5298c32012-04-03 14:51:47 +05304898 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004899 if (ret)
4900 goto clk_put;
4901
San Mehat9d2bd732009-09-22 16:44:22 -07004902 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304903 if (!host->clk_rate)
4904 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304905
4906 /*
4907 * Lookup the Controller Version, to identify the supported features
4908 * Version number read as 0 would indicate SDCC3 or earlier versions
4909 */
4910 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4911 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4912 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304913 /*
4914 * Set the register write delay according to min. clock frequency
4915 * supported and update later when the host->clk_rate changes.
4916 */
4917 host->reg_write_delay =
4918 (1 + ((3 * USEC_PER_SEC) /
4919 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004920
4921 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304922 /* Apply Hard reset to SDCC to put it in power on default state */
4923 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004924
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004925#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304926 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004927 if (host->plat->cpu_dma_latency)
4928 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4929 else
4930 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4931 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304932 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4933
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05304934 ret = msmsdcc_msm_bus_register(host);
4935 if (ret)
4936 goto pm_qos_remove;
4937
4938 if (host->msm_bus_vote.client_handle)
4939 INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
4940 msmsdcc_msm_bus_work);
4941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004942 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004943 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004944 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004945 goto clk_disable;
4946 }
4947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004948
4949 /* Clocks has to be running before accessing SPS/DML HW blocks */
4950 if (host->is_sps_mode) {
4951 /* Initialize SPS */
4952 ret = msmsdcc_sps_init(host);
4953 if (ret)
4954 goto vreg_deinit;
4955 /* Initialize DML */
4956 ret = msmsdcc_dml_init(host);
4957 if (ret)
4958 goto sps_exit;
4959 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304960 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004961
San Mehat9d2bd732009-09-22 16:44:22 -07004962 /*
4963 * Setup MMC host structure
4964 */
4965 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004966 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4967 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004968 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004969 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4970 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004971
San Mehat9d2bd732009-09-22 16:44:22 -07004972 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304973 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
San Mehat9d2bd732009-09-22 16:44:22 -07004974
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304975 /*
4976 * If we send the CMD23 before multi block write/read command
4977 * then we need not to send CMD12 at the end of the transfer.
4978 * If we don't send the CMD12 then only way to detect the PROG_DONE
4979 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4980 * controller. So let's enable the CMD23 for SDCC4 only.
4981 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304982 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304983 mmc->caps |= MMC_CAP_CMD23;
San Mehat9d2bd732009-09-22 16:44:22 -07004984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004985 mmc->caps |= plat->uhs_caps;
4986 /*
4987 * XPC controls the maximum current in the default speed mode of SDXC
4988 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4989 * XPC=1 means 150mA (max.) and speed class is supported.
4990 */
4991 if (plat->xpc_cap)
4992 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4993 MMC_CAP_SET_XPC_180);
4994
Maya Erez25e22612012-05-20 08:45:01 +03004995 mmc->caps2 |= MMC_CAP2_PACKED_WR;
Maya Erez8afe8d22012-05-20 15:11:52 +03004996 mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304997 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Yaniv Gardi14098552012-06-04 10:56:03 +03004998 mmc->caps2 |= MMC_CAP2_SANITIZE;
4999
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05305000 if (pdev->dev.of_node) {
5001 if (of_get_property((&pdev->dev)->of_node,
5002 "qcom,sdcc-hs200", NULL))
5003 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
5004 }
5005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006 if (plat->nonremovable)
5007 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005008 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005009
Konstantin Dorfman9db69fc2012-06-01 14:04:45 +03005010 mmc->caps2 |= MMC_CAP2_INIT_BKOPS | MMC_CAP2_BKOPS;
5011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005012 if (plat->is_sdio_al_client)
5013 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07005014
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305015 mmc->max_segs = msmsdcc_get_nr_sg(host);
5016 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
5017 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07005018
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05305019 mmc->max_req_size = MMC_MAX_REQ_SIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07005020 mmc->max_seg_size = mmc->max_req_size;
5021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005022 writel_relaxed(0, host->base + MMCIMASK0);
5023 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05305024 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005026 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
5027 mb();
5028 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07005029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005030 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
5031 DRIVER_NAME " (cmd)", host);
5032 if (ret)
5033 goto dml_exit;
5034
5035 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
5036 DRIVER_NAME " (pio)", host);
5037 if (ret)
5038 goto irq_free;
5039
5040 /*
5041 * Enable SDCC IRQ only when host is powered on. Otherwise, this
5042 * IRQ is un-necessarily being monitored by MPM (Modem power
5043 * management block) during idle-power collapse. The MPM will be
5044 * configured to monitor the DATA1 GPIO line with level-low trigger
5045 * and thus depending on the GPIO status, it prevents TCXO shutdown
5046 * during idle-power collapse.
5047 */
5048 disable_irq(core_irqres->start);
5049 host->sdcc_irq_disabled = 1;
5050
5051 if (plat->sdiowakeup_irq) {
5052 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5053 mmc_hostname(mmc));
5054 ret = request_irq(plat->sdiowakeup_irq,
5055 msmsdcc_platform_sdiowakeup_irq,
5056 IRQF_SHARED | IRQF_TRIGGER_LOW,
5057 DRIVER_NAME "sdiowakeup", host);
5058 if (ret) {
5059 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
5060 plat->sdiowakeup_irq, ret);
5061 goto pio_irq_free;
5062 } else {
5063 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305064 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005065 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305066 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005067 }
5068 spin_unlock_irqrestore(&host->lock, flags);
5069 }
5070 }
5071
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305072 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005073 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
5074 mmc_hostname(mmc));
5075 }
5076
5077 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
5078 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005079 /*
5080 * Setup card detect change
5081 */
5082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005083 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08005084 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005085 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08005086 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005087 host->oldstat = msmsdcc_slot_status(host);
San Mehat9d2bd732009-09-22 16:44:22 -07005088
Krishna Konda941604a2012-01-10 17:46:34 -08005089 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005090 }
San Mehat9d2bd732009-09-22 16:44:22 -07005091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005092 if (plat->status_irq) {
5093 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07005094 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005095 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07005096 DRIVER_NAME " (slot)",
5097 host);
5098 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005099 pr_err("Unable to get slot IRQ %d (%d)\n",
5100 plat->status_irq, ret);
5101 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005102 }
5103 } else if (plat->register_status_notify) {
5104 plat->register_status_notify(msmsdcc_status_notify_cb, host);
5105 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005106 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07005107 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005108
5109 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005110
5111 ret = pm_runtime_set_active(&(pdev)->dev);
5112 if (ret < 0)
5113 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
5114 __func__, ret);
5115 /*
5116 * There is no notion of suspend/resume for SD/MMC/SDIO
5117 * cards. So host can be suspended/resumed with out
5118 * worrying about its children.
5119 */
5120 pm_suspend_ignore_children(&(pdev)->dev, true);
5121
5122 /*
5123 * MMC/SD/SDIO bus suspend/resume operations are defined
5124 * only for the slots that will be used for non-removable
5125 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
5126 * defined. Otherwise, they simply become card removal and
5127 * insertion events during suspend and resume respectively.
5128 * Hence, enable run-time PM only for slots for which bus
5129 * suspend/resume operations are defined.
5130 */
5131#ifdef CONFIG_MMC_UNSAFE_RESUME
5132 /*
5133 * If this capability is set, MMC core will enable/disable host
5134 * for every claim/release operation on a host. We use this
5135 * notification to increment/decrement runtime pm usage count.
5136 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005137 pm_runtime_enable(&(pdev)->dev);
5138#else
5139 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005140 pm_runtime_enable(&(pdev)->dev);
5141 }
5142#endif
5143 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
5144 (unsigned long)host);
5145
San Mehat9d2bd732009-09-22 16:44:22 -07005146 mmc_add_host(mmc);
5147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005148#ifdef CONFIG_HAS_EARLYSUSPEND
5149 host->early_suspend.suspend = msmsdcc_early_suspend;
5150 host->early_suspend.resume = msmsdcc_late_resume;
5151 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
5152 register_early_suspend(&host->early_suspend);
5153#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005154
Krishna Konda25786ec2011-07-25 16:21:36 -07005155 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
5156 " dmacrcri %d\n", mmc_hostname(mmc),
5157 (unsigned long long)core_memres->start,
5158 (unsigned int) core_irqres->start,
5159 (unsigned int) plat->status_irq, host->dma.channel,
5160 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005161
5162 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
5163 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
5164 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
5165 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
5166 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
5167 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
5168 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
5169 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
5170 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
5171 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
5172 host->eject);
5173 pr_info("%s: Power save feature enable = %d\n",
5174 mmc_hostname(mmc), msmsdcc_pwrsave);
5175
Krishna Konda25786ec2011-07-25 16:21:36 -07005176 if (host->is_dma_mode && host->dma.channel != -1
5177 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005178 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005179 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005180 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005181 mmc_hostname(mmc), host->dma.cmd_busaddr,
5182 host->dma.cmdptr_busaddr);
5183 } else if (host->is_sps_mode) {
5184 pr_info("%s: SPS-BAM data transfer mode available\n",
5185 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005186 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07005187 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07005188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189#if defined(CONFIG_DEBUG_FS)
5190 msmsdcc_dbg_createhost(host);
5191#endif
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305192 if (!plat->status_irq)
5193 dev_attrs[1] = &dev_attr_polling.attr;
5194
5195 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
5196 if (ret)
5197 goto platform_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07005198 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005199
5200 platform_irq_free:
5201 del_timer_sync(&host->req_tout_timer);
5202 pm_runtime_disable(&(pdev)->dev);
5203 pm_runtime_set_suspended(&(pdev)->dev);
5204
5205 if (plat->status_irq)
5206 free_irq(plat->status_irq, host);
5207 sdiowakeup_irq_free:
5208 wake_lock_destroy(&host->sdio_suspend_wlock);
5209 if (plat->sdiowakeup_irq)
5210 free_irq(plat->sdiowakeup_irq, host);
5211 pio_irq_free:
5212 if (plat->sdiowakeup_irq)
5213 wake_lock_destroy(&host->sdio_wlock);
5214 free_irq(core_irqres->start, host);
5215 irq_free:
5216 free_irq(core_irqres->start, host);
5217 dml_exit:
5218 if (host->is_sps_mode)
5219 msmsdcc_dml_exit(host);
5220 sps_exit:
5221 if (host->is_sps_mode)
5222 msmsdcc_sps_exit(host);
5223 vreg_deinit:
5224 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005225 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005226 clk_disable(host->clk);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305227 msmsdcc_msm_bus_unregister(host);
5228 pm_qos_remove:
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005229 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305230 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005231 clk_put:
5232 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005233 pclk_disable:
5234 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305235 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005236 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005237 if (!IS_ERR(host->pclk))
5238 clk_put(host->pclk);
5239 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305240 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005241 dfab_pclk_put:
5242 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5243 clk_put(host->dfab_pclk);
5244 dma_free:
5245 if (host->is_dma_mode) {
5246 if (host->dmares)
5247 dma_free_coherent(NULL,
5248 sizeof(struct msmsdcc_nc_dmadata),
5249 host->dma.nc, host->dma.nc_busaddr);
5250 }
5251 ioremap_free:
Sahitya Tummaladce7c752011-05-02 18:06:05 +05305252 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005253 host_free:
5254 mmc_free_host(mmc);
5255 out:
5256 return ret;
5257}
5258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005259static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005260{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005261 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5262 struct mmc_platform_data *plat;
5263 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005265 if (!mmc)
5266 return -ENXIO;
5267
5268 if (pm_runtime_suspended(&(pdev)->dev))
5269 pm_runtime_resume(&(pdev)->dev);
5270
5271 host = mmc_priv(mmc);
5272
5273 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5274 plat = host->plat;
5275
5276 if (!plat->status_irq)
5277 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
5278
5279 del_timer_sync(&host->req_tout_timer);
5280 tasklet_kill(&host->dma_tlet);
5281 tasklet_kill(&host->sps.tlet);
5282 mmc_remove_host(mmc);
5283
5284 if (plat->status_irq)
5285 free_irq(plat->status_irq, host);
5286
5287 wake_lock_destroy(&host->sdio_suspend_wlock);
5288 if (plat->sdiowakeup_irq) {
5289 wake_lock_destroy(&host->sdio_wlock);
5290 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5291 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005292 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005293
5294 free_irq(host->core_irqres->start, host);
5295 free_irq(host->core_irqres->start, host);
5296
5297 clk_put(host->clk);
5298 if (!IS_ERR(host->pclk))
5299 clk_put(host->pclk);
5300 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5301 clk_put(host->dfab_pclk);
5302
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005303 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305304 pm_qos_remove_request(&host->pm_qos_req_dma);
5305
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305306 if (host->msm_bus_vote.client_handle) {
5307 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
5308 msmsdcc_msm_bus_unregister(host);
5309 }
5310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005311 msmsdcc_vreg_init(host, false);
5312
5313 if (host->is_dma_mode) {
5314 if (host->dmares)
5315 dma_free_coherent(NULL,
5316 sizeof(struct msmsdcc_nc_dmadata),
5317 host->dma.nc, host->dma.nc_busaddr);
5318 }
5319
5320 if (host->is_sps_mode) {
5321 msmsdcc_dml_exit(host);
5322 msmsdcc_sps_exit(host);
5323 }
5324
5325 iounmap(host->base);
5326 mmc_free_host(mmc);
5327
5328#ifdef CONFIG_HAS_EARLYSUSPEND
5329 unregister_early_suspend(&host->early_suspend);
5330#endif
5331 pm_runtime_disable(&(pdev)->dev);
5332 pm_runtime_set_suspended(&(pdev)->dev);
5333
5334 return 0;
5335}
5336
5337#ifdef CONFIG_MSM_SDIO_AL
5338int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5339{
5340 struct msmsdcc_host *host = mmc_priv(mmc);
5341 unsigned long flags;
5342
Asutosh Dasf5298c32012-04-03 14:51:47 +05305343 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005344 spin_lock_irqsave(&host->lock, flags);
5345 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5346 enable ? "En" : "Dis");
5347
5348 if (enable) {
5349 if (!host->sdcc_irq_disabled) {
5350 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305351 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005352 host->sdcc_irq_disabled = 1;
5353 }
5354
5355 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305356 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005357 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305358 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005359 host->clks_on = 0;
5360 }
5361
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305362 if (host->plat->sdio_lpm_gpio_setup &&
5363 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005364 spin_unlock_irqrestore(&host->lock, flags);
5365 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5366 spin_lock_irqsave(&host->lock, flags);
5367 host->sdio_gpio_lpm = 1;
5368 }
5369
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305370 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005371 msmsdcc_enable_irq_wake(host);
5372 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305373 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005374 }
5375 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305376 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005377 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305378 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005379 msmsdcc_disable_irq_wake(host);
5380 }
5381
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305382 if (host->plat->sdio_lpm_gpio_setup &&
5383 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005384 spin_unlock_irqrestore(&host->lock, flags);
5385 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5386 spin_lock_irqsave(&host->lock, flags);
5387 host->sdio_gpio_lpm = 0;
5388 }
5389
5390 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305391 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005392 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305393 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005394 host->clks_on = 1;
5395 }
5396
5397 if (host->sdcc_irq_disabled) {
5398 writel_relaxed(host->mci_irqenable,
5399 host->base + MMCIMASK0);
5400 mb();
5401 enable_irq(host->core_irqres->start);
5402 host->sdcc_irq_disabled = 0;
5403 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005404 }
5405 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305406 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005407 return 0;
5408}
5409#else
5410int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5411{
5412 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005413}
5414#endif
5415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005416#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005417static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005418msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005419{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005420 struct mmc_host *mmc = dev_get_drvdata(dev);
5421 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005422 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305423 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005424
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305425 if (host->plat->is_sdio_al_client) {
5426 rc = 0;
5427 goto out;
San Mehat9d2bd732009-09-22 16:44:22 -07005428 }
San Mehat9d2bd732009-09-22 16:44:22 -07005429
Sahitya Tummala7661a452011-07-18 13:28:35 +05305430 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005431 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005432 host->sdcc_suspending = 1;
5433 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005435 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005436 * MMC core thinks that host is disabled by now since
5437 * runtime suspend is scheduled after msmsdcc_disable()
5438 * is called. Thus, MMC core will try to enable the host
5439 * while suspending it. This results in a synchronous
5440 * runtime resume request while in runtime suspending
5441 * context and hence inorder to complete this resume
5442 * requet, it will wait for suspend to be complete,
5443 * but runtime suspend also can not proceed further
5444 * until the host is resumed. Thus, it leads to a hang.
5445 * Hence, increase the pm usage count before suspending
5446 * the host so that any resume requests after this will
5447 * simple become pm usage counter increment operations.
5448 */
5449 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305450 /* If there is pending detect work abort runtime suspend */
5451 if (unlikely(work_busy(&mmc->detect.work)))
5452 rc = -EAGAIN;
5453 else
5454 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005455 pm_runtime_put_noidle(dev);
5456
5457 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305458 spin_lock_irqsave(&host->lock, flags);
5459 host->sdcc_suspended = true;
5460 spin_unlock_irqrestore(&host->lock, flags);
5461 if (mmc->card && mmc_card_sdio(mmc->card) &&
5462 mmc->ios.clock) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07005463#ifdef CONFIG_MMC_CLKGATE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005464 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305465 * If SDIO function driver doesn't want
5466 * to power off the card, atleast turn off
5467 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005468 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305469 mmc_host_clk_hold(mmc);
5470 spin_lock_irqsave(&mmc->clk_lock, flags);
5471 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005472 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305473 mmc->clk_gated = true;
5474 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5475 mmc_set_ios(mmc);
5476 mmc_host_clk_release(mmc);
Steve Mucklef132c6c2012-06-06 18:30:57 -07005477#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005478 }
5479 }
5480 host->sdcc_suspending = 0;
5481 mmc->suspend_task = NULL;
5482 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5483 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005484 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305485 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
Subhash Jadavanibcd435f2012-04-24 18:26:49 +05305486out:
5487 /* set bus bandwidth to 0 immediately */
5488 msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
San Mehat9d2bd732009-09-22 16:44:22 -07005489 return rc;
5490}
5491
5492static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005493msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005494{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005495 struct mmc_host *mmc = dev_get_drvdata(dev);
5496 struct msmsdcc_host *host = mmc_priv(mmc);
5497 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07005498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005499 if (host->plat->is_sdio_al_client)
5500 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005501
Sahitya Tummala7661a452011-07-18 13:28:35 +05305502 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005503 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305504 if (mmc->card && mmc_card_sdio(mmc->card) &&
5505 mmc_card_keep_power(mmc)) {
5506 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305507 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305508 mmc_set_ios(mmc);
5509 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305510 }
San Mehat9d2bd732009-09-22 16:44:22 -07005511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005512 mmc_resume_host(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005514 /*
5515 * FIXME: Clearing of flags must be handled in clients
5516 * resume handler.
5517 */
5518 spin_lock_irqsave(&host->lock, flags);
5519 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305520 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005521 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07005522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005523 /*
5524 * After resuming the host wait for sometime so that
5525 * the SDIO work will be processed.
5526 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305527 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305528 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005529 host->plat->sdiowakeup_irq) &&
5530 wake_lock_active(&host->sdio_wlock))
5531 wake_lock_timeout(&host->sdio_wlock, 1);
5532 }
5533
5534 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005535 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305536 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005537 return 0;
5538}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005539
5540static int msmsdcc_runtime_idle(struct device *dev)
5541{
5542 struct mmc_host *mmc = dev_get_drvdata(dev);
5543 struct msmsdcc_host *host = mmc_priv(mmc);
5544
5545 if (host->plat->is_sdio_al_client)
5546 return 0;
5547
5548 /* Idle timeout is not configurable for now */
5549 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5550
5551 return -EAGAIN;
5552}
5553
5554static int msmsdcc_pm_suspend(struct device *dev)
5555{
5556 struct mmc_host *mmc = dev_get_drvdata(dev);
5557 struct msmsdcc_host *host = mmc_priv(mmc);
5558 int rc = 0;
5559
5560 if (host->plat->is_sdio_al_client)
5561 return 0;
5562
5563
5564 if (host->plat->status_irq)
5565 disable_irq(host->plat->status_irq);
5566
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005567 if (!pm_runtime_suspended(dev))
5568 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005569
5570 return rc;
5571}
5572
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305573static int msmsdcc_suspend_noirq(struct device *dev)
5574{
5575 struct mmc_host *mmc = dev_get_drvdata(dev);
5576 struct msmsdcc_host *host = mmc_priv(mmc);
5577 int rc = 0;
5578
5579 /*
5580 * After platform suspend there may be active request
5581 * which might have enabled clocks. For example, in SDIO
5582 * case, ksdioirq thread might have scheduled after sdcc
5583 * suspend but before system freeze. In that case abort
5584 * suspend and retry instead of keeping the clocks on
5585 * during suspend and not allowing TCXO.
5586 */
5587
Asutosh Dasf5298c32012-04-03 14:51:47 +05305588 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305589 pr_warn("%s: clocks are on after suspend, aborting system "
5590 "suspend\n", mmc_hostname(mmc));
5591 rc = -EAGAIN;
5592 }
5593
5594 return rc;
5595}
5596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005597static int msmsdcc_pm_resume(struct device *dev)
5598{
5599 struct mmc_host *mmc = dev_get_drvdata(dev);
5600 struct msmsdcc_host *host = mmc_priv(mmc);
5601 int rc = 0;
5602
5603 if (host->plat->is_sdio_al_client)
5604 return 0;
5605
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005606 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305607 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005608 else
5609 host->pending_resume = true;
5610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611 if (host->plat->status_irq) {
5612 msmsdcc_check_status((unsigned long)host);
5613 enable_irq(host->plat->status_irq);
5614 }
5615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005616 return rc;
5617}
5618
Daniel Walker08ecfde2010-06-23 12:32:20 -07005619#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005620static int msmsdcc_runtime_suspend(struct device *dev)
5621{
5622 return 0;
5623}
5624static int msmsdcc_runtime_idle(struct device *dev)
5625{
5626 return 0;
5627}
5628static int msmsdcc_pm_suspend(struct device *dev)
5629{
5630 return 0;
5631}
5632static int msmsdcc_pm_resume(struct device *dev)
5633{
5634 return 0;
5635}
5636static int msmsdcc_suspend_noirq(struct device *dev)
5637{
5638 return 0;
5639}
5640static int msmsdcc_runtime_resume(struct device *dev)
5641{
5642 return 0;
5643}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005644#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005646static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5647 .runtime_suspend = msmsdcc_runtime_suspend,
5648 .runtime_resume = msmsdcc_runtime_resume,
5649 .runtime_idle = msmsdcc_runtime_idle,
5650 .suspend = msmsdcc_pm_suspend,
5651 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305652 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005653};
5654
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305655static const struct of_device_id msmsdcc_dt_match[] = {
5656 {.compatible = "qcom,msm-sdcc"},
5657
5658};
5659MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5660
San Mehat9d2bd732009-09-22 16:44:22 -07005661static struct platform_driver msmsdcc_driver = {
5662 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005663 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005664 .driver = {
5665 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005666 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305667 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005668 },
5669};
5670
5671static int __init msmsdcc_init(void)
5672{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005673#if defined(CONFIG_DEBUG_FS)
5674 int ret = 0;
5675 ret = msmsdcc_dbg_init();
5676 if (ret) {
5677 pr_err("Failed to create debug fs dir \n");
5678 return ret;
5679 }
5680#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005681 return platform_driver_register(&msmsdcc_driver);
5682}
San Mehat9d2bd732009-09-22 16:44:22 -07005683
San Mehat9d2bd732009-09-22 16:44:22 -07005684static void __exit msmsdcc_exit(void)
5685{
5686 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005687
5688#if defined(CONFIG_DEBUG_FS)
5689 debugfs_remove(debugfs_file);
5690 debugfs_remove(debugfs_dir);
5691#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005692}
5693
5694module_init(msmsdcc_init);
5695module_exit(msmsdcc_exit);
5696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005697MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005698MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005699
5700#if defined(CONFIG_DEBUG_FS)
5701
5702static int
5703msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5704{
5705 file->private_data = inode->i_private;
5706 return 0;
5707}
5708
5709static ssize_t
5710msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5711 size_t count, loff_t *ppos)
5712{
5713 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005714 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005715 int max, i;
5716
5717 i = 0;
5718 max = sizeof(buf) - 1;
5719
5720 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5721 host->curr.cmd, host->curr.data);
5722 if (host->curr.cmd) {
5723 struct mmc_command *cmd = host->curr.cmd;
5724
5725 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5726 cmd->opcode, cmd->arg, cmd->flags);
5727 }
5728 if (host->curr.data) {
5729 struct mmc_data *data = host->curr.data;
5730 i += scnprintf(buf + i, max - i,
5731 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5732 data->timeout_ns, data->timeout_clks,
5733 data->blksz, data->blocks, data->error,
5734 data->flags);
5735 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5736 host->curr.xfer_size, host->curr.xfer_remain,
5737 host->curr.data_xfered, host->dma.sg);
5738 }
5739
5740 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5741}
5742
5743static const struct file_operations msmsdcc_dbg_state_ops = {
5744 .read = msmsdcc_dbg_state_read,
5745 .open = msmsdcc_dbg_state_open,
5746};
5747
5748static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5749{
5750 if (debugfs_dir) {
5751 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5752 0644, debugfs_dir, host,
5753 &msmsdcc_dbg_state_ops);
5754 }
5755}
5756
5757static int __init msmsdcc_dbg_init(void)
5758{
5759 int err;
5760
5761 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5762 if (IS_ERR(debugfs_dir)) {
5763 err = PTR_ERR(debugfs_dir);
5764 debugfs_dir = NULL;
5765 return err;
5766 }
5767
5768 return 0;
5769}
5770#endif