blob: 6a02f48f8c383e691f3f922e573a0d8bd5e90277 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
Subhash Jadavani933e6a62011-12-26 18:05:04 +053046#include <linux/pm_qos_params.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
56#include <mach/htc_pwrsink.h>
57#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070058
San Mehat9d2bd732009-09-22 16:44:22 -070059#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070061
62#define DRIVER_NAME "msm-sdcc"
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#define DBG(host, fmt, args...) \
65 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
66
67#define IRQ_DEBUG 0
68#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
69#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
70#define SPS_CONS_PERIPHERAL 0
71#define SPS_PROD_PERIPHERAL 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072
73#if defined(CONFIG_DEBUG_FS)
74static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
75static struct dentry *debugfs_dir;
76static struct dentry *debugfs_file;
77static int msmsdcc_dbg_init(void);
78#endif
79
Subhash Jadavani8766e352011-11-30 11:30:32 +053080static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070081static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083static struct mmc_command dummy52cmd;
84static struct mmc_request dummy52mrq = {
85 .cmd = &dummy52cmd,
86 .data = NULL,
87 .stop = NULL,
88};
89static struct mmc_command dummy52cmd = {
90 .opcode = SD_IO_RW_DIRECT,
91 .flags = MMC_RSP_PRESENT,
92 .data = NULL,
93 .mrq = &dummy52mrq,
94};
95/*
96 * An array holding the Tuning pattern to compare with when
97 * executing a tuning cycle.
98 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +053099static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
101 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
102 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
103 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
104};
San Mehat865c8062009-11-13 13:42:06 -0800105
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530106static const u32 tuning_block_128[] = {
107 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
108 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
109 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
110 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
111 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
112 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
113 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
114 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
115};
116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117#if IRQ_DEBUG == 1
118static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
119 "dattimeout", "txunderrun", "rxoverrun",
120 "cmdrespend", "cmdsent", "dataend", NULL,
121 "datablkend", "cmdactive", "txactive",
122 "rxactive", "txhalfempty", "rxhalffull",
123 "txfifofull", "rxfifofull", "txfifoempty",
124 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
125 "sdiointr", "progdone", "atacmdcompl",
126 "sdiointrope", "ccstimeout", NULL, NULL,
127 NULL, NULL, NULL };
128
129static void
130msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800131{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
135 for (i = 0; i < 32; i++) {
136 if (status & (1 << i))
137 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800138 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800140}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141#endif
San Mehat865c8062009-11-13 13:42:06 -0800142
San Mehat9d2bd732009-09-22 16:44:22 -0700143static void
144msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
145 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530146static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530147static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800148static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800149static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530150
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530151static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
152{
153 unsigned short ret = NR_SG;
154
155 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530156 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530157 } else { /* DMA or PIO mode */
158 if (NR_SG > MAX_NR_SG_DMA_PIO)
159 ret = MAX_NR_SG_DMA_PIO;
160 }
161
162 return ret;
163}
164
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530165/* Prevent idle power collapse(pc) while operating in peripheral mode */
166static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
167{
168 u32 swfi_latency = 0;
169
170 if (!host->plat->swfi_latency)
171 return;
172
173 swfi_latency = host->plat->swfi_latency + 1;
174
175 if (vote)
176 pm_qos_update_request(&host->pm_qos_req_dma,
177 swfi_latency);
178 else
179 pm_qos_update_request(&host->pm_qos_req_dma,
180 PM_QOS_DEFAULT_VALUE);
181}
182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
184static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
185 struct msmsdcc_sps_ep_conn_data *ep);
186static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
187 struct msmsdcc_sps_ep_conn_data *ep);
188#else
189static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep,
191 bool is_producer) { return 0; }
192static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep) { }
194static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
195 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530196{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 return 0;
198}
199static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
200 struct msmsdcc_sps_ep_conn_data *ep)
201{
202 return 0;
203}
204static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
205static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
206#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530209 * Apply soft reset to all SDCC BAM pipes
210 *
211 * This function applies soft reset to SDCC BAM pipe.
212 *
213 * This function should be called to recover from error
214 * conditions encountered during CMD/DATA tranfsers with card.
215 *
216 * @host - Pointer to driver's host structure
217 *
218 */
219static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
220{
221 int rc;
222
223 /* Reset all SDCC BAM pipes */
224 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
225 if (rc)
226 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
227 mmc_hostname(host->mmc), rc);
228 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
229 if (rc)
230 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
231 mmc_hostname(host->mmc), rc);
232
233 /* Restore all BAM pipes connections */
234 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
235 if (rc)
236 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
237 mmc_hostname(host->mmc), rc);
238 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
239 if (rc)
240 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
241 mmc_hostname(host->mmc), rc);
242}
243
244/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 * Apply soft reset
246 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530247 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 *
249 * This function should be called to recover from error
250 * conditions encountered with CMD/DATA tranfsers with card.
251 *
252 * Soft reset should only be used with SDCC controller v4.
253 *
254 * @host - Pointer to driver's host structure
255 *
256 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530257static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 /*
260 * Reset SDCC controller's DPSM (data path state machine
261 * and CPSM (command path state machine).
262 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530264 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530266 msmsdcc_delay(host);
267}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530268
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530269static void msmsdcc_hard_reset(struct msmsdcc_host *host)
270{
271 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530272
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530273 /* Reset the controller */
274 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
275 if (ret)
276 pr_err("%s: Clock assert failed at %u Hz"
277 " with err %d\n", mmc_hostname(host->mmc),
278 host->clk_rate, ret);
279
280 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
281 if (ret)
282 pr_err("%s: Clock deassert failed at %u Hz"
283 " with err %d\n", mmc_hostname(host->mmc),
284 host->clk_rate, ret);
285
286 /* Give some delay for clock reset to propogate to controller */
287 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530288}
289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
291{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530292 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530293 if (host->is_sps_mode) {
294 /* Reset DML first */
295 msmsdcc_dml_reset(host);
296 /*
297 * delay the SPS pipe reset in thread context as
298 * sps_connect/sps_disconnect APIs can be called
299 * only from non-atomic context.
300 */
301 host->sps.pipe_reset_pending = true;
302 }
303 mb();
304 msmsdcc_soft_reset(host);
305
306 pr_debug("%s: Applied soft reset to Controller\n",
307 mmc_hostname(host->mmc));
308
309 if (host->is_sps_mode)
310 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 } else {
312 /* Give Clock reset (hard reset) to controller */
313 u32 mci_clk = 0;
314 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315
316 /* Save the controller state */
317 mci_clk = readl_relaxed(host->base + MMCICLOCK);
318 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530321 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 pr_debug("%s: Controller has been reinitialized\n",
323 mmc_hostname(host->mmc));
324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325 /* Restore the contoller state */
326 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530327 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530329 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530331 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530333
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700334 if (host->dummy_52_needed)
335 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336}
337
338static int
San Mehat9d2bd732009-09-22 16:44:22 -0700339msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
340{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 int retval = 0;
342
San Mehat9d2bd732009-09-22 16:44:22 -0700343 BUG_ON(host->curr.data);
344
345 host->curr.mrq = NULL;
346 host->curr.cmd = NULL;
347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 del_timer(&host->req_tout_timer);
349
San Mehat9d2bd732009-09-22 16:44:22 -0700350 if (mrq->data)
351 mrq->data->bytes_xfered = host->curr.data_xfered;
352 if (mrq->cmd->error == -ETIMEDOUT)
353 mdelay(5);
354
355 /*
356 * Need to drop the host lock here; mmc_request_done may call
357 * back into the driver...
358 */
359 spin_unlock(&host->lock);
360 mmc_request_done(host->mmc, mrq);
361 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
363 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700364}
365
366static void
367msmsdcc_stop_data(struct msmsdcc_host *host)
368{
San Mehat9d2bd732009-09-22 16:44:22 -0700369 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530370 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530371 host->curr.wait_for_auto_prog_done = 0;
372 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700373 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
374 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700375 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700376}
377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700379{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 return host->core_memres->start + MMCIFIFO;
381}
382
383static inline unsigned int msmsdcc_get_min_sup_clk_rate(
384 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static inline void msmsdcc_delay(struct msmsdcc_host *host)
387{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530388 ktime_t start, diff;
389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530391 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530392
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530393 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530394 (readl_relaxed(host->base + MCI_STATUS2) &
395 MCI_MCLK_REG_WR_ACTIVE)) {
396 start = ktime_get();
397 while (readl_relaxed(host->base + MCI_STATUS2) &
398 MCI_MCLK_REG_WR_ACTIVE) {
399 diff = ktime_sub(ktime_get(), start);
400 /* poll for max. 1 ms */
401 if (ktime_to_us(diff) > 1000) {
402 pr_warning("%s: previous reg. write is"
403 " still active\n",
404 mmc_hostname(host->mmc));
405 break;
406 }
407 }
408 }
San Mehat9d2bd732009-09-22 16:44:22 -0700409}
410
San Mehat56a8b5b2009-11-21 12:29:46 -0800411static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
413{
414 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530416 /*
417 * As after sending the command, we don't write any of the
418 * controller registers and just wait for the
419 * CMD_RESPOND_END/CMD_SENT/Command failure notication
420 * from Controller.
421 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800423}
424
425static void
426msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
427{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
431 writel_relaxed((unsigned int)host->curr.xfer_size,
432 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
434 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800435
San Mehat6ac9ea62009-12-02 17:24:58 -0800436 if (host->cmd_cmd) {
437 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800439 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800440}
441
San Mehat9d2bd732009-09-22 16:44:22 -0700442static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530443msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700444{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530445 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700446 unsigned long flags;
447 struct mmc_request *mrq;
448
449 spin_lock_irqsave(&host->lock, flags);
450 mrq = host->curr.mrq;
451 BUG_ON(!mrq);
452
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700454 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700455 goto out;
456 }
457
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700459 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700461 } else {
462 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530463 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700464 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530465 mmc_hostname(host->mmc), host->dma.result);
466 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700467 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530468 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530469 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 host->dma.err.flush[0], host->dma.err.flush[1],
471 host->dma.err.flush[2], host->dma.err.flush[3],
472 host->dma.err.flush[4],
473 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530474 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700475 if (!mrq->data->error)
476 mrq->data->error = -EIO;
477 }
San Mehat9d2bd732009-09-22 16:44:22 -0700478 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
479 host->dma.dir);
480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 if (host->curr.user_pages) {
482 struct scatterlist *sg = host->dma.sg;
483 int i;
484
485 for (i = 0; i < host->dma.num_ents; i++, sg++)
486 flush_dcache_page(sg_page(sg));
487 }
488
San Mehat9d2bd732009-09-22 16:44:22 -0700489 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800490 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700491
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530492 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
493 (host->curr.wait_for_auto_prog_done &&
494 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700495 /*
496 * If we've already gotten our DATAEND / DATABLKEND
497 * for this request, then complete it through here.
498 */
San Mehat9d2bd732009-09-22 16:44:22 -0700499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700501 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 host->curr.xfer_remain -= host->curr.xfer_size;
503 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700504 if (host->dummy_52_needed) {
505 mrq->data->bytes_xfered = host->curr.data_xfered;
506 host->dummy_52_sent = 1;
507 msmsdcc_start_command(host, &dummy52cmd,
508 MCI_CPSM_PROGENA);
509 goto out;
510 }
511 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530512 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530513 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700514 host->curr.mrq = NULL;
515 host->curr.cmd = NULL;
516 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700518 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519
San Mehat9d2bd732009-09-22 16:44:22 -0700520 mmc_request_done(host->mmc, mrq);
521 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530522 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
523 || !mrq->sbc)) {
524 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530525 }
San Mehat9d2bd732009-09-22 16:44:22 -0700526 }
527
528out:
529 spin_unlock_irqrestore(&host->lock, flags);
530 return;
531}
532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
534/**
535 * Callback notification from SPS driver
536 *
537 * This callback function gets triggered called from
538 * SPS driver when requested SPS data transfer is
539 * completed.
540 *
541 * SPS driver invokes this callback in BAM irq context so
542 * SDCC driver schedule a tasklet for further processing
543 * this callback notification at later point of time in
544 * tasklet context and immediately returns control back
545 * to SPS driver.
546 *
547 * @nofity - Pointer to sps event notify sturcture
548 *
549 */
550static void
551msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
552{
553 struct msmsdcc_host *host =
554 (struct msmsdcc_host *)
555 ((struct sps_event_notify *)notify)->user;
556
557 host->sps.notify = *notify;
558 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
559 mmc_hostname(host->mmc), __func__, notify->event_id,
560 notify->data.transfer.iovec.addr,
561 notify->data.transfer.iovec.size,
562 notify->data.transfer.iovec.flags);
563 /* Schedule a tasklet for completing data transfer */
564 tasklet_schedule(&host->sps.tlet);
565}
566
567/**
568 * Tasklet handler for processing SPS callback event
569 *
570 * This function processing SPS event notification and
571 * checks if the SPS transfer is completed or not and
572 * then accordingly notifies status to MMC core layer.
573 *
574 * This function is called in tasklet context.
575 *
576 * @data - Pointer to sdcc driver data
577 *
578 */
579static void msmsdcc_sps_complete_tlet(unsigned long data)
580{
581 unsigned long flags;
582 int i, rc;
583 u32 data_xfered = 0;
584 struct mmc_request *mrq;
585 struct sps_iovec iovec;
586 struct sps_pipe *sps_pipe_handle;
587 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
588 struct sps_event_notify *notify = &host->sps.notify;
589
590 spin_lock_irqsave(&host->lock, flags);
591 if (host->sps.dir == DMA_FROM_DEVICE)
592 sps_pipe_handle = host->sps.prod.pipe_handle;
593 else
594 sps_pipe_handle = host->sps.cons.pipe_handle;
595 mrq = host->curr.mrq;
596
597 if (!mrq) {
598 spin_unlock_irqrestore(&host->lock, flags);
599 return;
600 }
601
602 pr_debug("%s: %s: sps event_id=%d\n",
603 mmc_hostname(host->mmc), __func__,
604 notify->event_id);
605
606 if (msmsdcc_is_dml_busy(host)) {
607 /* oops !!! this should never happen. */
608 pr_err("%s: %s: Received SPS EOT event"
609 " but DML HW is still busy !!!\n",
610 mmc_hostname(host->mmc), __func__);
611 }
612 /*
613 * Got End of transfer event!!! Check if all of the data
614 * has been transferred?
615 */
616 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
617 rc = sps_get_iovec(sps_pipe_handle, &iovec);
618 if (rc) {
619 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
620 mmc_hostname(host->mmc), __func__, rc, i);
621 break;
622 }
623 data_xfered += iovec.size;
624 }
625
626 if (data_xfered == host->curr.xfer_size) {
627 host->curr.data_xfered = host->curr.xfer_size;
628 host->curr.xfer_remain -= host->curr.xfer_size;
629 pr_debug("%s: Data xfer success. data_xfered=0x%x",
630 mmc_hostname(host->mmc),
631 host->curr.xfer_size);
632 } else {
633 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
634 " xfer_size=%d", mmc_hostname(host->mmc),
635 data_xfered, host->curr.xfer_size);
636 msmsdcc_reset_and_restore(host);
637 if (!mrq->data->error)
638 mrq->data->error = -EIO;
639 }
640
641 /* Unmap sg buffers */
642 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
643 host->sps.dir);
644
645 host->sps.sg = NULL;
646 host->sps.busy = 0;
647
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530648 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
649 (host->curr.wait_for_auto_prog_done &&
650 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 /*
652 * If we've already gotten our DATAEND / DATABLKEND
653 * for this request, then complete it through here.
654 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655
656 if (!mrq->data->error) {
657 host->curr.data_xfered = host->curr.xfer_size;
658 host->curr.xfer_remain -= host->curr.xfer_size;
659 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700660 if (host->dummy_52_needed) {
661 mrq->data->bytes_xfered = host->curr.data_xfered;
662 host->dummy_52_sent = 1;
663 msmsdcc_start_command(host, &dummy52cmd,
664 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700665 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700666 return;
667 }
668 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530669 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530670 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 host->curr.mrq = NULL;
672 host->curr.cmd = NULL;
673 mrq->data->bytes_xfered = host->curr.data_xfered;
674 del_timer(&host->req_tout_timer);
675 spin_unlock_irqrestore(&host->lock, flags);
676
677 mmc_request_done(host->mmc, mrq);
678 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530679 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
680 || !mrq->sbc)) {
681 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 }
683 }
684 spin_unlock_irqrestore(&host->lock, flags);
685}
686
687/**
688 * Exit from current SPS data transfer
689 *
690 * This function exits from current SPS data transfer.
691 *
692 * This function should be called when error condition
693 * is encountered during data transfer.
694 *
695 * @host - Pointer to sdcc host structure
696 *
697 */
698static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
699{
700 struct mmc_request *mrq;
701
702 mrq = host->curr.mrq;
703 BUG_ON(!mrq);
704
705 msmsdcc_reset_and_restore(host);
706 if (!mrq->data->error)
707 mrq->data->error = -EIO;
708
709 /* Unmap sg buffers */
710 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
711 host->sps.dir);
712
713 host->sps.sg = NULL;
714 host->sps.busy = 0;
715 if (host->curr.data)
716 msmsdcc_stop_data(host);
717
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530718 if (!mrq->data->stop || mrq->cmd->error ||
719 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530721 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
722 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 msmsdcc_start_command(host, mrq->data->stop, 0);
724
725}
726#else
727static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
728static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
729static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
730#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
731
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530732static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530734static void
735msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
736 unsigned int result,
737 struct msm_dmov_errdata *err)
738{
739 struct msmsdcc_dma_data *dma_data =
740 container_of(cmd, struct msmsdcc_dma_data, hdr);
741 struct msmsdcc_host *host = dma_data->host;
742
743 dma_data->result = result;
744 if (err)
745 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
746
747 tasklet_schedule(&host->dma_tlet);
748}
749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700751{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700752 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
753 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700754 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700755 else
756 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700757}
758
759static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
760{
761 struct msmsdcc_nc_dmadata *nc;
762 dmov_box *box;
763 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700764 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530765 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700766 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530767 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700768
Krishna Konda25786ec2011-07-25 16:21:36 -0700769 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700771
Krishna Konda25786ec2011-07-25 16:21:36 -0700772 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
773
San Mehat9d2bd732009-09-22 16:44:22 -0700774 host->dma.sg = data->sg;
775 host->dma.num_ents = data->sg_len;
776
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530777 /* Prevent memory corruption */
778 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800779
San Mehat9d2bd732009-09-22 16:44:22 -0700780 nc = host->dma.nc;
781
San Mehat9d2bd732009-09-22 16:44:22 -0700782 if (data->flags & MMC_DATA_READ)
783 host->dma.dir = DMA_FROM_DEVICE;
784 else
785 host->dma.dir = DMA_TO_DEVICE;
786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
788 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789
790 if (n != host->dma.num_ents) {
791 pr_err("%s: Unable to map in all sg elements\n",
792 mmc_hostname(host->mmc));
793 host->dma.sg = NULL;
794 host->dma.num_ents = 0;
795 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800796 }
San Mehat9d2bd732009-09-22 16:44:22 -0700797
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530798 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
799 host->curr.user_pages = 0;
800 box = &nc->cmd[0];
801 for (i = 0; i < host->dma.num_ents; i++) {
802 len = sg_dma_len(sg);
803 offset = 0;
804
805 do {
806 /* Check if we can do DMA */
807 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
808 err = -ENOTSUPP;
809 goto unmap;
810 }
811
812 box->cmd = CMD_MODE_BOX;
813
814 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
815 len = MMC_MAX_DMA_BOX_LENGTH;
816 len -= len % data->blksz;
817 }
818 rows = (len % MCI_FIFOSIZE) ?
819 (len / MCI_FIFOSIZE) + 1 :
820 (len / MCI_FIFOSIZE);
821
822 if (data->flags & MMC_DATA_READ) {
823 box->src_row_addr = msmsdcc_fifo_addr(host);
824 box->dst_row_addr = sg_dma_address(sg) + offset;
825 box->src_dst_len = (MCI_FIFOSIZE << 16) |
826 (MCI_FIFOSIZE);
827 box->row_offset = MCI_FIFOSIZE;
828 box->num_rows = rows * ((1 << 16) + 1);
829 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
830 } else {
831 box->src_row_addr = sg_dma_address(sg) + offset;
832 box->dst_row_addr = msmsdcc_fifo_addr(host);
833 box->src_dst_len = (MCI_FIFOSIZE << 16) |
834 (MCI_FIFOSIZE);
835 box->row_offset = (MCI_FIFOSIZE << 16);
836 box->num_rows = rows * ((1 << 16) + 1);
837 box->cmd |= CMD_DST_CRCI(host->dma.crci);
838 }
839
840 offset += len;
841 len = sg_dma_len(sg) - offset;
842 box++;
843 box_cmd_cnt++;
844 } while (len);
845 sg++;
846 }
847 /* Mark last command */
848 box--;
849 box->cmd |= CMD_LC;
850
851 /* location of command block must be 64 bit aligned */
852 BUG_ON(host->dma.cmd_busaddr & 0x07);
853
854 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
855 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
856 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
857 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
858
859 /* Flush all data to memory before starting dma */
860 mb();
861
862unmap:
863 if (err) {
864 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
865 host->dma.num_ents, host->dma.dir);
866 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
867 mmc_hostname(host->mmc), err);
868 }
869
870 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700871}
872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
874/**
875 * Submits data transfer request to SPS driver
876 *
877 * This function make sg (scatter gather) data buffers
878 * DMA ready and then submits them to SPS driver for
879 * transfer.
880 *
881 * @host - Pointer to sdcc host structure
882 * @data - Pointer to mmc_data structure
883 *
884 * @return 0 if success else negative value
885 */
886static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
887 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800888{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 int rc = 0;
890 u32 flags;
891 int i;
892 u32 addr, len, data_cnt;
893 struct scatterlist *sg = data->sg;
894 struct sps_pipe *sps_pipe_handle;
895
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530896 /* Prevent memory corruption */
897 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898
899 host->sps.sg = data->sg;
900 host->sps.num_ents = data->sg_len;
901 host->sps.xfer_req_cnt = 0;
902 if (data->flags & MMC_DATA_READ) {
903 host->sps.dir = DMA_FROM_DEVICE;
904 sps_pipe_handle = host->sps.prod.pipe_handle;
905 } else {
906 host->sps.dir = DMA_TO_DEVICE;
907 sps_pipe_handle = host->sps.cons.pipe_handle;
908 }
909
910 /* Make sg buffers DMA ready */
911 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
912 host->sps.dir);
913
914 if (rc != data->sg_len) {
915 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
916 mmc_hostname(host->mmc), rc);
917 host->sps.sg = NULL;
918 host->sps.num_ents = 0;
919 rc = -ENOMEM;
920 goto dma_map_err;
921 }
922
923 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
924 mmc_hostname(host->mmc), __func__,
925 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
926 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
927
928 for (i = 0; i < data->sg_len; i++) {
929 /*
930 * Check if this is the last buffer to transfer?
931 * If yes then set the INT and EOT flags.
932 */
933 len = sg_dma_len(sg);
934 addr = sg_dma_address(sg);
935 flags = 0;
936 while (len > 0) {
937 if (len > SPS_MAX_DESC_SIZE) {
938 data_cnt = SPS_MAX_DESC_SIZE;
939 } else {
940 data_cnt = len;
941 if (i == data->sg_len - 1)
942 flags = SPS_IOVEC_FLAG_INT |
943 SPS_IOVEC_FLAG_EOT;
944 }
945 rc = sps_transfer_one(sps_pipe_handle, addr,
946 data_cnt, host, flags);
947 if (rc) {
948 pr_err("%s: sps_transfer_one() error! rc=%d,"
949 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
950 mmc_hostname(host->mmc), rc,
951 (u32)sps_pipe_handle, (u32)sg, i);
952 goto dma_map_err;
953 }
954 addr += data_cnt;
955 len -= data_cnt;
956 host->sps.xfer_req_cnt++;
957 }
958 sg++;
959 }
960 goto out;
961
962dma_map_err:
963 /* unmap sg buffers */
964 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
965 host->sps.dir);
966out:
967 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700968}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969#else
970static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
971 struct mmc_data *data) { return 0; }
972#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700973
974static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800975msmsdcc_start_command_deferred(struct msmsdcc_host *host,
976 struct mmc_command *cmd, u32 *c)
977{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530978 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 cmd->opcode, cmd->arg, cmd->flags);
980
San Mehat56a8b5b2009-11-21 12:29:46 -0800981 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
982
983 if (cmd->flags & MMC_RSP_PRESENT) {
984 if (cmd->flags & MMC_RSP_136)
985 *c |= MCI_CPSM_LONGRSP;
986 *c |= MCI_CPSM_RESPONSE;
987 }
988
989 if (/*interrupt*/0)
990 *c |= MCI_CPSM_INTERRUPT;
991
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530992 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
993 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
994 cmd->opcode == MMC_WRITE_BLOCK ||
995 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
996 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800997 *c |= MCI_CSPM_DATCMD;
998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301000 if (host->tuning_needed &&
1001 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1002
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301003 /*
1004 * For open ended block read operation (without CMD23),
1005 * AUTO_CMD19 bit should be set while sending the READ command.
1006 * For close ended block read operation (with CMD23),
1007 * AUTO_CMD19 bit should be set while sending CMD23.
1008 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301009 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1010 host->curr.mrq->cmd->opcode ==
1011 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301012 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301013 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1014 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301015 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1016 *c |= MCI_CSPM_AUTO_CMD19;
1017 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 }
1019
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301020 /* Clear CDR_EN bit for write operations */
1021 if (host->tuning_needed && cmd->mrq->data &&
1022 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1023 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1024 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1025
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301026 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301027 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301029 }
1030
San Mehat56a8b5b2009-11-21 12:29:46 -08001031 if (cmd == cmd->mrq->stop)
1032 *c |= MCI_CSPM_MCIABORT;
1033
San Mehat56a8b5b2009-11-21 12:29:46 -08001034 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 pr_err("%s: Overlapping command requests\n",
1036 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001037 }
1038 host->curr.cmd = cmd;
1039}
1040
1041static void
1042msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1043 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001044{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301045 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001046 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001048 unsigned int pio_irqmask = 0;
1049
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301050 BUG_ON(!data->sg);
1051 BUG_ON(!data->sg_len);
1052
San Mehat9d2bd732009-09-22 16:44:22 -07001053 host->curr.data = data;
1054 host->curr.xfer_size = data->blksz * data->blocks;
1055 host->curr.xfer_remain = host->curr.xfer_size;
1056 host->curr.data_xfered = 0;
1057 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301058 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001059
San Mehat9d2bd732009-09-22 16:44:22 -07001060 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1061
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301062 if (host->curr.wait_for_auto_prog_done)
1063 datactrl |= MCI_AUTO_PROG_DONE;
1064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 if (!msmsdcc_check_dma_op_req(data)) {
1066 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1067 datactrl |= MCI_DPSM_DMAENABLE;
1068 } else if (host->is_sps_mode) {
1069 if (!msmsdcc_is_dml_busy(host)) {
1070 if (!msmsdcc_sps_start_xfer(host, data)) {
1071 /* Now kick start DML transfer */
1072 mb();
1073 msmsdcc_dml_start_xfer(host, data);
1074 datactrl |= MCI_DPSM_DMAENABLE;
1075 host->sps.busy = 1;
1076 }
1077 } else {
1078 /*
1079 * Can't proceed with new transfer as
1080 * previous trasnfer is already in progress.
1081 * There is no point of going into PIO mode
1082 * as well. Is this a time to do kernel panic?
1083 */
1084 pr_err("%s: %s: DML HW is busy!!!"
1085 " Can't perform new SPS transfers"
1086 " now\n", mmc_hostname(host->mmc),
1087 __func__);
1088 }
1089 }
1090 }
1091
1092 /* Is data transfer in PIO mode required? */
1093 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001094 if (data->flags & MMC_DATA_READ) {
1095 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1096 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1097 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001098 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1100 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001101
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001102 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001103 }
1104
1105 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301106 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001107
San Mehat56a8b5b2009-11-21 12:29:46 -08001108 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001110 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1113 /* Use ADM (Application Data Mover) HW for Data transfer */
1114 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001115 host->cmd_timeout = timeout;
1116 host->cmd_pio_irqmask = pio_irqmask;
1117 host->cmd_datactrl = datactrl;
1118 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1121 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001122 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001123
1124 if (cmd) {
1125 msmsdcc_start_command_deferred(host, cmd, &c);
1126 host->cmd_c = c;
1127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1129 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1130 host->base + MMCIMASK0);
1131 mb();
1132 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001133 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1140 (~(MCI_IRQ_PIO))) | pio_irqmask,
1141 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301143 /*
1144 * We don't need delay after writing to DATA_CTRL register
1145 * if we are not writing to CMD register immediately after
1146 * this. As we already have delay before sending the
1147 * command, we just need mb() here.
1148 */
1149 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001150
1151 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001153 /* Daisy-chain the command if requested */
1154 msmsdcc_start_command(host, cmd, c);
1155 }
San Mehat9d2bd732009-09-22 16:44:22 -07001156 }
1157}
1158
1159static void
1160msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1161{
San Mehat56a8b5b2009-11-21 12:29:46 -08001162 msmsdcc_start_command_deferred(host, cmd, &c);
1163 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001164}
1165
1166static void
1167msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1168 unsigned int status)
1169{
1170 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1172 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1173 pr_err("%s: Data CRC error\n",
1174 mmc_hostname(host->mmc));
1175 pr_err("%s: opcode 0x%.8x\n", __func__,
1176 data->mrq->cmd->opcode);
1177 pr_err("%s: blksz %d, blocks %d\n", __func__,
1178 data->blksz, data->blocks);
1179 data->error = -EILSEQ;
1180 }
San Mehat9d2bd732009-09-22 16:44:22 -07001181 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 /* CRC is optional for the bus test commands, not all
1183 * cards respond back with CRC. However controller
1184 * waits for the CRC and times out. Hence ignore the
1185 * data timeouts during the Bustest.
1186 */
1187 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1188 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301189 pr_err("%s: CMD%d: Data timeout\n",
1190 mmc_hostname(host->mmc),
1191 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301193 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 }
San Mehat9d2bd732009-09-22 16:44:22 -07001195 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001196 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001197 data->error = -EIO;
1198 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001199 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001200 data->error = -EIO;
1201 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001202 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001204 data->error = -EIO;
1205 }
San Mehat9d2bd732009-09-22 16:44:22 -07001206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001208 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 host->dummy_52_needed = 0;
1210}
San Mehat9d2bd732009-09-22 16:44:22 -07001211
1212static int
1213msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1214{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001216 uint32_t *ptr = (uint32_t *) buffer;
1217 int count = 0;
1218
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301219 if (remain % 4)
1220 remain = ((remain >> 2) + 1) << 2;
1221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1223
1224 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001225 ptr++;
1226 count += sizeof(uint32_t);
1227
1228 remain -= sizeof(uint32_t);
1229 if (remain == 0)
1230 break;
1231 }
1232 return count;
1233}
1234
1235static int
1236msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001238{
1239 void __iomem *base = host->base;
1240 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 while (readl_relaxed(base + MMCISTATUS) &
1244 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1245 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001246
San Mehat9d2bd732009-09-22 16:44:22 -07001247 count = min(remain, maxcnt);
1248
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301249 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1250 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001251 ptr += count;
1252 remain -= count;
1253
1254 if (remain == 0)
1255 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 }
1257 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001258
1259 return ptr - buffer;
1260}
1261
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001262/*
1263 * Copy up to a word (4 bytes) between a scatterlist
1264 * and a temporary bounce buffer when the word lies across
1265 * two pages. The temporary buffer can then be read to/
1266 * written from the FIFO once.
1267 */
1268static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1269{
1270 struct msmsdcc_pio_data *pio = &host->pio;
1271 unsigned int bytes_avail;
1272
1273 if (host->curr.data->flags & MMC_DATA_READ)
1274 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1275 pio->bounce_buf_len);
1276 else
1277 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1278 pio->bounce_buf_len);
1279
1280 while (pio->bounce_buf_len != 4) {
1281 if (!sg_miter_next(&pio->sg_miter))
1282 break;
1283 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1284 4 - pio->bounce_buf_len);
1285 if (host->curr.data->flags & MMC_DATA_READ)
1286 memcpy(pio->sg_miter.addr,
1287 &pio->bounce_buf[pio->bounce_buf_len],
1288 bytes_avail);
1289 else
1290 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1291 pio->sg_miter.addr, bytes_avail);
1292
1293 pio->sg_miter.consumed = bytes_avail;
1294 pio->bounce_buf_len += bytes_avail;
1295 }
1296}
1297
1298/*
1299 * Use sg_miter_next to return as many 4-byte aligned
1300 * chunks as possible, using a temporary 4 byte buffer
1301 * for alignment if necessary
1302 */
1303static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1304{
1305 struct msmsdcc_pio_data *pio = &host->pio;
1306 unsigned int length, rlength;
1307 char *buffer;
1308
1309 if (!sg_miter_next(&pio->sg_miter))
1310 return 0;
1311
1312 buffer = pio->sg_miter.addr;
1313 length = pio->sg_miter.length;
1314
1315 if (length < host->curr.xfer_remain) {
1316 rlength = round_down(length, 4);
1317 if (rlength) {
1318 /*
1319 * We have a 4-byte aligned chunk.
1320 * The rounding will be reflected by
1321 * a call to msmsdcc_sg_consumed
1322 */
1323 length = rlength;
1324 goto sg_next_end;
1325 }
1326 /*
1327 * We have a length less than 4 bytes. Check to
1328 * see if more buffer is available, and combine
1329 * to make 4 bytes if possible.
1330 */
1331 pio->bounce_buf_len = length;
1332 memset(pio->bounce_buf, 0, 4);
1333
1334 /*
1335 * On a read, get 4 bytes from FIFO, and distribute
1336 * (4-bouce_buf_len) bytes into consecutive
1337 * sgl buffers when msmsdcc_sg_consumed is called
1338 */
1339 if (host->curr.data->flags & MMC_DATA_READ) {
1340 buffer = pio->bounce_buf;
1341 length = 4;
1342 goto sg_next_end;
1343 } else {
1344 _msmsdcc_sg_consume_word(host);
1345 buffer = pio->bounce_buf;
1346 length = pio->bounce_buf_len;
1347 }
1348 }
1349
1350sg_next_end:
1351 *buf = buffer;
1352 *len = length;
1353 return 1;
1354}
1355
1356/*
1357 * Update sg_miter.consumed based on how many bytes were
1358 * consumed. If the bounce buffer was used to read from FIFO,
1359 * redistribute into sgls.
1360 */
1361static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1362 unsigned int length)
1363{
1364 struct msmsdcc_pio_data *pio = &host->pio;
1365
1366 if (host->curr.data->flags & MMC_DATA_READ) {
1367 if (length > pio->sg_miter.consumed)
1368 /*
1369 * consumed 4 bytes, but sgl
1370 * describes < 4 bytes
1371 */
1372 _msmsdcc_sg_consume_word(host);
1373 else
1374 pio->sg_miter.consumed = length;
1375 } else
1376 if (length < pio->sg_miter.consumed)
1377 pio->sg_miter.consumed = length;
1378}
1379
1380static void msmsdcc_sg_start(struct msmsdcc_host *host)
1381{
1382 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1383
1384 host->pio.bounce_buf_len = 0;
1385
1386 if (host->curr.data->flags & MMC_DATA_READ)
1387 sg_miter_flags |= SG_MITER_TO_SG;
1388 else
1389 sg_miter_flags |= SG_MITER_FROM_SG;
1390
1391 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1392 host->curr.data->sg_len, sg_miter_flags);
1393}
1394
1395static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1396{
1397 sg_miter_stop(&host->pio.sg_miter);
1398}
1399
San Mehat1cd22962010-02-03 12:59:29 -08001400static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001401msmsdcc_pio_irq(int irq, void *dev_id)
1402{
1403 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001405 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001406 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001407 unsigned int remain;
1408 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001409
Murali Palnati36448a42011-09-02 15:06:18 +05301410 spin_lock(&host->lock);
1411
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301415 (MCI_IRQ_PIO)) == 0) {
1416 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301418 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419#if IRQ_DEBUG
1420 msmsdcc_print_status(host, "irq1-r", status);
1421#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001422 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001424 do {
1425 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1428 | MCI_RXDATAAVLBL)))
1429 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001430
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001431 if (!msmsdcc_sg_next(host, &buffer, &remain))
1432 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433
San Mehat9d2bd732009-09-22 16:44:22 -07001434 len = 0;
1435 if (status & MCI_RXACTIVE)
1436 len = msmsdcc_pio_read(host, buffer, remain);
1437 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001439
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301440 /* len might have aligned to 32bits above */
1441 if (len > remain)
1442 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001443
San Mehat9d2bd732009-09-22 16:44:22 -07001444 host->curr.xfer_remain -= len;
1445 host->curr.data_xfered += len;
1446 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001447 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 if (remain) /* Done with this page? */
1450 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001453 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001454
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001455 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001456 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1459 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1460 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1461 host->base + MMCIMASK0);
1462 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301463 /*
1464 * back to back write to MASK0 register don't need
1465 * synchronization delay.
1466 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1468 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1469 }
1470 mb();
1471 } else if (!host->curr.xfer_remain) {
1472 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1473 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1474 mb();
1475 }
San Mehat9d2bd732009-09-22 16:44:22 -07001476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001478
1479 return IRQ_HANDLED;
1480}
1481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482static void
1483msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1484
1485static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1486 struct mmc_data *data)
1487{
1488 u32 loop_cnt = 0;
1489
1490 /*
1491 * For read commands with data less than fifo size, it is possible to
1492 * get DATAEND first and RXDATA_AVAIL might be set later because of
1493 * synchronization delay through the asynchronous RX FIFO. Thus, for
1494 * such cases, even after DATAEND interrupt is received software
1495 * should poll for RXDATA_AVAIL until the requested data is read out
1496 * of FIFO. This change is needed to get around this abnormal but
1497 * sometimes expected behavior of SDCC3 controller.
1498 *
1499 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1500 * after the data is loaded into RX FIFO. This would amount to less
1501 * than a microsecond and thus looping for 1000 times is good enough
1502 * for that delay.
1503 */
1504 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1505 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1506 spin_unlock(&host->lock);
1507 msmsdcc_pio_irq(1, host);
1508 spin_lock(&host->lock);
1509 }
1510 }
1511 if (loop_cnt == 1000) {
1512 pr_info("%s: Timed out while polling for Rx Data\n",
1513 mmc_hostname(host->mmc));
1514 data->error = -ETIMEDOUT;
1515 msmsdcc_reset_and_restore(host);
1516 }
1517}
1518
San Mehat9d2bd732009-09-22 16:44:22 -07001519static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1520{
1521 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001522
1523 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1525 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1526 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1527 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301530 pr_debug("%s: CMD%d: Command timeout\n",
1531 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001532 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301534 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301535 pr_err("%s: CMD%d: Command CRC error\n",
1536 mmc_hostname(host->mmc), cmd->opcode);
1537 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001538 cmd->error = -EILSEQ;
1539 }
1540
1541 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 if (host->curr.data && host->dma.sg &&
1543 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001544 msm_dmov_stop_cmd(host->dma.channel,
1545 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 else if (host->curr.data && host->sps.sg &&
1547 host->is_sps_mode){
1548 /* Stop current SPS transfer */
1549 msmsdcc_sps_exit_curr_xfer(host);
1550 }
San Mehat9d2bd732009-09-22 16:44:22 -07001551 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301552 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001553 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301554 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301555 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301556 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301557 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301559 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301561 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301562 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301563 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001564 if (host->dummy_52_needed)
1565 host->dummy_52_needed = 0;
1566 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301568 msmsdcc_request_end(host, cmd->mrq);
1569 }
1570 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301571 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1572 if (cmd->data->flags & MMC_DATA_READ)
1573 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1574 else
1575 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301576 } else if (cmd->data) {
1577 if (!(cmd->data->flags & MMC_DATA_READ))
1578 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001579 }
1580}
1581
San Mehat9d2bd732009-09-22 16:44:22 -07001582static irqreturn_t
1583msmsdcc_irq(int irq, void *dev_id)
1584{
1585 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001586 u32 status;
1587 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001589
1590 spin_lock(&host->lock);
1591
1592 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 struct mmc_command *cmd;
1594 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 if (timer) {
1597 timer = 0;
1598 msmsdcc_delay(host);
1599 }
San Mehat865c8062009-11-13 13:42:06 -08001600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 if (!host->clks_on) {
1602 pr_debug("%s: %s: SDIO async irq received\n",
1603 mmc_hostname(host->mmc), __func__);
1604 host->mmc->ios.clock = host->clk_rate;
1605 spin_unlock(&host->lock);
1606 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1607 spin_lock(&host->lock);
1608 if (host->plat->cfg_mpm_sdiowakeup &&
1609 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1610 wake_lock(&host->sdio_wlock);
1611 /* only ansyc interrupt can come when clocks are off */
1612 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301613 if (host->clk_rate <=
1614 msmsdcc_get_min_sup_clk_rate(host))
1615 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 }
1617
1618 status = readl_relaxed(host->base + MMCISTATUS);
1619
1620 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1621 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001622 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624#if IRQ_DEBUG
1625 msmsdcc_print_status(host, "irq0-r", status);
1626#endif
1627 status &= readl_relaxed(host->base + MMCIMASK0);
1628 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301629 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301630 if (host->clk_rate <=
1631 msmsdcc_get_min_sup_clk_rate(host))
1632 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633#if IRQ_DEBUG
1634 msmsdcc_print_status(host, "irq0-p", status);
1635#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1638 if (status & MCI_SDIOINTROPE) {
1639 if (host->sdcc_suspending)
1640 wake_lock(&host->sdio_suspend_wlock);
1641 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001642 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001644 data = host->curr.data;
1645
1646 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1648 MCI_CMDTIMEOUT)) {
1649 if (status & MCI_CMDTIMEOUT)
1650 pr_debug("%s: dummy CMD52 timeout\n",
1651 mmc_hostname(host->mmc));
1652 if (status & MCI_CMDCRCFAIL)
1653 pr_debug("%s: dummy CMD52 CRC failed\n",
1654 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001655 host->dummy_52_sent = 0;
1656 host->dummy_52_needed = 0;
1657 if (data) {
1658 msmsdcc_stop_data(host);
1659 msmsdcc_request_end(host, data->mrq);
1660 }
1661 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 spin_unlock(&host->lock);
1663 return IRQ_HANDLED;
1664 }
1665 break;
1666 }
1667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 /*
1669 * Check for proper command response
1670 */
1671 cmd = host->curr.cmd;
1672 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1673 MCI_CMDTIMEOUT | MCI_PROGDONE |
1674 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1675 msmsdcc_do_cmdirq(host, status);
1676 }
1677
Sathish Ambley081d7842011-11-29 11:19:41 -08001678 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 /* Check for data errors */
1680 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1681 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1682 msmsdcc_data_err(host, data, status);
1683 host->curr.data_xfered = 0;
1684 if (host->dma.sg && host->is_dma_mode)
1685 msm_dmov_stop_cmd(host->dma.channel,
1686 &host->dma.hdr, 0);
1687 else if (host->sps.sg && host->is_sps_mode) {
1688 /* Stop current SPS transfer */
1689 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301690 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 msmsdcc_reset_and_restore(host);
1692 if (host->curr.data)
1693 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301694 if (!data->stop || (host->curr.mrq->sbc
1695 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 timer |=
1697 msmsdcc_request_end(host,
1698 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301699 else if ((host->curr.mrq->sbc
1700 && data->error) ||
1701 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 msmsdcc_start_command(host,
1703 data->stop,
1704 0);
1705 timer = 1;
1706 }
1707 }
1708 }
1709
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301710 /* Check for prog done */
1711 if (host->curr.wait_for_auto_prog_done &&
1712 (status & MCI_PROGDONE))
1713 host->curr.got_auto_prog_done = 1;
1714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715 /* Check for data done */
1716 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1717 host->curr.got_dataend = 1;
1718
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301719 if (host->curr.got_dataend &&
1720 (!host->curr.wait_for_auto_prog_done ||
1721 (host->curr.wait_for_auto_prog_done &&
1722 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 /*
1724 * If DMA is still in progress, we complete
1725 * via the completion handler
1726 */
1727 if (!host->dma.busy && !host->sps.busy) {
1728 /*
1729 * There appears to be an issue in the
1730 * controller where if you request a
1731 * small block transfer (< fifo size),
1732 * you may get your DATAEND/DATABLKEND
1733 * irq without the PIO data irq.
1734 *
1735 * Check to see if theres still data
1736 * to be read, and simulate a PIO irq.
1737 */
1738 if (data->flags & MMC_DATA_READ)
1739 msmsdcc_wait_for_rxdata(host,
1740 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 if (!data->error) {
1742 host->curr.data_xfered =
1743 host->curr.xfer_size;
1744 host->curr.xfer_remain -=
1745 host->curr.xfer_size;
1746 }
1747
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001748 if (!host->dummy_52_needed) {
1749 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301750 if (!data->stop ||
1751 (host->curr.mrq->sbc
1752 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001753 msmsdcc_request_end(
1754 host,
1755 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301756 else if ((host->curr.mrq->sbc
1757 && data->error) ||
1758 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001759 msmsdcc_start_command(
1760 host,
1761 data->stop, 0);
1762 timer = 1;
1763 }
1764 } else {
1765 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001767 &dummy52cmd,
1768 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 }
1770 }
1771 }
1772 }
1773
San Mehat9d2bd732009-09-22 16:44:22 -07001774 ret = 1;
1775 } while (status);
1776
1777 spin_unlock(&host->lock);
1778
San Mehat9d2bd732009-09-22 16:44:22 -07001779 return IRQ_RETVAL(ret);
1780}
1781
1782static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1784{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301785 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301787 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301788 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1789 else
1790 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791 } else {
1792 msmsdcc_start_command(host, mrq->cmd, 0);
1793 }
1794}
1795
1796static void
San Mehat9d2bd732009-09-22 16:44:22 -07001797msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1798{
1799 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 /*
1803 * Get the SDIO AL client out of LPM.
1804 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001805 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 if (host->plat->is_sdio_al_client)
1807 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001808
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301809 /* check if sps pipe reset is pending? */
1810 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1811 msmsdcc_sps_pipes_reset_and_restore(host);
1812 host->sps.pipe_reset_pending = false;
1813 }
1814
San Mehat9d2bd732009-09-22 16:44:22 -07001815 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816 WARN(host->curr.mrq, "Request in progress\n");
1817 WARN(!host->pwr, "SDCC power is turned off\n");
1818 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1819 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001820
1821 if (host->eject) {
1822 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1823 mrq->cmd->error = 0;
1824 mrq->data->bytes_xfered = mrq->data->blksz *
1825 mrq->data->blocks;
1826 } else
1827 mrq->cmd->error = -ENOMEDIUM;
1828
1829 spin_unlock_irqrestore(&host->lock, flags);
1830 mmc_request_done(mmc, mrq);
1831 return;
1832 }
1833
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301834 /*
1835 * Kick the software command timeout timer here.
1836 * Timer expires in 10 secs.
1837 */
1838 mod_timer(&host->req_tout_timer,
1839 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001840
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301841 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301842 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301843 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1844 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301845 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301847 else
1848 /*
1849 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1850 * write operations using CMD53 and CMD54.
1851 * Setting this bit with CMD53 would
1852 * automatically triggers PROG_DONE interrupt
1853 * without the need of sending dummy CMD52.
1854 */
1855 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301856 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1857 host->sdcc_version) {
1858 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 }
San Mehat9d2bd732009-09-22 16:44:22 -07001860 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301861
Pratibhasagar V00b94332011-10-18 14:57:27 +05301862 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301863 mrq->sbc->mrq = mrq;
1864 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301865 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301866 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301867 msmsdcc_start_command(host, mrq->sbc, 0);
1868 } else {
1869 msmsdcc_request_start(host, mrq);
1870 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301871 } else {
1872 msmsdcc_request_start(host, mrq);
1873 }
1874
San Mehat9d2bd732009-09-22 16:44:22 -07001875 spin_unlock_irqrestore(&host->lock, flags);
1876}
1877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1879 int min_uV, int max_uV)
1880{
1881 int rc = 0;
1882
1883 if (vreg->set_voltage_sup) {
1884 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1885 if (rc) {
1886 pr_err("%s: regulator_set_voltage(%s) failed."
1887 " min_uV=%d, max_uV=%d, rc=%d\n",
1888 __func__, vreg->name, min_uV, max_uV, rc);
1889 }
1890 }
1891
1892 return rc;
1893}
1894
1895static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1896 int uA_load)
1897{
1898 int rc = 0;
1899
Krishna Kondafea60182011-11-01 16:01:34 -07001900 /* regulators that do not support regulator_set_voltage also
1901 do not support regulator_set_optimum_mode */
1902 if (vreg->set_voltage_sup) {
1903 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1904 if (rc < 0)
1905 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1906 "uA_load=%d) failed. rc=%d\n", __func__,
1907 vreg->name, uA_load, rc);
1908 else
1909 /* regulator_set_optimum_mode() can return non zero
1910 * value even for success case.
1911 */
1912 rc = 0;
1913 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914
1915 return rc;
1916}
1917
1918static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1919 struct device *dev)
1920{
1921 int rc = 0;
1922
1923 /* check if regulator is already initialized? */
1924 if (vreg->reg)
1925 goto out;
1926
1927 /* Get the regulator handle */
1928 vreg->reg = regulator_get(dev, vreg->name);
1929 if (IS_ERR(vreg->reg)) {
1930 rc = PTR_ERR(vreg->reg);
1931 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1932 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001933 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001935
1936 if (regulator_count_voltages(vreg->reg) > 0)
1937 vreg->set_voltage_sup = 1;
1938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001939out:
1940 return rc;
1941}
1942
1943static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1944{
1945 if (vreg->reg)
1946 regulator_put(vreg->reg);
1947}
1948
1949/* This init function should be called only once for each SDCC slot */
1950static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1951{
1952 int rc = 0;
1953 struct msm_mmc_slot_reg_data *curr_slot;
1954 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1955 struct device *dev = mmc_dev(host->mmc);
1956
1957 curr_slot = host->plat->vreg_data;
1958 if (!curr_slot)
1959 goto out;
1960
1961 curr_vdd_reg = curr_slot->vdd_data;
1962 curr_vccq_reg = curr_slot->vccq_data;
1963 curr_vddp_reg = curr_slot->vddp_data;
1964
1965 if (is_init) {
1966 /*
1967 * Get the regulator handle from voltage regulator framework
1968 * and then try to set the voltage level for the regulator
1969 */
1970 if (curr_vdd_reg) {
1971 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1972 if (rc)
1973 goto out;
1974 }
1975 if (curr_vccq_reg) {
1976 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1977 if (rc)
1978 goto vdd_reg_deinit;
1979 }
1980 if (curr_vddp_reg) {
1981 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1982 if (rc)
1983 goto vccq_reg_deinit;
1984 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08001985 rc = msmsdcc_vreg_reset(host);
1986 if (rc)
1987 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
1988 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989 goto out;
1990 } else {
1991 /* Deregister all regulators from regulator framework */
1992 goto vddp_reg_deinit;
1993 }
1994vddp_reg_deinit:
1995 if (curr_vddp_reg)
1996 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1997vccq_reg_deinit:
1998 if (curr_vccq_reg)
1999 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2000vdd_reg_deinit:
2001 if (curr_vdd_reg)
2002 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2003out:
2004 return rc;
2005}
2006
2007static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2008{
2009 int rc = 0;
2010
Subhash Jadavanicc922692011-08-01 23:05:01 +05302011 /* Put regulator in HPM (high power mode) */
2012 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2013 if (rc < 0)
2014 goto out;
2015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 if (!vreg->is_enabled) {
2017 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302018 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2019 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 if (rc)
2021 goto out;
2022
2023 rc = regulator_enable(vreg->reg);
2024 if (rc) {
2025 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2026 __func__, vreg->name, rc);
2027 goto out;
2028 }
2029 vreg->is_enabled = true;
2030 }
2031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032out:
2033 return rc;
2034}
2035
2036static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2037{
2038 int rc = 0;
2039
2040 /* Never disable regulator marked as always_on */
2041 if (vreg->is_enabled && !vreg->always_on) {
2042 rc = regulator_disable(vreg->reg);
2043 if (rc) {
2044 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2045 __func__, vreg->name, rc);
2046 goto out;
2047 }
2048 vreg->is_enabled = false;
2049
2050 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2051 if (rc < 0)
2052 goto out;
2053
2054 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302055 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 if (rc)
2057 goto out;
2058 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2059 /* Put always_on regulator in LPM (low power mode) */
2060 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2061 if (rc < 0)
2062 goto out;
2063 }
2064out:
2065 return rc;
2066}
2067
2068static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2069{
2070 int rc = 0, i;
2071 struct msm_mmc_slot_reg_data *curr_slot;
2072 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2073 struct msm_mmc_reg_data *vreg_table[3];
2074
2075 curr_slot = host->plat->vreg_data;
2076 if (!curr_slot)
2077 goto out;
2078
2079 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2080 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2081 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2082
2083 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2084 if (vreg_table[i]) {
2085 if (enable)
2086 rc = msmsdcc_vreg_enable(vreg_table[i]);
2087 else
2088 rc = msmsdcc_vreg_disable(vreg_table[i]);
2089 if (rc)
2090 goto out;
2091 }
2092 }
2093out:
2094 return rc;
2095}
2096
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002097/*
2098 * Reset vreg by ensuring it is off during probe. A call
2099 * to enable vreg is needed to balance disable vreg
2100 */
2101static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2102{
2103 int rc;
2104
2105 rc = msmsdcc_setup_vreg(host, 1);
2106 if (rc)
2107 return rc;
2108 rc = msmsdcc_setup_vreg(host, 0);
2109 return rc;
2110}
2111
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302112static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002113{
2114 int rc = 0;
2115
2116 if (host->plat->vreg_data) {
2117 struct msm_mmc_reg_data *vddp_reg =
2118 host->plat->vreg_data->vddp_data;
2119
2120 if (vddp_reg && vddp_reg->is_enabled)
2121 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2122 }
2123
2124 return rc;
2125}
2126
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302127static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2128{
2129 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2130 int rc = 0;
2131
2132 if (curr_slot && curr_slot->vddp_data) {
2133 rc = msmsdcc_set_vddp_level(host,
2134 curr_slot->vddp_data->low_vol_level);
2135
2136 if (rc)
2137 pr_err("%s: %s: failed to change vddp level to %d",
2138 mmc_hostname(host->mmc), __func__,
2139 curr_slot->vddp_data->low_vol_level);
2140 }
2141
2142 return rc;
2143}
2144
2145static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2146{
2147 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2148 int rc = 0;
2149
2150 if (curr_slot && curr_slot->vddp_data) {
2151 rc = msmsdcc_set_vddp_level(host,
2152 curr_slot->vddp_data->high_vol_level);
2153
2154 if (rc)
2155 pr_err("%s: %s: failed to change vddp level to %d",
2156 mmc_hostname(host->mmc), __func__,
2157 curr_slot->vddp_data->high_vol_level);
2158 }
2159
2160 return rc;
2161}
2162
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302163static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2164{
2165 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2166 int rc = 0;
2167
2168 if (curr_slot && curr_slot->vccq_data) {
2169 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2170 level, level);
2171 if (rc)
2172 pr_err("%s: %s: failed to change vccq level to %d",
2173 mmc_hostname(host->mmc), __func__, level);
2174 }
2175
2176 return rc;
2177}
2178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2180{
2181 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2182 return 1;
2183 return 0;
2184}
2185
2186static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2187{
2188 if (enable) {
2189 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2190 clk_enable(host->dfab_pclk);
2191 if (!IS_ERR(host->pclk))
2192 clk_enable(host->pclk);
2193 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302194 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302196 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197 clk_disable(host->clk);
2198 if (!IS_ERR(host->pclk))
2199 clk_disable(host->pclk);
2200 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2201 clk_disable(host->dfab_pclk);
2202 }
2203}
2204
2205static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2206 unsigned int req_clk)
2207{
2208 unsigned int sel_clk = -1;
2209
2210 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2211 unsigned char cnt;
2212
2213 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2214 if (host->plat->sup_clk_table[cnt] > req_clk)
2215 break;
2216 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2217 sel_clk = host->plat->sup_clk_table[cnt];
2218 break;
2219 } else
2220 sel_clk = host->plat->sup_clk_table[cnt];
2221 }
2222 } else {
2223 if ((req_clk < host->plat->msmsdcc_fmax) &&
2224 (req_clk > host->plat->msmsdcc_fmid))
2225 sel_clk = host->plat->msmsdcc_fmid;
2226 else
2227 sel_clk = req_clk;
2228 }
2229
2230 return sel_clk;
2231}
2232
2233static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2234 struct msmsdcc_host *host)
2235{
2236 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2237 return host->plat->sup_clk_table[0];
2238 else
2239 return host->plat->msmsdcc_fmin;
2240}
2241
2242static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2243 struct msmsdcc_host *host)
2244{
2245 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2246 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2247 else
2248 return host->plat->msmsdcc_fmax;
2249}
2250
2251static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302252{
2253 struct msm_mmc_gpio_data *curr;
2254 int i, rc = 0;
2255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302257 for (i = 0; i < curr->size; i++) {
2258 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 if (curr->gpio[i].is_always_on &&
2260 curr->gpio[i].is_enabled)
2261 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302262 rc = gpio_request(curr->gpio[i].no,
2263 curr->gpio[i].name);
2264 if (rc) {
2265 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2266 mmc_hostname(host->mmc),
2267 curr->gpio[i].no,
2268 curr->gpio[i].name, rc);
2269 goto free_gpios;
2270 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302272 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 if (curr->gpio[i].is_always_on)
2274 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302275 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302277 }
2278 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302280
2281free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302283 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 curr->gpio[i].is_enabled = false;
2285 }
2286out:
2287 return rc;
2288}
2289
2290static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2291{
2292 struct msm_mmc_pad_data *curr;
2293 int i;
2294
2295 curr = host->plat->pin_data->pad_data;
2296 for (i = 0; i < curr->drv->size; i++) {
2297 if (enable)
2298 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2299 curr->drv->on[i].val);
2300 else
2301 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2302 curr->drv->off[i].val);
2303 }
2304
2305 for (i = 0; i < curr->pull->size; i++) {
2306 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002307 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002308 curr->pull->on[i].val);
2309 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002310 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 curr->pull->off[i].val);
2312 }
2313
2314 return 0;
2315}
2316
2317static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2318{
2319 int rc = 0;
2320
2321 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2322 return 0;
2323
2324 if (host->plat->pin_data->is_gpio)
2325 rc = msmsdcc_setup_gpio(host, enable);
2326 else
2327 rc = msmsdcc_setup_pad(host, enable);
2328
2329 if (!rc)
2330 host->plat->pin_data->cfg_sts = enable;
2331
2332 return rc;
2333}
2334
2335static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2336{
2337 unsigned int wakeup_irq;
2338
2339 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2340 host->plat->sdiowakeup_irq :
2341 host->core_irqres->start;
2342
2343 if (!host->irq_wake_enabled) {
2344 enable_irq_wake(wakeup_irq);
2345 host->irq_wake_enabled = true;
2346 }
2347}
2348
2349static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2350{
2351 unsigned int wakeup_irq;
2352
2353 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2354 host->plat->sdiowakeup_irq :
2355 host->core_irqres->start;
2356
2357 if (host->irq_wake_enabled) {
2358 disable_irq_wake(wakeup_irq);
2359 host->irq_wake_enabled = false;
2360 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302361}
2362
San Mehat9d2bd732009-09-22 16:44:22 -07002363static void
2364msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2365{
2366 struct msmsdcc_host *host = mmc_priv(mmc);
2367 u32 clk = 0, pwr = 0;
2368 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002369 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302373
San Mehat9d2bd732009-09-22 16:44:22 -07002374 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 spin_lock_irqsave(&host->lock, flags);
2376 if (!host->clks_on) {
2377 msmsdcc_setup_clocks(host, true);
2378 host->clks_on = 1;
2379 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2380 if (!host->plat->sdiowakeup_irq) {
2381 writel_relaxed(host->mci_irqenable,
2382 host->base + MMCIMASK0);
2383 mb();
2384 if (host->plat->cfg_mpm_sdiowakeup &&
2385 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2386 host->plat->cfg_mpm_sdiowakeup(
2387 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2388 msmsdcc_disable_irq_wake(host);
2389 } else if (!(mmc->pm_flags &
2390 MMC_PM_WAKE_SDIO_IRQ)) {
2391 writel_relaxed(host->mci_irqenable,
2392 host->base + MMCIMASK0);
2393 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302394 } else {
2395 writel_relaxed(host->mci_irqenable,
2396 host->base + MMCIMASK0);
2397 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 }
San Mehat9d2bd732009-09-22 16:44:22 -07002399 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400 spin_unlock_irqrestore(&host->lock, flags);
2401
2402 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2403 /*
2404 * For DDR50 mode, controller needs clock rate to be
2405 * double than what is required on the SD card CLK pin.
2406 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302407 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408 /*
2409 * Make sure that we don't double the clock if
2410 * doubled clock rate is already set
2411 */
2412 if (!host->ddr_doubled_clk_rate ||
2413 (host->ddr_doubled_clk_rate &&
2414 (host->ddr_doubled_clk_rate != ios->clock))) {
2415 host->ddr_doubled_clk_rate =
2416 msmsdcc_get_sup_clk_rate(
2417 host, (ios->clock * 2));
2418 clock = host->ddr_doubled_clk_rate;
2419 }
2420 } else {
2421 host->ddr_doubled_clk_rate = 0;
2422 }
2423
2424 if (clock != host->clk_rate) {
2425 rc = clk_set_rate(host->clk, clock);
2426 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302427 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 mmc_hostname(mmc), clock);
2429 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302430 host->reg_write_delay =
2431 (1 + ((3 * USEC_PER_SEC) /
2432 (host->clk_rate ? host->clk_rate :
2433 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434 }
2435 /*
2436 * give atleast 2 MCLK cycles delay for clocks
2437 * and SDCC core to stabilize
2438 */
2439 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002440 clk |= MCI_CLK_ENABLE;
2441 }
2442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002443 if (ios->bus_width == MMC_BUS_WIDTH_8)
2444 clk |= MCI_CLK_WIDEBUS_8;
2445 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2446 clk |= MCI_CLK_WIDEBUS_4;
2447 else
2448 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 if (msmsdcc_is_pwrsave(host))
2451 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 host->tuning_needed = 0;
2456 /*
2457 * Select the controller timing mode according
2458 * to current bus speed mode
2459 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302460 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2461 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 clk |= (4 << 14);
2463 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302464 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 clk |= (3 << 14);
2466 } else {
2467 clk |= (2 << 14); /* feedback clock */
2468 }
2469
2470 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2471 clk |= (2 << 23);
2472
Subhash Jadavani00083572012-02-15 16:18:01 +05302473 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2474 if (!ios->vdd)
2475 host->io_pad_pwr_switch = 0;
2476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 if (host->io_pad_pwr_switch)
2478 clk |= IO_PAD_PWR_SWITCH;
2479
2480 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002481 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2483 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002484
2485 switch (ios->power_mode) {
2486 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2488 if (!host->sdcc_irq_disabled) {
2489 if (host->plat->cfg_mpm_sdiowakeup)
2490 host->plat->cfg_mpm_sdiowakeup(
2491 mmc_dev(mmc), SDC_DAT1_DISABLE);
2492 disable_irq(host->core_irqres->start);
2493 host->sdcc_irq_disabled = 1;
2494 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302495 /*
2496 * As VDD pad rail is always on, set low voltage for VDD
2497 * pad rail when slot is unused (when card is not present
2498 * or during system suspend).
2499 */
2500 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002502 break;
2503 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302504 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002505 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 if (host->sdcc_irq_disabled) {
2507 if (host->plat->cfg_mpm_sdiowakeup)
2508 host->plat->cfg_mpm_sdiowakeup(
2509 mmc_dev(mmc), SDC_DAT1_ENABLE);
2510 enable_irq(host->core_irqres->start);
2511 host->sdcc_irq_disabled = 0;
2512 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302513 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002514 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002515 break;
2516 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002518 pwr |= MCI_PWR_ON;
2519 break;
2520 }
2521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 spin_lock_irqsave(&host->lock, flags);
2523 if (!host->clks_on) {
2524 /* force the clocks to be on */
2525 msmsdcc_setup_clocks(host, true);
2526 /*
2527 * give atleast 2 MCLK cycles delay for clocks
2528 * and SDCC core to stabilize
2529 */
2530 msmsdcc_delay(host);
2531 }
2532 writel_relaxed(clk, host->base + MMCICLOCK);
2533 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002534
2535 if (host->pwr != pwr) {
2536 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302538 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002539 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540 if (!host->clks_on) {
2541 /* force the clocks to be off */
2542 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543 }
2544
2545 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2546 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2547 if (!host->plat->sdiowakeup_irq) {
2548 writel_relaxed(MCI_SDIOINTMASK,
2549 host->base + MMCIMASK0);
2550 mb();
2551 if (host->plat->cfg_mpm_sdiowakeup &&
2552 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2553 host->plat->cfg_mpm_sdiowakeup(
2554 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2555 msmsdcc_enable_irq_wake(host);
2556 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2557 writel_relaxed(0, host->base + MMCIMASK0);
2558 } else {
2559 writel_relaxed(MCI_SDIOINTMASK,
2560 host->base + MMCIMASK0);
2561 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302562 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 }
2564 msmsdcc_setup_clocks(host, false);
2565 host->clks_on = 0;
2566 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302567
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302568 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302569 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302570 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302571
San Mehat4adbbcc2009-11-08 13:00:37 -08002572 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002573}
2574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2576{
2577 struct msmsdcc_host *host = mmc_priv(mmc);
2578 u32 clk;
2579
2580 clk = readl_relaxed(host->base + MMCICLOCK);
2581 pr_debug("Changing to pwr_save=%d", pwrsave);
2582 if (pwrsave && msmsdcc_is_pwrsave(host))
2583 clk |= MCI_CLK_PWRSAVE;
2584 else
2585 clk &= ~MCI_CLK_PWRSAVE;
2586 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302587 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588
2589 return 0;
2590}
2591
2592static int msmsdcc_get_ro(struct mmc_host *mmc)
2593{
2594 int status = -ENOSYS;
2595 struct msmsdcc_host *host = mmc_priv(mmc);
2596
2597 if (host->plat->wpswitch) {
2598 status = host->plat->wpswitch(mmc_dev(mmc));
2599 } else if (host->plat->wpswitch_gpio) {
2600 status = gpio_request(host->plat->wpswitch_gpio,
2601 "SD_WP_Switch");
2602 if (status) {
2603 pr_err("%s: %s: Failed to request GPIO %d\n",
2604 mmc_hostname(mmc), __func__,
2605 host->plat->wpswitch_gpio);
2606 } else {
2607 status = gpio_direction_input(
2608 host->plat->wpswitch_gpio);
2609 if (!status) {
2610 /*
2611 * Wait for atleast 300ms as debounce
2612 * time for GPIO input to stabilize.
2613 */
2614 msleep(300);
2615 status = gpio_get_value_cansleep(
2616 host->plat->wpswitch_gpio);
2617 status ^= !host->plat->wpswitch_polarity;
2618 }
2619 gpio_free(host->plat->wpswitch_gpio);
2620 }
2621 }
2622
2623 if (status < 0)
2624 status = -ENOSYS;
2625 pr_debug("%s: Card read-only status %d\n", __func__, status);
2626
2627 return status;
2628}
2629
2630#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002631static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2632{
2633 struct msmsdcc_host *host = mmc_priv(mmc);
2634 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002635
2636 if (enable) {
2637 spin_lock_irqsave(&host->lock, flags);
2638 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2639 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2640 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2641 spin_unlock_irqrestore(&host->lock, flags);
2642 } else {
2643 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2644 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2645 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2646 }
2647 mb();
2648}
2649#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2650
2651#ifdef CONFIG_PM_RUNTIME
2652static int msmsdcc_enable(struct mmc_host *mmc)
2653{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302654 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302656 struct msmsdcc_host *host = mmc_priv(mmc);
2657
2658 msmsdcc_pm_qos_update_latency(host, 1);
2659
2660 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2661 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302663 if (dev->power.runtime_status == RPM_SUSPENDING) {
2664 if (mmc->suspend_task == current) {
2665 pm_runtime_get_noresume(dev);
2666 goto out;
2667 }
2668 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002669
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302670 rc = pm_runtime_get_sync(dev);
2671
2672 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002673 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2674 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302675 return rc;
2676 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302677
2678 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302679out:
2680 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681}
2682
2683static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2684{
2685 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302686 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302688 msmsdcc_pm_qos_update_latency(host, 0);
2689
2690 if (mmc->card && mmc_card_sdio(mmc->card))
2691 return 0;
2692
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302693 if (host->plat->disable_runtime_pm)
2694 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002695
2696 rc = pm_runtime_put_sync(mmc->parent);
2697
2698 if (rc < 0)
2699 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2700 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302701 else
2702 host->is_resumed = false;
2703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 return rc;
2705}
2706#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302707static int msmsdcc_enable(struct mmc_host *mmc)
2708{
2709 struct msmsdcc_host *host = mmc_priv(mmc);
2710 unsigned long flags;
2711
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302712 msmsdcc_pm_qos_update_latency(host, 1);
2713
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302714 spin_lock_irqsave(&host->lock, flags);
2715 if (!host->clks_on) {
2716 msmsdcc_setup_clocks(host, true);
2717 host->clks_on = 1;
2718 }
2719 spin_unlock_irqrestore(&host->lock, flags);
2720
2721 return 0;
2722}
2723
2724static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2725{
2726 struct msmsdcc_host *host = mmc_priv(mmc);
2727 unsigned long flags;
2728
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302729 msmsdcc_pm_qos_update_latency(host, 0);
2730
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302731 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302732 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302733
2734 spin_lock_irqsave(&host->lock, flags);
2735 if (host->clks_on) {
2736 msmsdcc_setup_clocks(host, false);
2737 host->clks_on = 0;
2738 }
2739 spin_unlock_irqrestore(&host->lock, flags);
2740
2741 return 0;
2742}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002743#endif
2744
2745static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2746 struct mmc_ios *ios)
2747{
2748 struct msmsdcc_host *host = mmc_priv(mmc);
2749 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302750 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751
Subhash Jadavani00083572012-02-15 16:18:01 +05302752 spin_lock_irqsave(&host->lock, flags);
2753 host->io_pad_pwr_switch = 0;
2754 spin_unlock_irqrestore(&host->lock, flags);
2755
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302756 /*
2757 * For eMMC cards, VccQ voltage range must be changed
2758 * only if it operates in HS200 SDR 1.2V mode or in
2759 * DDR 1.2V mode.
2760 */
2761 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2762 rc = msmsdcc_set_vccq_vol(host, 1200000);
2763 goto out;
2764 }
2765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2767 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302768 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 goto out;
2770 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2771 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302772 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773 goto out;
2774 }
San Mehat9d2bd732009-09-22 16:44:22 -07002775
2776 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777 /*
2778 * If we are here means voltage switch from high voltage to
2779 * low voltage is required
2780 */
2781
2782 /*
2783 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2784 * register until they become all zeros.
2785 */
2786 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302787 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2789 mmc_hostname(mmc), __func__);
2790 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002791 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792
2793 /* Stop SD CLK output. */
2794 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2795 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302796 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002797 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798
2799 /*
2800 * Switch VDDPX from high voltage to low voltage
2801 * to change the VDD of the SD IO pads.
2802 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302803 rc = msmsdcc_set_vddp_low_vol(host);
2804 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806
2807 spin_lock_irqsave(&host->lock, flags);
2808 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2809 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302810 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811 host->io_pad_pwr_switch = 1;
2812 spin_unlock_irqrestore(&host->lock, flags);
2813
2814 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2815 usleep_range(5000, 5500);
2816
2817 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302818 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002819 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2820 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302821 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822 spin_unlock_irqrestore(&host->lock, flags);
2823
2824 /*
2825 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2826 * don't become all ones within 1 ms then a Voltage Switch
2827 * sequence has failed and a power cycle to the card is required.
2828 * Otherwise Voltage Switch sequence is completed successfully.
2829 */
2830 usleep_range(1000, 1500);
2831
2832 spin_lock_irqsave(&host->lock, flags);
2833 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2834 != (0xF << 1)) {
2835 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2836 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302837 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838 goto out_unlock;
2839 }
2840
2841out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302842 /* Enable PWRSAVE */
2843 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2844 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 spin_unlock_irqrestore(&host->lock, flags);
2846out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302847 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848}
2849
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302850static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853
2854 /* Program the MCLK value to MCLK_FREQ bit field */
2855 if (host->clk_rate <= 112000000)
2856 mclk_freq = 0;
2857 else if (host->clk_rate <= 125000000)
2858 mclk_freq = 1;
2859 else if (host->clk_rate <= 137000000)
2860 mclk_freq = 2;
2861 else if (host->clk_rate <= 150000000)
2862 mclk_freq = 3;
2863 else if (host->clk_rate <= 162000000)
2864 mclk_freq = 4;
2865 else if (host->clk_rate <= 175000000)
2866 mclk_freq = 5;
2867 else if (host->clk_rate <= 187000000)
2868 mclk_freq = 6;
2869 else if (host->clk_rate <= 200000000)
2870 mclk_freq = 7;
2871
2872 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2873 & ~(7 << 24)) | (mclk_freq << 24)),
2874 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875}
2876
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302877/* Initialize the DLL (Programmable Delay Line ) */
2878static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002880 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302881 unsigned long flags;
2882 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302884 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002885 /*
2886 * Make sure that clock is always enabled when DLL
2887 * tuning is in progress. Keeping PWRSAVE ON may
2888 * turn off the clock. So let's disable the PWRSAVE
2889 * here and re-enable it once tuning is completed.
2890 */
2891 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2892 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302893
2894 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2895 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2896 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2897
2898 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2899 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2900 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2901
2902 msmsdcc_cm_sdc4_dll_set_freq(host);
2903
2904 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2905 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2906 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2907
2908 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2909 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2910 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2911
2912 /* Set DLL_EN bit to 1. */
2913 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2914 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2915
2916 /* Set CK_OUT_EN bit to 1. */
2917 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2918 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2919
2920 wait_cnt = 50;
2921 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2922 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2923 /* max. wait for 50us sec for LOCK bit to be set */
2924 if (--wait_cnt == 0) {
2925 pr_err("%s: %s: DLL failed to LOCK\n",
2926 mmc_hostname(host->mmc), __func__);
2927 rc = -ETIMEDOUT;
2928 goto out;
2929 }
2930 /* wait for 1us before polling again */
2931 udelay(1);
2932 }
2933
2934out:
2935 /* re-enable PWRSAVE */
2936 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2937 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2938 spin_unlock_irqrestore(&host->lock, flags);
2939
2940 return rc;
2941}
2942
2943static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2944 u8 poll)
2945{
2946 int rc = 0;
2947 u32 wait_cnt = 50;
2948 u8 ck_out_en = 0;
2949
2950 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2951 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2952 MCI_CK_OUT_EN);
2953
2954 while (ck_out_en != poll) {
2955 if (--wait_cnt == 0) {
2956 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2957 mmc_hostname(host->mmc), __func__, poll);
2958 rc = -ETIMEDOUT;
2959 goto out;
2960 }
2961 udelay(1);
2962
2963 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2964 MCI_CK_OUT_EN);
2965 }
2966out:
2967 return rc;
2968}
2969
2970/*
2971 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2972 * calibration sequence. This function should be called before
2973 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2974 * commands (CMD17/CMD18).
2975 *
2976 * This function gets called when host spinlock acquired.
2977 */
2978static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2979{
2980 int rc = 0;
2981 u32 config;
2982
2983 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2984 config |= MCI_CDR_EN;
2985 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2986 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2987
2988 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2989 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2990 if (rc)
2991 goto err_out;
2992
2993 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2994 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2995 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2996
2997 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2998 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2999 if (rc)
3000 goto err_out;
3001
3002 goto out;
3003
3004err_out:
3005 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3006out:
3007 return rc;
3008}
3009
3010static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3011 u8 phase)
3012{
3013 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303014 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3015 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3016 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303017 unsigned long flags;
3018 u32 config;
3019
3020 spin_lock_irqsave(&host->lock, flags);
3021
3022 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3023 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3024 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3025 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3026
3027 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3028 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3029 if (rc)
3030 goto err_out;
3031
3032 /*
3033 * Write the selected DLL clock output phase (0 ... 15)
3034 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3035 */
3036 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3037 & ~(0xF << 20))
3038 | (grey_coded_phase_table[phase] << 20)),
3039 host->base + MCI_DLL_CONFIG);
3040
3041 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3042 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3043 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3044
3045 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3046 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3047 if (rc)
3048 goto err_out;
3049
3050 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3051 config |= MCI_CDR_EN;
3052 config &= ~MCI_CDR_EXT_EN;
3053 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3054 goto out;
3055
3056err_out:
3057 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3058 mmc_hostname(host->mmc), __func__, phase);
3059out:
3060 spin_unlock_irqrestore(&host->lock, flags);
3061 return rc;
3062}
3063
3064/*
3065 * Find out the greatest range of consecuitive selected
3066 * DLL clock output phases that can be used as sampling
3067 * setting for SD3.0 UHS-I card read operation (in SDR104
3068 * timing mode) or for eMMC4.5 card read operation (in HS200
3069 * timing mode).
3070 * Select the 3/4 of the range and configure the DLL with the
3071 * selected DLL clock output phase.
3072*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303073static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303074 u8 *phase_table, u8 total_phases)
3075{
Subhash Jadavani34187042012-03-02 10:59:49 +05303076 int ret;
3077 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303078 u8 phases_per_row[16] = {0};
3079 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303080 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3081 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303082
Subhash Jadavani34187042012-03-02 10:59:49 +05303083 if (total_phases > 16) {
3084 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3085 mmc_hostname(host->mmc), __func__, total_phases);
3086 return -EINVAL;
3087 }
3088
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303089 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303090 ranges[row_index][col_index] = phase_table[cnt];
3091 phases_per_row[row_index] += 1;
3092 col_index++;
3093
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303094 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303095 continue;
3096 /* check if next phase in phase_table is consecutive or not */
3097 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3098 row_index++;
3099 col_index = 0;
3100 }
3101 }
3102
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303103 /* Check if phase-0 is present in first valid window? */
3104 if (!ranges[0][0]) {
3105 phase_0_found = true;
3106 phase_0_raw_index = 0;
3107 /* Check if cycle exist between 2 valid windows */
3108 for (cnt = 1; cnt <= row_index; cnt++) {
3109 if (phases_per_row[cnt]) {
3110 for (i = 0; i <= phases_per_row[cnt]; i++) {
3111 if (ranges[cnt][i] == 15) {
3112 phase_15_found = true;
3113 phase_15_raw_index = cnt;
3114 break;
3115 }
3116 }
3117 }
3118 }
3119 }
3120
3121 /* If 2 valid windows form cycle then merge them as single window */
3122 if (phase_0_found && phase_15_found) {
3123 /* number of phases in raw where phase 0 is present */
3124 u8 phases_0 = phases_per_row[phase_0_raw_index];
3125 /* number of phases in raw where phase 15 is present */
3126 u8 phases_15 = phases_per_row[phase_15_raw_index];
3127
3128 cnt = 0;
3129 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3130 ranges[phase_15_raw_index][i] =
3131 ranges[phase_0_raw_index][cnt];
3132 cnt++;
3133 }
3134 phases_per_row[phase_0_raw_index] = 0;
3135 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3136 }
3137
3138 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303139 if (phases_per_row[cnt] > curr_max) {
3140 curr_max = phases_per_row[cnt];
3141 selected_row_index = cnt;
3142 }
3143 }
3144
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303145 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303146 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303147
3148 return ret;
3149}
3150
Girish K Sa3f41692012-02-29 12:00:09 +05303151static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303152{
3153 int rc = 0;
3154 struct msmsdcc_host *host = mmc_priv(mmc);
3155 unsigned long flags;
3156 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303157 const u32 *tuning_block_pattern = tuning_block_64;
3158 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303159
3160 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3161
3162 /* Tuning is only required for SDR104 modes */
3163 if (!host->tuning_needed) {
3164 rc = 0;
3165 goto exit;
3166 }
3167
3168 spin_lock_irqsave(&host->lock, flags);
3169 WARN(!host->pwr, "SDCC power is turned off\n");
3170 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3171 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3172
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303173 host->tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303174 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303175 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3176 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3177 tuning_block_pattern = tuning_block_128;
3178 size = sizeof(tuning_block_128);
3179 }
3180
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303181 spin_unlock_irqrestore(&host->lock, flags);
3182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003183 /* first of all reset the tuning block */
3184 rc = msmsdcc_init_cm_sdc4_dll(host);
3185 if (rc)
3186 goto out;
3187
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303188 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003189 if (!data_buf) {
3190 rc = -ENOMEM;
3191 goto out;
3192 }
3193
3194 phase = 0;
3195 do {
3196 struct mmc_command cmd = {0};
3197 struct mmc_data data = {0};
3198 struct mmc_request mrq = {
3199 .cmd = &cmd,
3200 .data = &data
3201 };
3202 struct scatterlist sg;
3203
3204 /* set the phase in delay line hw block */
3205 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3206 if (rc)
3207 goto kfree;
3208
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303209 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003210 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3211
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303212 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003213 data.blocks = 1;
3214 data.flags = MMC_DATA_READ;
3215 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3216
3217 data.sg = &sg;
3218 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303219 sg_init_one(&sg, data_buf, size);
3220 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221 mmc_wait_for_req(mmc, &mrq);
3222
3223 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303224 !memcmp(data_buf, tuning_block_pattern, size)) {
3225 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003226 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303227 pr_debug("%s: %s: found good phase = %d\n",
3228 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 }
3230 } while (++phase < 16);
3231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303233 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303234 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303235 if (rc < 0)
3236 goto kfree;
3237 else
3238 phase = (u8)rc;
3239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 /*
3241 * Finally set the selected phase in delay
3242 * line hw block.
3243 */
3244 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3245 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303246 goto kfree;
3247 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3248 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249 } else {
3250 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303251 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303253 msmsdcc_dump_sdcc_state(host);
3254 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256
3257kfree:
3258 kfree(data_buf);
3259out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303260 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303261 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303262 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303263 spin_unlock_irqrestore(&host->lock, flags);
3264exit:
3265 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003267}
3268
3269static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003270 .enable = msmsdcc_enable,
3271 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003272 .request = msmsdcc_request,
3273 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003274 .get_ro = msmsdcc_get_ro,
3275#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003276 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277#endif
3278 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3279 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003280};
3281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282static unsigned int
3283msmsdcc_slot_status(struct msmsdcc_host *host)
3284{
3285 int status;
3286 unsigned int gpio_no = host->plat->status_gpio;
3287
3288 status = gpio_request(gpio_no, "SD_HW_Detect");
3289 if (status) {
3290 pr_err("%s: %s: Failed to request GPIO %d\n",
3291 mmc_hostname(host->mmc), __func__, gpio_no);
3292 } else {
3293 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003294 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003295 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003296 if (host->plat->is_status_gpio_active_low)
3297 status = !status;
3298 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003299 gpio_free(gpio_no);
3300 }
3301 return status;
3302}
3303
San Mehat9d2bd732009-09-22 16:44:22 -07003304static void
3305msmsdcc_check_status(unsigned long data)
3306{
3307 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3308 unsigned int status;
3309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003310 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003311 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003313 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 status = msmsdcc_slot_status(host);
3315
Krishna Konda941604a2012-01-10 17:46:34 -08003316 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003318 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003319 if (host->plat->status)
3320 pr_info("%s: Slot status change detected "
3321 "(%d -> %d)\n",
3322 mmc_hostname(host->mmc),
3323 host->oldstat, status);
3324 else if (host->plat->is_status_gpio_active_low)
3325 pr_info("%s: Slot status change detected "
3326 "(%d -> %d) and the card detect GPIO"
3327 " is ACTIVE_LOW\n",
3328 mmc_hostname(host->mmc),
3329 host->oldstat, status);
3330 else
3331 pr_info("%s: Slot status change detected "
3332 "(%d -> %d) and the card detect GPIO"
3333 " is ACTIVE_HIGH\n",
3334 mmc_hostname(host->mmc),
3335 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003336 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003337 }
3338 host->oldstat = status;
3339 } else {
3340 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003341 }
San Mehat9d2bd732009-09-22 16:44:22 -07003342}
3343
3344static irqreturn_t
3345msmsdcc_platform_status_irq(int irq, void *dev_id)
3346{
3347 struct msmsdcc_host *host = dev_id;
3348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003350 msmsdcc_check_status((unsigned long) host);
3351 return IRQ_HANDLED;
3352}
3353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354static irqreturn_t
3355msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3356{
3357 struct msmsdcc_host *host = dev_id;
3358
3359 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3360 spin_lock(&host->lock);
3361 if (!host->sdio_irq_disabled) {
3362 disable_irq_nosync(irq);
3363 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3364 wake_lock(&host->sdio_wlock);
3365 msmsdcc_disable_irq_wake(host);
3366 }
3367 host->sdio_irq_disabled = 1;
3368 }
3369 if (host->plat->is_sdio_al_client) {
3370 if (!host->clks_on) {
3371 msmsdcc_setup_clocks(host, true);
3372 host->clks_on = 1;
3373 }
3374 if (host->sdcc_irq_disabled) {
3375 writel_relaxed(host->mci_irqenable,
3376 host->base + MMCIMASK0);
3377 mb();
3378 enable_irq(host->core_irqres->start);
3379 host->sdcc_irq_disabled = 0;
3380 }
3381 wake_lock(&host->sdio_wlock);
3382 }
3383 spin_unlock(&host->lock);
3384
3385 return IRQ_HANDLED;
3386}
3387
San Mehat9d2bd732009-09-22 16:44:22 -07003388static void
3389msmsdcc_status_notify_cb(int card_present, void *dev_id)
3390{
3391 struct msmsdcc_host *host = dev_id;
3392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003394 card_present);
3395 msmsdcc_check_status((unsigned long) host);
3396}
3397
San Mehat9d2bd732009-09-22 16:44:22 -07003398static int
3399msmsdcc_init_dma(struct msmsdcc_host *host)
3400{
3401 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3402 host->dma.host = host;
3403 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003404 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003405
3406 if (!host->dmares)
3407 return -ENODEV;
3408
3409 host->dma.nc = dma_alloc_coherent(NULL,
3410 sizeof(struct msmsdcc_nc_dmadata),
3411 &host->dma.nc_busaddr,
3412 GFP_KERNEL);
3413 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003414 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003415 return -ENOMEM;
3416 }
3417 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3418 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3419 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3420 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3421 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003422 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003423
3424 return 0;
3425}
3426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3428/**
3429 * Allocate and Connect a SDCC peripheral's SPS endpoint
3430 *
3431 * This function allocates endpoint context and
3432 * connect it with memory endpoint by calling
3433 * appropriate SPS driver APIs.
3434 *
3435 * Also registers a SPS callback function with
3436 * SPS driver
3437 *
3438 * This function should only be called once typically
3439 * during driver probe.
3440 *
3441 * @host - Pointer to sdcc host structure
3442 * @ep - Pointer to sps endpoint data structure
3443 * @is_produce - 1 means Producer endpoint
3444 * 0 means Consumer endpoint
3445 *
3446 * @return - 0 if successful else negative value.
3447 *
3448 */
3449static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3450 struct msmsdcc_sps_ep_conn_data *ep,
3451 bool is_producer)
3452{
3453 int rc = 0;
3454 struct sps_pipe *sps_pipe_handle;
3455 struct sps_connect *sps_config = &ep->config;
3456 struct sps_register_event *sps_event = &ep->event;
3457
3458 /* Allocate endpoint context */
3459 sps_pipe_handle = sps_alloc_endpoint();
3460 if (!sps_pipe_handle) {
3461 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3462 mmc_hostname(host->mmc), is_producer);
3463 rc = -ENOMEM;
3464 goto out;
3465 }
3466
3467 /* Get default connection configuration for an endpoint */
3468 rc = sps_get_config(sps_pipe_handle, sps_config);
3469 if (rc) {
3470 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3471 " rc=%d", mmc_hostname(host->mmc),
3472 (u32)sps_pipe_handle, rc);
3473 goto get_config_err;
3474 }
3475
3476 /* Modify the default connection configuration */
3477 if (is_producer) {
3478 /*
3479 * For SDCC producer transfer, source should be
3480 * SDCC peripheral where as destination should
3481 * be system memory.
3482 */
3483 sps_config->source = host->sps.bam_handle;
3484 sps_config->destination = SPS_DEV_HANDLE_MEM;
3485 /* Producer pipe will handle this connection */
3486 sps_config->mode = SPS_MODE_SRC;
3487 sps_config->options =
3488 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3489 } else {
3490 /*
3491 * For SDCC consumer transfer, source should be
3492 * system memory where as destination should
3493 * SDCC peripheral
3494 */
3495 sps_config->source = SPS_DEV_HANDLE_MEM;
3496 sps_config->destination = host->sps.bam_handle;
3497 sps_config->mode = SPS_MODE_DEST;
3498 sps_config->options =
3499 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3500 }
3501
3502 /* Producer pipe index */
3503 sps_config->src_pipe_index = host->sps.src_pipe_index;
3504 /* Consumer pipe index */
3505 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3506 /*
3507 * This event thresold value is only significant for BAM-to-BAM
3508 * transfer. It's ignored for BAM-to-System mode transfer.
3509 */
3510 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303511
3512 /* Allocate maximum descriptor fifo size */
3513 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3514 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3516 sps_config->desc.size,
3517 &sps_config->desc.phys_base,
3518 GFP_KERNEL);
3519
Pratibhasagar V00b94332011-10-18 14:57:27 +05303520 if (!sps_config->desc.base) {
3521 rc = -ENOMEM;
3522 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3523 , mmc_hostname(host->mmc));
3524 goto get_config_err;
3525 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3527
3528 /* Establish connection between peripheral and memory endpoint */
3529 rc = sps_connect(sps_pipe_handle, sps_config);
3530 if (rc) {
3531 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3532 " rc=%d", mmc_hostname(host->mmc),
3533 (u32)sps_pipe_handle, rc);
3534 goto sps_connect_err;
3535 }
3536
3537 sps_event->mode = SPS_TRIGGER_CALLBACK;
3538 sps_event->options = SPS_O_EOT;
3539 sps_event->callback = msmsdcc_sps_complete_cb;
3540 sps_event->xfer_done = NULL;
3541 sps_event->user = (void *)host;
3542
3543 /* Register callback event for EOT (End of transfer) event. */
3544 rc = sps_register_event(sps_pipe_handle, sps_event);
3545 if (rc) {
3546 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3547 " rc=%d", mmc_hostname(host->mmc),
3548 (u32)sps_pipe_handle, rc);
3549 goto reg_event_err;
3550 }
3551 /* Now save the sps pipe handle */
3552 ep->pipe_handle = sps_pipe_handle;
3553 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3554 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3555 __func__, is_producer ? "READ" : "WRITE",
3556 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3557 goto out;
3558
3559reg_event_err:
3560 sps_disconnect(sps_pipe_handle);
3561sps_connect_err:
3562 dma_free_coherent(mmc_dev(host->mmc),
3563 sps_config->desc.size,
3564 sps_config->desc.base,
3565 sps_config->desc.phys_base);
3566get_config_err:
3567 sps_free_endpoint(sps_pipe_handle);
3568out:
3569 return rc;
3570}
3571
3572/**
3573 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3574 *
3575 * This function disconnect endpoint and deallocates
3576 * endpoint context.
3577 *
3578 * This function should only be called once typically
3579 * during driver remove.
3580 *
3581 * @host - Pointer to sdcc host structure
3582 * @ep - Pointer to sps endpoint data structure
3583 *
3584 */
3585static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3586 struct msmsdcc_sps_ep_conn_data *ep)
3587{
3588 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3589 struct sps_connect *sps_config = &ep->config;
3590 struct sps_register_event *sps_event = &ep->event;
3591
3592 sps_event->xfer_done = NULL;
3593 sps_event->callback = NULL;
3594 sps_register_event(sps_pipe_handle, sps_event);
3595 sps_disconnect(sps_pipe_handle);
3596 dma_free_coherent(mmc_dev(host->mmc),
3597 sps_config->desc.size,
3598 sps_config->desc.base,
3599 sps_config->desc.phys_base);
3600 sps_free_endpoint(sps_pipe_handle);
3601}
3602
3603/**
3604 * Reset SDCC peripheral's SPS endpoint
3605 *
3606 * This function disconnects an endpoint.
3607 *
3608 * This function should be called for reseting
3609 * SPS endpoint when data transfer error is
3610 * encountered during data transfer. This
3611 * can be considered as soft reset to endpoint.
3612 *
3613 * This function should only be called if
3614 * msmsdcc_sps_init() is already called.
3615 *
3616 * @host - Pointer to sdcc host structure
3617 * @ep - Pointer to sps endpoint data structure
3618 *
3619 * @return - 0 if successful else negative value.
3620 */
3621static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3622 struct msmsdcc_sps_ep_conn_data *ep)
3623{
3624 int rc = 0;
3625 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3626
3627 rc = sps_disconnect(sps_pipe_handle);
3628 if (rc) {
3629 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3630 " rc=%d", mmc_hostname(host->mmc), __func__,
3631 (u32)sps_pipe_handle, rc);
3632 goto out;
3633 }
3634 out:
3635 return rc;
3636}
3637
3638/**
3639 * Restore SDCC peripheral's SPS endpoint
3640 *
3641 * This function connects an endpoint.
3642 *
3643 * This function should be called for restoring
3644 * SPS endpoint after data transfer error is
3645 * encountered during data transfer. This
3646 * can be considered as soft reset to endpoint.
3647 *
3648 * This function should only be called if
3649 * msmsdcc_sps_reset_ep() is called before.
3650 *
3651 * @host - Pointer to sdcc host structure
3652 * @ep - Pointer to sps endpoint data structure
3653 *
3654 * @return - 0 if successful else negative value.
3655 */
3656static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3657 struct msmsdcc_sps_ep_conn_data *ep)
3658{
3659 int rc = 0;
3660 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3661 struct sps_connect *sps_config = &ep->config;
3662 struct sps_register_event *sps_event = &ep->event;
3663
3664 /* Establish connection between peripheral and memory endpoint */
3665 rc = sps_connect(sps_pipe_handle, sps_config);
3666 if (rc) {
3667 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3668 " rc=%d", mmc_hostname(host->mmc), __func__,
3669 (u32)sps_pipe_handle, rc);
3670 goto out;
3671 }
3672
3673 /* Register callback event for EOT (End of transfer) event. */
3674 rc = sps_register_event(sps_pipe_handle, sps_event);
3675 if (rc) {
3676 pr_err("%s: %s: sps_register_event() failed!!!"
3677 " pipe_handle=0x%x, rc=%d",
3678 mmc_hostname(host->mmc), __func__,
3679 (u32)sps_pipe_handle, rc);
3680 goto reg_event_err;
3681 }
3682 goto out;
3683
3684reg_event_err:
3685 sps_disconnect(sps_pipe_handle);
3686out:
3687 return rc;
3688}
3689
3690/**
3691 * Initialize SPS HW connected with SDCC core
3692 *
3693 * This function register BAM HW resources with
3694 * SPS driver and then initialize 2 SPS endpoints
3695 *
3696 * This function should only be called once typically
3697 * during driver probe.
3698 *
3699 * @host - Pointer to sdcc host structure
3700 *
3701 * @return - 0 if successful else negative value.
3702 *
3703 */
3704static int msmsdcc_sps_init(struct msmsdcc_host *host)
3705{
3706 int rc = 0;
3707 struct sps_bam_props bam = {0};
3708
3709 host->bam_base = ioremap(host->bam_memres->start,
3710 resource_size(host->bam_memres));
3711 if (!host->bam_base) {
3712 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3713 " size=0x%x", mmc_hostname(host->mmc),
3714 host->bam_memres->start,
3715 (host->bam_memres->end -
3716 host->bam_memres->start));
3717 rc = -ENOMEM;
3718 goto out;
3719 }
3720
3721 bam.phys_addr = host->bam_memres->start;
3722 bam.virt_addr = host->bam_base;
3723 /*
3724 * This event thresold value is only significant for BAM-to-BAM
3725 * transfer. It's ignored for BAM-to-System mode transfer.
3726 */
3727 bam.event_threshold = 0x10; /* Pipe event threshold */
3728 /*
3729 * This threshold controls when the BAM publish
3730 * the descriptor size on the sideband interface.
3731 * SPS HW will only be used when
3732 * data transfer size > MCI_FIFOSIZE (64 bytes).
3733 * PIO mode will be used when
3734 * data transfer size < MCI_FIFOSIZE (64 bytes).
3735 * So set this thresold value to 64 bytes.
3736 */
3737 bam.summing_threshold = 64;
3738 /* SPS driver wll handle the SDCC BAM IRQ */
3739 bam.irq = (u32)host->bam_irqres->start;
3740 bam.manage = SPS_BAM_MGR_LOCAL;
3741
3742 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3743 (u32)bam.phys_addr);
3744 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3745 (u32)bam.virt_addr);
3746
3747 /* Register SDCC Peripheral BAM device to SPS driver */
3748 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3749 if (rc) {
3750 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3751 mmc_hostname(host->mmc), rc);
3752 goto reg_bam_err;
3753 }
3754 pr_info("%s: BAM device registered. bam_handle=0x%x",
3755 mmc_hostname(host->mmc), host->sps.bam_handle);
3756
3757 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3758 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3759
3760 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3761 SPS_PROD_PERIPHERAL);
3762 if (rc)
3763 goto sps_reset_err;
3764 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3765 SPS_CONS_PERIPHERAL);
3766 if (rc)
3767 goto cons_conn_err;
3768
3769 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3770 mmc_hostname(host->mmc),
3771 (unsigned long long)host->bam_memres->start,
3772 (unsigned int)host->bam_irqres->start);
3773 goto out;
3774
3775cons_conn_err:
3776 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3777sps_reset_err:
3778 sps_deregister_bam_device(host->sps.bam_handle);
3779reg_bam_err:
3780 iounmap(host->bam_base);
3781out:
3782 return rc;
3783}
3784
3785/**
3786 * De-initialize SPS HW connected with SDCC core
3787 *
3788 * This function deinitialize SPS endpoints and then
3789 * deregisters BAM resources from SPS driver.
3790 *
3791 * This function should only be called once typically
3792 * during driver remove.
3793 *
3794 * @host - Pointer to sdcc host structure
3795 *
3796 */
3797static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3798{
3799 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3800 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3801 sps_deregister_bam_device(host->sps.bam_handle);
3802 iounmap(host->bam_base);
3803}
3804#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3805
3806static ssize_t
3807show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3808{
3809 struct mmc_host *mmc = dev_get_drvdata(dev);
3810 struct msmsdcc_host *host = mmc_priv(mmc);
3811 int poll;
3812 unsigned long flags;
3813
3814 spin_lock_irqsave(&host->lock, flags);
3815 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3816 spin_unlock_irqrestore(&host->lock, flags);
3817
3818 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3819}
3820
3821static ssize_t
3822set_polling(struct device *dev, struct device_attribute *attr,
3823 const char *buf, size_t count)
3824{
3825 struct mmc_host *mmc = dev_get_drvdata(dev);
3826 struct msmsdcc_host *host = mmc_priv(mmc);
3827 int value;
3828 unsigned long flags;
3829
3830 sscanf(buf, "%d", &value);
3831
3832 spin_lock_irqsave(&host->lock, flags);
3833 if (value) {
3834 mmc->caps |= MMC_CAP_NEEDS_POLL;
3835 mmc_detect_change(host->mmc, 0);
3836 } else {
3837 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3838 }
3839#ifdef CONFIG_HAS_EARLYSUSPEND
3840 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3841#endif
3842 spin_unlock_irqrestore(&host->lock, flags);
3843 return count;
3844}
3845
3846static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3847 show_polling, set_polling);
3848static struct attribute *dev_attrs[] = {
3849 &dev_attr_polling.attr,
3850 NULL,
3851};
3852static struct attribute_group dev_attr_grp = {
3853 .attrs = dev_attrs,
3854};
3855
3856#ifdef CONFIG_HAS_EARLYSUSPEND
3857static void msmsdcc_early_suspend(struct early_suspend *h)
3858{
3859 struct msmsdcc_host *host =
3860 container_of(h, struct msmsdcc_host, early_suspend);
3861 unsigned long flags;
3862
3863 spin_lock_irqsave(&host->lock, flags);
3864 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3865 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3866 spin_unlock_irqrestore(&host->lock, flags);
3867};
3868static void msmsdcc_late_resume(struct early_suspend *h)
3869{
3870 struct msmsdcc_host *host =
3871 container_of(h, struct msmsdcc_host, early_suspend);
3872 unsigned long flags;
3873
3874 if (host->polling_enabled) {
3875 spin_lock_irqsave(&host->lock, flags);
3876 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3877 mmc_detect_change(host->mmc, 0);
3878 spin_unlock_irqrestore(&host->lock, flags);
3879 }
3880};
3881#endif
3882
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303883void msmsdcc_print_regs(const char *name, void __iomem *base,
3884 unsigned int no_of_regs)
3885{
3886 unsigned int i;
3887
3888 if (!base)
3889 return;
3890 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3891 name, (u32)base);
3892 for (i = 0; i < no_of_regs; i = i + 4) {
3893 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3894 (u32)readl_relaxed(base + i*4),
3895 (u32)readl_relaxed(base + ((i+1)*4)),
3896 (u32)readl_relaxed(base + ((i+2)*4)),
3897 (u32)readl_relaxed(base + ((i+3)*4)));
3898 }
3899}
3900
3901static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3902{
3903 /* Dump current state of SDCC clocks, power and irq */
3904 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3905 (host->pwr ? "ON" : "OFF"));
3906 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3907 mmc_hostname(host->mmc),
3908 (host->clks_on ? "ON" : "OFF"),
3909 (u32)clk_get_rate(host->clk));
3910 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3911 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3912
3913 /* Now dump SDCC registers. Don't print FIFO registers */
3914 if (host->clks_on)
3915 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3916
3917 if (host->curr.data) {
3918 if (msmsdcc_check_dma_op_req(host->curr.data))
3919 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3920 else if (host->is_dma_mode)
3921 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3922 mmc_hostname(host->mmc), host->dma.busy,
3923 host->dma.channel, host->dma.crci);
3924 else if (host->is_sps_mode)
3925 pr_info("%s: SPS mode: busy=%d\n",
3926 mmc_hostname(host->mmc), host->sps.busy);
3927
3928 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3929 mmc_hostname(host->mmc), host->curr.xfer_size,
3930 host->curr.data_xfered, host->curr.xfer_remain);
3931 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3932 " wait_for_auto_prog_done=%d,"
3933 " got_auto_prog_done=%d\n",
3934 mmc_hostname(host->mmc), host->curr.got_dataend,
3935 host->prog_enable, host->curr.wait_for_auto_prog_done,
3936 host->curr.got_auto_prog_done);
3937 }
3938
3939}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3941{
3942 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3943 struct mmc_request *mrq;
3944 unsigned long flags;
3945
3946 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003947 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 pr_info("%s: %s: dummy CMD52 timeout\n",
3949 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003950 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 }
3952
3953 mrq = host->curr.mrq;
3954
3955 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303956 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3957 mrq->cmd->opcode);
3958 msmsdcc_dump_sdcc_state(host);
3959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003960 if (!mrq->cmd->error)
3961 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303962 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003964 if (mrq->data && !mrq->data->error)
3965 mrq->data->error = -ETIMEDOUT;
3966 host->curr.data_xfered = 0;
3967 if (host->dma.sg && host->is_dma_mode) {
3968 msm_dmov_stop_cmd(host->dma.channel,
3969 &host->dma.hdr, 0);
3970 } else if (host->sps.sg && host->is_sps_mode) {
3971 /* Stop current SPS transfer */
3972 msmsdcc_sps_exit_curr_xfer(host);
3973 } else {
3974 msmsdcc_reset_and_restore(host);
3975 msmsdcc_stop_data(host);
3976 if (mrq->data && mrq->data->stop)
3977 msmsdcc_start_command(host,
3978 mrq->data->stop, 0);
3979 else
3980 msmsdcc_request_end(host, mrq);
3981 }
3982 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303983 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 msmsdcc_reset_and_restore(host);
3985 msmsdcc_request_end(host, mrq);
3986 }
3987 }
3988 spin_unlock_irqrestore(&host->lock, flags);
3989}
3990
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303991static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3992{
3993 int i, ret;
3994 struct mmc_platform_data *pdata;
3995 struct device_node *np = dev->of_node;
3996 u32 bus_width = 0;
3997 u32 *clk_table;
3998 int clk_table_len;
3999 u32 *sup_voltages;
4000 int sup_volt_len;
4001
4002 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4003 if (!pdata) {
4004 dev_err(dev, "could not allocate memory for platform data\n");
4005 goto err;
4006 }
4007
4008 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4009 if (bus_width == 8) {
4010 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4011 } else if (bus_width == 4) {
4012 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4013 } else {
4014 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4015 pdata->mmc_bus_width = 0;
4016 }
4017
4018 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4019 size_t sz;
4020 sz = sup_volt_len / sizeof(*sup_voltages);
4021 if (sz > 0) {
4022 sup_voltages = devm_kzalloc(dev,
4023 sz * sizeof(*sup_voltages), GFP_KERNEL);
4024 if (!sup_voltages) {
4025 dev_err(dev, "No memory for supported voltage\n");
4026 goto err;
4027 }
4028
4029 ret = of_property_read_u32_array(np,
4030 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4031 if (ret < 0) {
4032 dev_err(dev, "error while reading voltage"
4033 "ranges %d\n", ret);
4034 goto err;
4035 }
4036 } else {
4037 dev_err(dev, "No supported voltages\n");
4038 goto err;
4039 }
4040 for (i = 0; i < sz; i += 2) {
4041 u32 mask;
4042
4043 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4044 sup_voltages[i + 1]);
4045 if (!mask)
4046 dev_err(dev, "Invalide voltage range %d\n", i);
4047 pdata->ocr_mask |= mask;
4048 }
4049 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4050 } else {
4051 dev_err(dev, "Supported voltage range not specified\n");
4052 }
4053
4054 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4055 size_t sz;
4056 sz = clk_table_len / sizeof(*clk_table);
4057
4058 if (sz > 0) {
4059 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4060 GFP_KERNEL);
4061 if (!clk_table) {
4062 dev_err(dev, "No memory for clock table\n");
4063 goto err;
4064 }
4065
4066 ret = of_property_read_u32_array(np,
4067 "qcom,sdcc-clk-rates", clk_table, sz);
4068 if (ret < 0) {
4069 dev_err(dev, "error while reading clk"
4070 "table %d\n", ret);
4071 goto err;
4072 }
4073 } else {
4074 dev_err(dev, "clk_table not specified\n");
4075 goto err;
4076 }
4077 pdata->sup_clk_table = clk_table;
4078 pdata->sup_clk_cnt = sz;
4079 } else {
4080 dev_err(dev, "Supported clock rates not specified\n");
4081 }
4082
4083 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4084 pdata->nonremovable = true;
4085 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4086 pdata->disable_cmd23 = true;
4087
4088 return pdata;
4089err:
4090 return NULL;
4091}
4092
San Mehat9d2bd732009-09-22 16:44:22 -07004093static int
4094msmsdcc_probe(struct platform_device *pdev)
4095{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304096 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004097 struct msmsdcc_host *host;
4098 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099 unsigned long flags;
4100 struct resource *core_irqres = NULL;
4101 struct resource *bam_irqres = NULL;
4102 struct resource *core_memres = NULL;
4103 struct resource *dml_memres = NULL;
4104 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004105 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004106 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304107 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004109
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304110 if (pdev->dev.of_node) {
4111 plat = msmsdcc_populate_pdata(&pdev->dev);
4112 of_property_read_u32((&pdev->dev)->of_node,
4113 "cell-index", &pdev->id);
4114 } else {
4115 plat = pdev->dev.platform_data;
4116 }
4117
San Mehat9d2bd732009-09-22 16:44:22 -07004118 /* must have platform data */
4119 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004120 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004121 ret = -EINVAL;
4122 goto out;
4123 }
4124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004126 return -EINVAL;
4127
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304128 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4129 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4130 return -EINVAL;
4131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004132
San Mehat9d2bd732009-09-22 16:44:22 -07004133 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004134 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004135 return -ENXIO;
4136 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304137 if (pdev->dev.of_node) {
4138 /*
4139 * Device tree iomem resources are only accessible by index.
4140 * index = 0 -> SDCC register interface
4141 * index = 1 -> DML register interface
4142 * index = 2 -> BAM register interface
4143 * IRQ resources:
4144 * index = 0 -> SDCC IRQ
4145 * index = 1 -> BAM IRQ
4146 */
4147 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4148 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4149 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4150 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4151 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4152 } else {
4153 for (i = 0; i < pdev->num_resources; i++) {
4154 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4155 if (!strncmp(pdev->resource[i].name,
4156 "sdcc_dml_addr",
4157 sizeof("sdcc_dml_addr")))
4158 dml_memres = &pdev->resource[i];
4159 else if (!strncmp(pdev->resource[i].name,
4160 "sdcc_bam_addr",
4161 sizeof("sdcc_bam_addr")))
4162 bam_memres = &pdev->resource[i];
4163 else
4164 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004165
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304166 }
4167 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4168 if (!strncmp(pdev->resource[i].name,
4169 "sdcc_bam_irq",
4170 sizeof("sdcc_bam_irq")))
4171 bam_irqres = &pdev->resource[i];
4172 else
4173 core_irqres = &pdev->resource[i];
4174 }
4175 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4176 if (!strncmp(pdev->resource[i].name,
4177 "sdcc_dma_chnl",
4178 sizeof("sdcc_dma_chnl")))
4179 dmares = &pdev->resource[i];
4180 else if (!strncmp(pdev->resource[i].name,
4181 "sdcc_dma_crci",
4182 sizeof("sdcc_dma_crci")))
4183 dma_crci_res = &pdev->resource[i];
4184 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004185 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004186 }
4187
4188 if (!core_irqres || !core_memres) {
4189 pr_err("%s: Invalid sdcc core resource\n", __func__);
4190 return -ENXIO;
4191 }
4192
4193 /*
4194 * Both BAM and DML memory resource should be preset.
4195 * BAM IRQ resource should also be present.
4196 */
4197 if ((bam_memres && !dml_memres) ||
4198 (!bam_memres && dml_memres) ||
4199 ((bam_memres && dml_memres) && !bam_irqres)) {
4200 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004201 return -ENXIO;
4202 }
4203
4204 /*
4205 * Setup our host structure
4206 */
San Mehat9d2bd732009-09-22 16:44:22 -07004207 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4208 if (!mmc) {
4209 ret = -ENOMEM;
4210 goto out;
4211 }
4212
4213 host = mmc_priv(mmc);
4214 host->pdev_id = pdev->id;
4215 host->plat = plat;
4216 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004217 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304218
4219 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220 host->is_sps_mode = 1;
4221 else if (dmares)
4222 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004224 host->base = ioremap(core_memres->start,
4225 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004226 if (!host->base) {
4227 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004228 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004229 }
4230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 host->core_irqres = core_irqres;
4232 host->bam_irqres = bam_irqres;
4233 host->core_memres = core_memres;
4234 host->dml_memres = dml_memres;
4235 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004236 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004237 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004238 spin_lock_init(&host->lock);
4239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004240#ifdef CONFIG_MMC_EMBEDDED_SDIO
4241 if (plat->embedded_sdio)
4242 mmc_set_embedded_sdio_data(mmc,
4243 &plat->embedded_sdio->cis,
4244 &plat->embedded_sdio->cccr,
4245 plat->embedded_sdio->funcs,
4246 plat->embedded_sdio->num_funcs);
4247#endif
4248
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304249 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4250 (unsigned long)host);
4251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4253 (unsigned long)host);
4254 if (host->is_dma_mode) {
4255 /* Setup DMA */
4256 ret = msmsdcc_init_dma(host);
4257 if (ret)
4258 goto ioremap_free;
4259 } else {
4260 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004261 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004262 }
4263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004264 /*
4265 * Setup SDCC clock if derived from Dayatona
4266 * fabric core clock.
4267 */
4268 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004269 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004270 if (!IS_ERR(host->dfab_pclk)) {
4271 /* Set the clock rate to 64MHz for max. performance */
4272 ret = clk_set_rate(host->dfab_pclk, 64000000);
4273 if (ret)
4274 goto dfab_pclk_put;
4275 ret = clk_enable(host->dfab_pclk);
4276 if (ret)
4277 goto dfab_pclk_put;
4278 } else
4279 goto dma_free;
4280 }
4281
4282 /*
4283 * Setup main peripheral bus clock
4284 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004285 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004286 if (!IS_ERR(host->pclk)) {
4287 ret = clk_enable(host->pclk);
4288 if (ret)
4289 goto pclk_put;
4290
4291 host->pclk_rate = clk_get_rate(host->pclk);
4292 }
4293
4294 /*
4295 * Setup SDC MMC clock
4296 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004297 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004298 if (IS_ERR(host->clk)) {
4299 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004300 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004301 }
4302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004303 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4304 if (ret) {
4305 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4306 goto clk_put;
4307 }
4308
4309 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004310 if (ret)
4311 goto clk_put;
4312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304314 if (!host->clk_rate)
4315 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304316
4317 /*
4318 * Lookup the Controller Version, to identify the supported features
4319 * Version number read as 0 would indicate SDCC3 or earlier versions
4320 */
4321 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4322 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4323 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304324 /*
4325 * Set the register write delay according to min. clock frequency
4326 * supported and update later when the host->clk_rate changes.
4327 */
4328 host->reg_write_delay =
4329 (1 + ((3 * USEC_PER_SEC) /
4330 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004331
4332 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304333 /* Apply Hard reset to SDCC to put it in power on default state */
4334 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004335
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304336 /* pm qos request to prevent apps idle power collapse */
4337 if (host->plat->swfi_latency)
4338 pm_qos_add_request(&host->pm_qos_req_dma,
4339 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004342 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004343 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004344 goto clk_disable;
4345 }
4346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004347
4348 /* Clocks has to be running before accessing SPS/DML HW blocks */
4349 if (host->is_sps_mode) {
4350 /* Initialize SPS */
4351 ret = msmsdcc_sps_init(host);
4352 if (ret)
4353 goto vreg_deinit;
4354 /* Initialize DML */
4355 ret = msmsdcc_dml_init(host);
4356 if (ret)
4357 goto sps_exit;
4358 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304359 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004360
San Mehat9d2bd732009-09-22 16:44:22 -07004361 /*
4362 * Setup MMC host structure
4363 */
4364 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4366 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004367 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4369 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004370
San Mehat9d2bd732009-09-22 16:44:22 -07004371 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304372 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304373
4374 /*
4375 * If we send the CMD23 before multi block write/read command
4376 * then we need not to send CMD12 at the end of the transfer.
4377 * If we don't send the CMD12 then only way to detect the PROG_DONE
4378 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4379 * controller. So let's enable the CMD23 for SDCC4 only.
4380 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304381 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304382 mmc->caps |= MMC_CAP_CMD23;
4383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004384 mmc->caps |= plat->uhs_caps;
4385 /*
4386 * XPC controls the maximum current in the default speed mode of SDXC
4387 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4388 * XPC=1 means 150mA (max.) and speed class is supported.
4389 */
4390 if (plat->xpc_cap)
4391 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4392 MMC_CAP_SET_XPC_180);
4393
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304394 if (pdev->dev.of_node) {
4395 if (of_get_property((&pdev->dev)->of_node,
4396 "qcom,sdcc-hs200", NULL))
4397 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4398 }
4399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400 if (plat->nonremovable)
4401 mmc->caps |= MMC_CAP_NONREMOVABLE;
4402#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4403 mmc->caps |= MMC_CAP_SDIO_IRQ;
4404#endif
4405
4406 if (plat->is_sdio_al_client)
4407 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004408
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304409 mmc->max_segs = msmsdcc_get_nr_sg(host);
4410 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4411 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004412
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304413 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304414 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004416 writel_relaxed(0, host->base + MMCIMASK0);
4417 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004419 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4420 mb();
4421 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004423 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4424 DRIVER_NAME " (cmd)", host);
4425 if (ret)
4426 goto dml_exit;
4427
4428 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4429 DRIVER_NAME " (pio)", host);
4430 if (ret)
4431 goto irq_free;
4432
4433 /*
4434 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4435 * IRQ is un-necessarily being monitored by MPM (Modem power
4436 * management block) during idle-power collapse. The MPM will be
4437 * configured to monitor the DATA1 GPIO line with level-low trigger
4438 * and thus depending on the GPIO status, it prevents TCXO shutdown
4439 * during idle-power collapse.
4440 */
4441 disable_irq(core_irqres->start);
4442 host->sdcc_irq_disabled = 1;
4443
4444 if (plat->sdiowakeup_irq) {
4445 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4446 mmc_hostname(mmc));
4447 ret = request_irq(plat->sdiowakeup_irq,
4448 msmsdcc_platform_sdiowakeup_irq,
4449 IRQF_SHARED | IRQF_TRIGGER_LOW,
4450 DRIVER_NAME "sdiowakeup", host);
4451 if (ret) {
4452 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4453 plat->sdiowakeup_irq, ret);
4454 goto pio_irq_free;
4455 } else {
4456 spin_lock_irqsave(&host->lock, flags);
4457 if (!host->sdio_irq_disabled) {
4458 disable_irq_nosync(plat->sdiowakeup_irq);
4459 host->sdio_irq_disabled = 1;
4460 }
4461 spin_unlock_irqrestore(&host->lock, flags);
4462 }
4463 }
4464
4465 if (plat->cfg_mpm_sdiowakeup) {
4466 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4467 mmc_hostname(mmc));
4468 }
4469
4470 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4471 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004472 /*
4473 * Setup card detect change
4474 */
4475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004476 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004477 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004478 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004479 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004480 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004481
Krishna Konda941604a2012-01-10 17:46:34 -08004482 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483 }
San Mehat9d2bd732009-09-22 16:44:22 -07004484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004485 if (plat->status_irq) {
4486 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004487 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004488 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004489 DRIVER_NAME " (slot)",
4490 host);
4491 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492 pr_err("Unable to get slot IRQ %d (%d)\n",
4493 plat->status_irq, ret);
4494 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004495 }
4496 } else if (plat->register_status_notify) {
4497 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4498 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004499 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004500 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004501
4502 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503
4504 ret = pm_runtime_set_active(&(pdev)->dev);
4505 if (ret < 0)
4506 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4507 __func__, ret);
4508 /*
4509 * There is no notion of suspend/resume for SD/MMC/SDIO
4510 * cards. So host can be suspended/resumed with out
4511 * worrying about its children.
4512 */
4513 pm_suspend_ignore_children(&(pdev)->dev, true);
4514
4515 /*
4516 * MMC/SD/SDIO bus suspend/resume operations are defined
4517 * only for the slots that will be used for non-removable
4518 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4519 * defined. Otherwise, they simply become card removal and
4520 * insertion events during suspend and resume respectively.
4521 * Hence, enable run-time PM only for slots for which bus
4522 * suspend/resume operations are defined.
4523 */
4524#ifdef CONFIG_MMC_UNSAFE_RESUME
4525 /*
4526 * If this capability is set, MMC core will enable/disable host
4527 * for every claim/release operation on a host. We use this
4528 * notification to increment/decrement runtime pm usage count.
4529 */
4530 mmc->caps |= MMC_CAP_DISABLE;
4531 pm_runtime_enable(&(pdev)->dev);
4532#else
4533 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4534 mmc->caps |= MMC_CAP_DISABLE;
4535 pm_runtime_enable(&(pdev)->dev);
4536 }
4537#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304538#ifndef CONFIG_PM_RUNTIME
4539 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4540#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4542 (unsigned long)host);
4543
San Mehat9d2bd732009-09-22 16:44:22 -07004544 mmc_add_host(mmc);
4545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004546#ifdef CONFIG_HAS_EARLYSUSPEND
4547 host->early_suspend.suspend = msmsdcc_early_suspend;
4548 host->early_suspend.resume = msmsdcc_late_resume;
4549 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4550 register_early_suspend(&host->early_suspend);
4551#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004552
Krishna Konda25786ec2011-07-25 16:21:36 -07004553 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4554 " dmacrcri %d\n", mmc_hostname(mmc),
4555 (unsigned long long)core_memres->start,
4556 (unsigned int) core_irqres->start,
4557 (unsigned int) plat->status_irq, host->dma.channel,
4558 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004559
4560 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4561 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4562 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4563 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4564 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4565 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4566 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4567 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4568 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4569 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4570 host->eject);
4571 pr_info("%s: Power save feature enable = %d\n",
4572 mmc_hostname(mmc), msmsdcc_pwrsave);
4573
Krishna Konda25786ec2011-07-25 16:21:36 -07004574 if (host->is_dma_mode && host->dma.channel != -1
4575 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004576 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004577 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004578 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004579 mmc_hostname(mmc), host->dma.cmd_busaddr,
4580 host->dma.cmdptr_busaddr);
4581 } else if (host->is_sps_mode) {
4582 pr_info("%s: SPS-BAM data transfer mode available\n",
4583 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004584 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004585 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004587#if defined(CONFIG_DEBUG_FS)
4588 msmsdcc_dbg_createhost(host);
4589#endif
4590 if (!plat->status_irq) {
4591 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4592 if (ret)
4593 goto platform_irq_free;
4594 }
San Mehat9d2bd732009-09-22 16:44:22 -07004595 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004596
4597 platform_irq_free:
4598 del_timer_sync(&host->req_tout_timer);
4599 pm_runtime_disable(&(pdev)->dev);
4600 pm_runtime_set_suspended(&(pdev)->dev);
4601
4602 if (plat->status_irq)
4603 free_irq(plat->status_irq, host);
4604 sdiowakeup_irq_free:
4605 wake_lock_destroy(&host->sdio_suspend_wlock);
4606 if (plat->sdiowakeup_irq)
4607 free_irq(plat->sdiowakeup_irq, host);
4608 pio_irq_free:
4609 if (plat->sdiowakeup_irq)
4610 wake_lock_destroy(&host->sdio_wlock);
4611 free_irq(core_irqres->start, host);
4612 irq_free:
4613 free_irq(core_irqres->start, host);
4614 dml_exit:
4615 if (host->is_sps_mode)
4616 msmsdcc_dml_exit(host);
4617 sps_exit:
4618 if (host->is_sps_mode)
4619 msmsdcc_sps_exit(host);
4620 vreg_deinit:
4621 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004622 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004623 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304624 if (host->plat->swfi_latency)
4625 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004626 clk_put:
4627 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004628 pclk_disable:
4629 if (!IS_ERR(host->pclk))
4630 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004631 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004632 if (!IS_ERR(host->pclk))
4633 clk_put(host->pclk);
4634 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4635 clk_disable(host->dfab_pclk);
4636 dfab_pclk_put:
4637 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4638 clk_put(host->dfab_pclk);
4639 dma_free:
4640 if (host->is_dma_mode) {
4641 if (host->dmares)
4642 dma_free_coherent(NULL,
4643 sizeof(struct msmsdcc_nc_dmadata),
4644 host->dma.nc, host->dma.nc_busaddr);
4645 }
4646 ioremap_free:
4647 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004648 host_free:
4649 mmc_free_host(mmc);
4650 out:
4651 return ret;
4652}
4653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004654static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004655{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4657 struct mmc_platform_data *plat;
4658 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004660 if (!mmc)
4661 return -ENXIO;
4662
4663 if (pm_runtime_suspended(&(pdev)->dev))
4664 pm_runtime_resume(&(pdev)->dev);
4665
4666 host = mmc_priv(mmc);
4667
4668 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4669 plat = host->plat;
4670
4671 if (!plat->status_irq)
4672 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4673
4674 del_timer_sync(&host->req_tout_timer);
4675 tasklet_kill(&host->dma_tlet);
4676 tasklet_kill(&host->sps.tlet);
4677 mmc_remove_host(mmc);
4678
4679 if (plat->status_irq)
4680 free_irq(plat->status_irq, host);
4681
4682 wake_lock_destroy(&host->sdio_suspend_wlock);
4683 if (plat->sdiowakeup_irq) {
4684 wake_lock_destroy(&host->sdio_wlock);
4685 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4686 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004687 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004688
4689 free_irq(host->core_irqres->start, host);
4690 free_irq(host->core_irqres->start, host);
4691
4692 clk_put(host->clk);
4693 if (!IS_ERR(host->pclk))
4694 clk_put(host->pclk);
4695 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4696 clk_put(host->dfab_pclk);
4697
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304698 if (host->plat->swfi_latency)
4699 pm_qos_remove_request(&host->pm_qos_req_dma);
4700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004701 msmsdcc_vreg_init(host, false);
4702
4703 if (host->is_dma_mode) {
4704 if (host->dmares)
4705 dma_free_coherent(NULL,
4706 sizeof(struct msmsdcc_nc_dmadata),
4707 host->dma.nc, host->dma.nc_busaddr);
4708 }
4709
4710 if (host->is_sps_mode) {
4711 msmsdcc_dml_exit(host);
4712 msmsdcc_sps_exit(host);
4713 }
4714
4715 iounmap(host->base);
4716 mmc_free_host(mmc);
4717
4718#ifdef CONFIG_HAS_EARLYSUSPEND
4719 unregister_early_suspend(&host->early_suspend);
4720#endif
4721 pm_runtime_disable(&(pdev)->dev);
4722 pm_runtime_set_suspended(&(pdev)->dev);
4723
4724 return 0;
4725}
4726
4727#ifdef CONFIG_MSM_SDIO_AL
4728int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4729{
4730 struct msmsdcc_host *host = mmc_priv(mmc);
4731 unsigned long flags;
4732
4733 spin_lock_irqsave(&host->lock, flags);
4734 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4735 enable ? "En" : "Dis");
4736
4737 if (enable) {
4738 if (!host->sdcc_irq_disabled) {
4739 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304740 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004741 host->sdcc_irq_disabled = 1;
4742 }
4743
4744 if (host->clks_on) {
4745 msmsdcc_setup_clocks(host, false);
4746 host->clks_on = 0;
4747 }
4748
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304749 if (host->plat->sdio_lpm_gpio_setup &&
4750 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 spin_unlock_irqrestore(&host->lock, flags);
4752 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4753 spin_lock_irqsave(&host->lock, flags);
4754 host->sdio_gpio_lpm = 1;
4755 }
4756
4757 if (host->sdio_irq_disabled) {
4758 msmsdcc_enable_irq_wake(host);
4759 enable_irq(host->plat->sdiowakeup_irq);
4760 host->sdio_irq_disabled = 0;
4761 }
4762 } else {
4763 if (!host->sdio_irq_disabled) {
4764 disable_irq_nosync(host->plat->sdiowakeup_irq);
4765 host->sdio_irq_disabled = 1;
4766 msmsdcc_disable_irq_wake(host);
4767 }
4768
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304769 if (host->plat->sdio_lpm_gpio_setup &&
4770 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004771 spin_unlock_irqrestore(&host->lock, flags);
4772 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4773 spin_lock_irqsave(&host->lock, flags);
4774 host->sdio_gpio_lpm = 0;
4775 }
4776
4777 if (!host->clks_on) {
4778 msmsdcc_setup_clocks(host, true);
4779 host->clks_on = 1;
4780 }
4781
4782 if (host->sdcc_irq_disabled) {
4783 writel_relaxed(host->mci_irqenable,
4784 host->base + MMCIMASK0);
4785 mb();
4786 enable_irq(host->core_irqres->start);
4787 host->sdcc_irq_disabled = 0;
4788 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789 }
4790 spin_unlock_irqrestore(&host->lock, flags);
4791 return 0;
4792}
4793#else
4794int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4795{
4796 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004797}
4798#endif
4799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004800#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004801static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004802msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004803{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004804 struct mmc_host *mmc = dev_get_drvdata(dev);
4805 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004806 int rc = 0;
4807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808 if (host->plat->is_sdio_al_client)
4809 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304810 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004811 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 host->sdcc_suspending = 1;
4813 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004815 /*
4816 * If the clocks are already turned off by SDIO clients (as
4817 * part of LPM), then clocks should be turned on before
4818 * calling mmc_suspend_host() because mmc_suspend_host might
4819 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304820 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 * cards, clocks will be turned on before mmc_suspend_host
4822 * and turned off after mmc_suspend_host.
4823 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304824 if (mmc->card && mmc_card_sdio(mmc->card)) {
4825 mmc->ios.clock = host->clk_rate;
4826 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4827 }
San Mehat9d2bd732009-09-22 16:44:22 -07004828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829 /*
4830 * MMC core thinks that host is disabled by now since
4831 * runtime suspend is scheduled after msmsdcc_disable()
4832 * is called. Thus, MMC core will try to enable the host
4833 * while suspending it. This results in a synchronous
4834 * runtime resume request while in runtime suspending
4835 * context and hence inorder to complete this resume
4836 * requet, it will wait for suspend to be complete,
4837 * but runtime suspend also can not proceed further
4838 * until the host is resumed. Thus, it leads to a hang.
4839 * Hence, increase the pm usage count before suspending
4840 * the host so that any resume requests after this will
4841 * simple become pm usage counter increment operations.
4842 */
4843 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304844 /* If there is pending detect work abort runtime suspend */
4845 if (unlikely(work_busy(&mmc->detect.work)))
4846 rc = -EAGAIN;
4847 else
4848 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004849 pm_runtime_put_noidle(dev);
4850
4851 if (!rc) {
4852 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4853 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4854 disable_irq(host->core_irqres->start);
4855 host->sdcc_irq_disabled = 1;
4856
4857 /*
4858 * If MMC core level suspend is not supported,
4859 * turn off clocks to allow deep sleep (TCXO
4860 * shutdown).
4861 */
4862 mmc->ios.clock = 0;
4863 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4864 enable_irq(host->core_irqres->start);
4865 host->sdcc_irq_disabled = 0;
4866
4867 if (host->plat->sdiowakeup_irq) {
4868 host->sdio_irq_disabled = 0;
4869 msmsdcc_enable_irq_wake(host);
4870 enable_irq(host->plat->sdiowakeup_irq);
4871 }
4872 }
4873 }
4874 host->sdcc_suspending = 0;
4875 mmc->suspend_task = NULL;
4876 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4877 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004878 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304879 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004880 return rc;
4881}
4882
4883static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004884msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004885{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004886 struct mmc_host *mmc = dev_get_drvdata(dev);
4887 struct msmsdcc_host *host = mmc_priv(mmc);
4888 unsigned long flags;
4889
4890 if (host->plat->is_sdio_al_client)
4891 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004892
Sahitya Tummala7661a452011-07-18 13:28:35 +05304893 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004894 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004895 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4896 if (host->sdcc_irq_disabled) {
4897 enable_irq(host->core_irqres->start);
4898 host->sdcc_irq_disabled = 0;
4899 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304900 mmc->ios.clock = host->clk_rate;
4901 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004902
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304903 spin_lock_irqsave(&host->lock, flags);
4904 writel_relaxed(host->mci_irqenable,
4905 host->base + MMCIMASK0);
4906 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004907
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304908 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4909 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004910 if (host->plat->sdiowakeup_irq) {
4911 disable_irq_nosync(
4912 host->plat->sdiowakeup_irq);
4913 msmsdcc_disable_irq_wake(host);
4914 host->sdio_irq_disabled = 1;
4915 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304916 }
San Mehat9d2bd732009-09-22 16:44:22 -07004917
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304918 spin_unlock_irqrestore(&host->lock, flags);
4919 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004920
4921 mmc_resume_host(mmc);
4922
4923 /*
4924 * FIXME: Clearing of flags must be handled in clients
4925 * resume handler.
4926 */
4927 spin_lock_irqsave(&host->lock, flags);
4928 mmc->pm_flags = 0;
4929 spin_unlock_irqrestore(&host->lock, flags);
4930
4931 /*
4932 * After resuming the host wait for sometime so that
4933 * the SDIO work will be processed.
4934 */
4935 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4936 if ((host->plat->cfg_mpm_sdiowakeup ||
4937 host->plat->sdiowakeup_irq) &&
4938 wake_lock_active(&host->sdio_wlock))
4939 wake_lock_timeout(&host->sdio_wlock, 1);
4940 }
4941
4942 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004943 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304944 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004945 return 0;
4946}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947
4948static int msmsdcc_runtime_idle(struct device *dev)
4949{
4950 struct mmc_host *mmc = dev_get_drvdata(dev);
4951 struct msmsdcc_host *host = mmc_priv(mmc);
4952
4953 if (host->plat->is_sdio_al_client)
4954 return 0;
4955
4956 /* Idle timeout is not configurable for now */
4957 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4958
4959 return -EAGAIN;
4960}
4961
4962static int msmsdcc_pm_suspend(struct device *dev)
4963{
4964 struct mmc_host *mmc = dev_get_drvdata(dev);
4965 struct msmsdcc_host *host = mmc_priv(mmc);
4966 int rc = 0;
4967
4968 if (host->plat->is_sdio_al_client)
4969 return 0;
4970
4971
4972 if (host->plat->status_irq)
4973 disable_irq(host->plat->status_irq);
4974
4975 if (!pm_runtime_suspended(dev))
4976 rc = msmsdcc_runtime_suspend(dev);
4977
4978 return rc;
4979}
4980
4981static int msmsdcc_pm_resume(struct device *dev)
4982{
4983 struct mmc_host *mmc = dev_get_drvdata(dev);
4984 struct msmsdcc_host *host = mmc_priv(mmc);
4985 int rc = 0;
4986
4987 if (host->plat->is_sdio_al_client)
4988 return 0;
4989
Sahitya Tummalafb486372011-09-02 19:01:49 +05304990 if (!pm_runtime_suspended(dev))
4991 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 if (host->plat->status_irq) {
4993 msmsdcc_check_status((unsigned long)host);
4994 enable_irq(host->plat->status_irq);
4995 }
4996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004997 return rc;
4998}
4999
Daniel Walker08ecfde2010-06-23 12:32:20 -07005000#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005001#define msmsdcc_runtime_suspend NULL
5002#define msmsdcc_runtime_resume NULL
5003#define msmsdcc_runtime_idle NULL
5004#define msmsdcc_pm_suspend NULL
5005#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005006#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005008static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5009 .runtime_suspend = msmsdcc_runtime_suspend,
5010 .runtime_resume = msmsdcc_runtime_resume,
5011 .runtime_idle = msmsdcc_runtime_idle,
5012 .suspend = msmsdcc_pm_suspend,
5013 .resume = msmsdcc_pm_resume,
5014};
5015
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305016static const struct of_device_id msmsdcc_dt_match[] = {
5017 {.compatible = "qcom,msm-sdcc"},
5018
5019};
5020MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5021
San Mehat9d2bd732009-09-22 16:44:22 -07005022static struct platform_driver msmsdcc_driver = {
5023 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005024 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005025 .driver = {
5026 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005027 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305028 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005029 },
5030};
5031
5032static int __init msmsdcc_init(void)
5033{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034#if defined(CONFIG_DEBUG_FS)
5035 int ret = 0;
5036 ret = msmsdcc_dbg_init();
5037 if (ret) {
5038 pr_err("Failed to create debug fs dir \n");
5039 return ret;
5040 }
5041#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005042 return platform_driver_register(&msmsdcc_driver);
5043}
5044
5045static void __exit msmsdcc_exit(void)
5046{
5047 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048
5049#if defined(CONFIG_DEBUG_FS)
5050 debugfs_remove(debugfs_file);
5051 debugfs_remove(debugfs_dir);
5052#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005053}
5054
5055module_init(msmsdcc_init);
5056module_exit(msmsdcc_exit);
5057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005058MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005059MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005060
5061#if defined(CONFIG_DEBUG_FS)
5062
5063static int
5064msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5065{
5066 file->private_data = inode->i_private;
5067 return 0;
5068}
5069
5070static ssize_t
5071msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5072 size_t count, loff_t *ppos)
5073{
5074 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005075 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005076 int max, i;
5077
5078 i = 0;
5079 max = sizeof(buf) - 1;
5080
5081 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5082 host->curr.cmd, host->curr.data);
5083 if (host->curr.cmd) {
5084 struct mmc_command *cmd = host->curr.cmd;
5085
5086 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5087 cmd->opcode, cmd->arg, cmd->flags);
5088 }
5089 if (host->curr.data) {
5090 struct mmc_data *data = host->curr.data;
5091 i += scnprintf(buf + i, max - i,
5092 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5093 data->timeout_ns, data->timeout_clks,
5094 data->blksz, data->blocks, data->error,
5095 data->flags);
5096 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5097 host->curr.xfer_size, host->curr.xfer_remain,
5098 host->curr.data_xfered, host->dma.sg);
5099 }
5100
5101 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5102}
5103
5104static const struct file_operations msmsdcc_dbg_state_ops = {
5105 .read = msmsdcc_dbg_state_read,
5106 .open = msmsdcc_dbg_state_open,
5107};
5108
5109static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5110{
5111 if (debugfs_dir) {
5112 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5113 0644, debugfs_dir, host,
5114 &msmsdcc_dbg_state_ops);
5115 }
5116}
5117
5118static int __init msmsdcc_dbg_init(void)
5119{
5120 int err;
5121
5122 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5123 if (IS_ERR(debugfs_dir)) {
5124 err = PTR_ERR(debugfs_dir);
5125 debugfs_dir = NULL;
5126 return err;
5127 }
5128
5129 return 0;
5130}
5131#endif