blob: ff12eb18ca793fe2ea3f334c836f6edb51deafdd [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 del_timer(&host->req_tout_timer);
346
San Mehat9d2bd732009-09-22 16:44:22 -0700347 if (mrq->data)
348 mrq->data->bytes_xfered = host->curr.data_xfered;
349 if (mrq->cmd->error == -ETIMEDOUT)
350 mdelay(5);
351
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530352 /* Clear current request information as current request has ended */
353 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
354
San Mehat9d2bd732009-09-22 16:44:22 -0700355 /*
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 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530516 /*
517 * Clear current request information as current
518 * request has ended
519 */
520 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700521 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522
San Mehat9d2bd732009-09-22 16:44:22 -0700523 mmc_request_done(host->mmc, mrq);
524 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530525 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
526 || !mrq->sbc)) {
527 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530528 }
San Mehat9d2bd732009-09-22 16:44:22 -0700529 }
530
531out:
532 spin_unlock_irqrestore(&host->lock, flags);
533 return;
534}
535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
537/**
538 * Callback notification from SPS driver
539 *
540 * This callback function gets triggered called from
541 * SPS driver when requested SPS data transfer is
542 * completed.
543 *
544 * SPS driver invokes this callback in BAM irq context so
545 * SDCC driver schedule a tasklet for further processing
546 * this callback notification at later point of time in
547 * tasklet context and immediately returns control back
548 * to SPS driver.
549 *
550 * @nofity - Pointer to sps event notify sturcture
551 *
552 */
553static void
554msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
555{
556 struct msmsdcc_host *host =
557 (struct msmsdcc_host *)
558 ((struct sps_event_notify *)notify)->user;
559
560 host->sps.notify = *notify;
561 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
562 mmc_hostname(host->mmc), __func__, notify->event_id,
563 notify->data.transfer.iovec.addr,
564 notify->data.transfer.iovec.size,
565 notify->data.transfer.iovec.flags);
566 /* Schedule a tasklet for completing data transfer */
567 tasklet_schedule(&host->sps.tlet);
568}
569
570/**
571 * Tasklet handler for processing SPS callback event
572 *
573 * This function processing SPS event notification and
574 * checks if the SPS transfer is completed or not and
575 * then accordingly notifies status to MMC core layer.
576 *
577 * This function is called in tasklet context.
578 *
579 * @data - Pointer to sdcc driver data
580 *
581 */
582static void msmsdcc_sps_complete_tlet(unsigned long data)
583{
584 unsigned long flags;
585 int i, rc;
586 u32 data_xfered = 0;
587 struct mmc_request *mrq;
588 struct sps_iovec iovec;
589 struct sps_pipe *sps_pipe_handle;
590 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
591 struct sps_event_notify *notify = &host->sps.notify;
592
593 spin_lock_irqsave(&host->lock, flags);
594 if (host->sps.dir == DMA_FROM_DEVICE)
595 sps_pipe_handle = host->sps.prod.pipe_handle;
596 else
597 sps_pipe_handle = host->sps.cons.pipe_handle;
598 mrq = host->curr.mrq;
599
600 if (!mrq) {
601 spin_unlock_irqrestore(&host->lock, flags);
602 return;
603 }
604
605 pr_debug("%s: %s: sps event_id=%d\n",
606 mmc_hostname(host->mmc), __func__,
607 notify->event_id);
608
609 if (msmsdcc_is_dml_busy(host)) {
610 /* oops !!! this should never happen. */
611 pr_err("%s: %s: Received SPS EOT event"
612 " but DML HW is still busy !!!\n",
613 mmc_hostname(host->mmc), __func__);
614 }
615 /*
616 * Got End of transfer event!!! Check if all of the data
617 * has been transferred?
618 */
619 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
620 rc = sps_get_iovec(sps_pipe_handle, &iovec);
621 if (rc) {
622 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
623 mmc_hostname(host->mmc), __func__, rc, i);
624 break;
625 }
626 data_xfered += iovec.size;
627 }
628
629 if (data_xfered == host->curr.xfer_size) {
630 host->curr.data_xfered = host->curr.xfer_size;
631 host->curr.xfer_remain -= host->curr.xfer_size;
632 pr_debug("%s: Data xfer success. data_xfered=0x%x",
633 mmc_hostname(host->mmc),
634 host->curr.xfer_size);
635 } else {
636 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
637 " xfer_size=%d", mmc_hostname(host->mmc),
638 data_xfered, host->curr.xfer_size);
639 msmsdcc_reset_and_restore(host);
640 if (!mrq->data->error)
641 mrq->data->error = -EIO;
642 }
643
644 /* Unmap sg buffers */
645 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
646 host->sps.dir);
647
648 host->sps.sg = NULL;
649 host->sps.busy = 0;
650
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530651 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
652 (host->curr.wait_for_auto_prog_done &&
653 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 /*
655 * If we've already gotten our DATAEND / DATABLKEND
656 * for this request, then complete it through here.
657 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658
659 if (!mrq->data->error) {
660 host->curr.data_xfered = host->curr.xfer_size;
661 host->curr.xfer_remain -= host->curr.xfer_size;
662 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700663 if (host->dummy_52_needed) {
664 mrq->data->bytes_xfered = host->curr.data_xfered;
665 host->dummy_52_sent = 1;
666 msmsdcc_start_command(host, &dummy52cmd,
667 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700668 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700669 return;
670 }
671 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530672 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530673 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 mrq->data->bytes_xfered = host->curr.data_xfered;
675 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530676 /*
677 * Clear current request information as current
678 * request has ended
679 */
680 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 spin_unlock_irqrestore(&host->lock, flags);
682
683 mmc_request_done(host->mmc, mrq);
684 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530685 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
686 || !mrq->sbc)) {
687 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 }
689 }
690 spin_unlock_irqrestore(&host->lock, flags);
691}
692
693/**
694 * Exit from current SPS data transfer
695 *
696 * This function exits from current SPS data transfer.
697 *
698 * This function should be called when error condition
699 * is encountered during data transfer.
700 *
701 * @host - Pointer to sdcc host structure
702 *
703 */
704static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
705{
706 struct mmc_request *mrq;
707
708 mrq = host->curr.mrq;
709 BUG_ON(!mrq);
710
711 msmsdcc_reset_and_restore(host);
712 if (!mrq->data->error)
713 mrq->data->error = -EIO;
714
715 /* Unmap sg buffers */
716 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
717 host->sps.dir);
718
719 host->sps.sg = NULL;
720 host->sps.busy = 0;
721 if (host->curr.data)
722 msmsdcc_stop_data(host);
723
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530724 if (!mrq->data->stop || mrq->cmd->error ||
725 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530727 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
728 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 msmsdcc_start_command(host, mrq->data->stop, 0);
730
731}
732#else
733static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
734static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
735static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
736#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
737
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530738static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530740static void
741msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
742 unsigned int result,
743 struct msm_dmov_errdata *err)
744{
745 struct msmsdcc_dma_data *dma_data =
746 container_of(cmd, struct msmsdcc_dma_data, hdr);
747 struct msmsdcc_host *host = dma_data->host;
748
749 dma_data->result = result;
750 if (err)
751 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
752
753 tasklet_schedule(&host->dma_tlet);
754}
755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700757{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
759 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700760 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 else
762 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700763}
764
765static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
766{
767 struct msmsdcc_nc_dmadata *nc;
768 dmov_box *box;
769 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700770 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530771 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700772 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530773 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700774
Krishna Konda25786ec2011-07-25 16:21:36 -0700775 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700777
Krishna Konda25786ec2011-07-25 16:21:36 -0700778 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
779
San Mehat9d2bd732009-09-22 16:44:22 -0700780 host->dma.sg = data->sg;
781 host->dma.num_ents = data->sg_len;
782
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530783 /* Prevent memory corruption */
784 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800785
San Mehat9d2bd732009-09-22 16:44:22 -0700786 nc = host->dma.nc;
787
San Mehat9d2bd732009-09-22 16:44:22 -0700788 if (data->flags & MMC_DATA_READ)
789 host->dma.dir = DMA_FROM_DEVICE;
790 else
791 host->dma.dir = DMA_TO_DEVICE;
792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
794 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795
796 if (n != host->dma.num_ents) {
797 pr_err("%s: Unable to map in all sg elements\n",
798 mmc_hostname(host->mmc));
799 host->dma.sg = NULL;
800 host->dma.num_ents = 0;
801 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800802 }
San Mehat9d2bd732009-09-22 16:44:22 -0700803
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530804 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
805 host->curr.user_pages = 0;
806 box = &nc->cmd[0];
807 for (i = 0; i < host->dma.num_ents; i++) {
808 len = sg_dma_len(sg);
809 offset = 0;
810
811 do {
812 /* Check if we can do DMA */
813 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
814 err = -ENOTSUPP;
815 goto unmap;
816 }
817
818 box->cmd = CMD_MODE_BOX;
819
820 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
821 len = MMC_MAX_DMA_BOX_LENGTH;
822 len -= len % data->blksz;
823 }
824 rows = (len % MCI_FIFOSIZE) ?
825 (len / MCI_FIFOSIZE) + 1 :
826 (len / MCI_FIFOSIZE);
827
828 if (data->flags & MMC_DATA_READ) {
829 box->src_row_addr = msmsdcc_fifo_addr(host);
830 box->dst_row_addr = sg_dma_address(sg) + offset;
831 box->src_dst_len = (MCI_FIFOSIZE << 16) |
832 (MCI_FIFOSIZE);
833 box->row_offset = MCI_FIFOSIZE;
834 box->num_rows = rows * ((1 << 16) + 1);
835 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
836 } else {
837 box->src_row_addr = sg_dma_address(sg) + offset;
838 box->dst_row_addr = msmsdcc_fifo_addr(host);
839 box->src_dst_len = (MCI_FIFOSIZE << 16) |
840 (MCI_FIFOSIZE);
841 box->row_offset = (MCI_FIFOSIZE << 16);
842 box->num_rows = rows * ((1 << 16) + 1);
843 box->cmd |= CMD_DST_CRCI(host->dma.crci);
844 }
845
846 offset += len;
847 len = sg_dma_len(sg) - offset;
848 box++;
849 box_cmd_cnt++;
850 } while (len);
851 sg++;
852 }
853 /* Mark last command */
854 box--;
855 box->cmd |= CMD_LC;
856
857 /* location of command block must be 64 bit aligned */
858 BUG_ON(host->dma.cmd_busaddr & 0x07);
859
860 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
861 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
862 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
863 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
864
865 /* Flush all data to memory before starting dma */
866 mb();
867
868unmap:
869 if (err) {
870 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
871 host->dma.num_ents, host->dma.dir);
872 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
873 mmc_hostname(host->mmc), err);
874 }
875
876 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700877}
878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
880/**
881 * Submits data transfer request to SPS driver
882 *
883 * This function make sg (scatter gather) data buffers
884 * DMA ready and then submits them to SPS driver for
885 * transfer.
886 *
887 * @host - Pointer to sdcc host structure
888 * @data - Pointer to mmc_data structure
889 *
890 * @return 0 if success else negative value
891 */
892static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
893 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800894{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895 int rc = 0;
896 u32 flags;
897 int i;
898 u32 addr, len, data_cnt;
899 struct scatterlist *sg = data->sg;
900 struct sps_pipe *sps_pipe_handle;
901
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530902 /* Prevent memory corruption */
903 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904
905 host->sps.sg = data->sg;
906 host->sps.num_ents = data->sg_len;
907 host->sps.xfer_req_cnt = 0;
908 if (data->flags & MMC_DATA_READ) {
909 host->sps.dir = DMA_FROM_DEVICE;
910 sps_pipe_handle = host->sps.prod.pipe_handle;
911 } else {
912 host->sps.dir = DMA_TO_DEVICE;
913 sps_pipe_handle = host->sps.cons.pipe_handle;
914 }
915
916 /* Make sg buffers DMA ready */
917 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
918 host->sps.dir);
919
920 if (rc != data->sg_len) {
921 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
922 mmc_hostname(host->mmc), rc);
923 host->sps.sg = NULL;
924 host->sps.num_ents = 0;
925 rc = -ENOMEM;
926 goto dma_map_err;
927 }
928
929 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
930 mmc_hostname(host->mmc), __func__,
931 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
932 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
933
934 for (i = 0; i < data->sg_len; i++) {
935 /*
936 * Check if this is the last buffer to transfer?
937 * If yes then set the INT and EOT flags.
938 */
939 len = sg_dma_len(sg);
940 addr = sg_dma_address(sg);
941 flags = 0;
942 while (len > 0) {
943 if (len > SPS_MAX_DESC_SIZE) {
944 data_cnt = SPS_MAX_DESC_SIZE;
945 } else {
946 data_cnt = len;
947 if (i == data->sg_len - 1)
948 flags = SPS_IOVEC_FLAG_INT |
949 SPS_IOVEC_FLAG_EOT;
950 }
951 rc = sps_transfer_one(sps_pipe_handle, addr,
952 data_cnt, host, flags);
953 if (rc) {
954 pr_err("%s: sps_transfer_one() error! rc=%d,"
955 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
956 mmc_hostname(host->mmc), rc,
957 (u32)sps_pipe_handle, (u32)sg, i);
958 goto dma_map_err;
959 }
960 addr += data_cnt;
961 len -= data_cnt;
962 host->sps.xfer_req_cnt++;
963 }
964 sg++;
965 }
966 goto out;
967
968dma_map_err:
969 /* unmap sg buffers */
970 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
971 host->sps.dir);
972out:
973 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700974}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700975#else
976static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
977 struct mmc_data *data) { return 0; }
978#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700979
980static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800981msmsdcc_start_command_deferred(struct msmsdcc_host *host,
982 struct mmc_command *cmd, u32 *c)
983{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530984 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 cmd->opcode, cmd->arg, cmd->flags);
986
San Mehat56a8b5b2009-11-21 12:29:46 -0800987 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
988
989 if (cmd->flags & MMC_RSP_PRESENT) {
990 if (cmd->flags & MMC_RSP_136)
991 *c |= MCI_CPSM_LONGRSP;
992 *c |= MCI_CPSM_RESPONSE;
993 }
994
995 if (/*interrupt*/0)
996 *c |= MCI_CPSM_INTERRUPT;
997
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530998 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
999 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1000 cmd->opcode == MMC_WRITE_BLOCK ||
1001 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1002 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001003 *c |= MCI_CSPM_DATCMD;
1004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301006 if (host->tuning_needed &&
1007 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1008
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301009 /*
1010 * For open ended block read operation (without CMD23),
1011 * AUTO_CMD19 bit should be set while sending the READ command.
1012 * For close ended block read operation (with CMD23),
1013 * AUTO_CMD19 bit should be set while sending CMD23.
1014 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301015 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1016 host->curr.mrq->cmd->opcode ==
1017 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301018 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301019 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1020 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301021 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1022 *c |= MCI_CSPM_AUTO_CMD19;
1023 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 }
1025
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301026 /* Clear CDR_EN bit for write operations */
1027 if (host->tuning_needed && cmd->mrq->data &&
1028 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1029 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1030 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1031
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301032 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301033 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301035 }
1036
San Mehat56a8b5b2009-11-21 12:29:46 -08001037 if (cmd == cmd->mrq->stop)
1038 *c |= MCI_CSPM_MCIABORT;
1039
San Mehat56a8b5b2009-11-21 12:29:46 -08001040 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 pr_err("%s: Overlapping command requests\n",
1042 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001043 }
1044 host->curr.cmd = cmd;
1045}
1046
1047static void
1048msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1049 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001050{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301051 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001052 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001054 unsigned int pio_irqmask = 0;
1055
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301056 BUG_ON(!data->sg);
1057 BUG_ON(!data->sg_len);
1058
San Mehat9d2bd732009-09-22 16:44:22 -07001059 host->curr.data = data;
1060 host->curr.xfer_size = data->blksz * data->blocks;
1061 host->curr.xfer_remain = host->curr.xfer_size;
1062 host->curr.data_xfered = 0;
1063 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301064 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001065
San Mehat9d2bd732009-09-22 16:44:22 -07001066 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1067
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301068 if (host->curr.wait_for_auto_prog_done)
1069 datactrl |= MCI_AUTO_PROG_DONE;
1070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 if (!msmsdcc_check_dma_op_req(data)) {
1072 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1073 datactrl |= MCI_DPSM_DMAENABLE;
1074 } else if (host->is_sps_mode) {
1075 if (!msmsdcc_is_dml_busy(host)) {
1076 if (!msmsdcc_sps_start_xfer(host, data)) {
1077 /* Now kick start DML transfer */
1078 mb();
1079 msmsdcc_dml_start_xfer(host, data);
1080 datactrl |= MCI_DPSM_DMAENABLE;
1081 host->sps.busy = 1;
1082 }
1083 } else {
1084 /*
1085 * Can't proceed with new transfer as
1086 * previous trasnfer is already in progress.
1087 * There is no point of going into PIO mode
1088 * as well. Is this a time to do kernel panic?
1089 */
1090 pr_err("%s: %s: DML HW is busy!!!"
1091 " Can't perform new SPS transfers"
1092 " now\n", mmc_hostname(host->mmc),
1093 __func__);
1094 }
1095 }
1096 }
1097
1098 /* Is data transfer in PIO mode required? */
1099 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001100 if (data->flags & MMC_DATA_READ) {
1101 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1102 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1103 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001104 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1106 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001107
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001108 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001109 }
1110
1111 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301112 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001113
San Mehat56a8b5b2009-11-21 12:29:46 -08001114 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001116 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1119 /* Use ADM (Application Data Mover) HW for Data transfer */
1120 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001121 host->cmd_timeout = timeout;
1122 host->cmd_pio_irqmask = pio_irqmask;
1123 host->cmd_datactrl = datactrl;
1124 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1127 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001128 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001129
1130 if (cmd) {
1131 msmsdcc_start_command_deferred(host, cmd, &c);
1132 host->cmd_c = c;
1133 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1135 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1136 host->base + MMCIMASK0);
1137 mb();
1138 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001139 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1146 (~(MCI_IRQ_PIO))) | pio_irqmask,
1147 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301149 /*
1150 * We don't need delay after writing to DATA_CTRL register
1151 * if we are not writing to CMD register immediately after
1152 * this. As we already have delay before sending the
1153 * command, we just need mb() here.
1154 */
1155 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001156
1157 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001159 /* Daisy-chain the command if requested */
1160 msmsdcc_start_command(host, cmd, c);
1161 }
San Mehat9d2bd732009-09-22 16:44:22 -07001162 }
1163}
1164
1165static void
1166msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1167{
San Mehat56a8b5b2009-11-21 12:29:46 -08001168 msmsdcc_start_command_deferred(host, cmd, &c);
1169 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001170}
1171
1172static void
1173msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1174 unsigned int status)
1175{
1176 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1178 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1179 pr_err("%s: Data CRC error\n",
1180 mmc_hostname(host->mmc));
1181 pr_err("%s: opcode 0x%.8x\n", __func__,
1182 data->mrq->cmd->opcode);
1183 pr_err("%s: blksz %d, blocks %d\n", __func__,
1184 data->blksz, data->blocks);
1185 data->error = -EILSEQ;
1186 }
San Mehat9d2bd732009-09-22 16:44:22 -07001187 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 /* CRC is optional for the bus test commands, not all
1189 * cards respond back with CRC. However controller
1190 * waits for the CRC and times out. Hence ignore the
1191 * data timeouts during the Bustest.
1192 */
1193 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1194 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301195 pr_err("%s: CMD%d: Data timeout\n",
1196 mmc_hostname(host->mmc),
1197 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301199 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 }
San Mehat9d2bd732009-09-22 16:44:22 -07001201 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001202 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001203 data->error = -EIO;
1204 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001205 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001206 data->error = -EIO;
1207 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001208 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001210 data->error = -EIO;
1211 }
San Mehat9d2bd732009-09-22 16:44:22 -07001212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001214 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 host->dummy_52_needed = 0;
1216}
San Mehat9d2bd732009-09-22 16:44:22 -07001217
1218static int
1219msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1220{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001222 uint32_t *ptr = (uint32_t *) buffer;
1223 int count = 0;
1224
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301225 if (remain % 4)
1226 remain = ((remain >> 2) + 1) << 2;
1227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1229
1230 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001231 ptr++;
1232 count += sizeof(uint32_t);
1233
1234 remain -= sizeof(uint32_t);
1235 if (remain == 0)
1236 break;
1237 }
1238 return count;
1239}
1240
1241static int
1242msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001244{
1245 void __iomem *base = host->base;
1246 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 while (readl_relaxed(base + MMCISTATUS) &
1250 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1251 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001252
San Mehat9d2bd732009-09-22 16:44:22 -07001253 count = min(remain, maxcnt);
1254
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301255 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1256 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001257 ptr += count;
1258 remain -= count;
1259
1260 if (remain == 0)
1261 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 }
1263 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001264
1265 return ptr - buffer;
1266}
1267
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001268/*
1269 * Copy up to a word (4 bytes) between a scatterlist
1270 * and a temporary bounce buffer when the word lies across
1271 * two pages. The temporary buffer can then be read to/
1272 * written from the FIFO once.
1273 */
1274static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1275{
1276 struct msmsdcc_pio_data *pio = &host->pio;
1277 unsigned int bytes_avail;
1278
1279 if (host->curr.data->flags & MMC_DATA_READ)
1280 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1281 pio->bounce_buf_len);
1282 else
1283 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1284 pio->bounce_buf_len);
1285
1286 while (pio->bounce_buf_len != 4) {
1287 if (!sg_miter_next(&pio->sg_miter))
1288 break;
1289 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1290 4 - pio->bounce_buf_len);
1291 if (host->curr.data->flags & MMC_DATA_READ)
1292 memcpy(pio->sg_miter.addr,
1293 &pio->bounce_buf[pio->bounce_buf_len],
1294 bytes_avail);
1295 else
1296 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1297 pio->sg_miter.addr, bytes_avail);
1298
1299 pio->sg_miter.consumed = bytes_avail;
1300 pio->bounce_buf_len += bytes_avail;
1301 }
1302}
1303
1304/*
1305 * Use sg_miter_next to return as many 4-byte aligned
1306 * chunks as possible, using a temporary 4 byte buffer
1307 * for alignment if necessary
1308 */
1309static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1310{
1311 struct msmsdcc_pio_data *pio = &host->pio;
1312 unsigned int length, rlength;
1313 char *buffer;
1314
1315 if (!sg_miter_next(&pio->sg_miter))
1316 return 0;
1317
1318 buffer = pio->sg_miter.addr;
1319 length = pio->sg_miter.length;
1320
1321 if (length < host->curr.xfer_remain) {
1322 rlength = round_down(length, 4);
1323 if (rlength) {
1324 /*
1325 * We have a 4-byte aligned chunk.
1326 * The rounding will be reflected by
1327 * a call to msmsdcc_sg_consumed
1328 */
1329 length = rlength;
1330 goto sg_next_end;
1331 }
1332 /*
1333 * We have a length less than 4 bytes. Check to
1334 * see if more buffer is available, and combine
1335 * to make 4 bytes if possible.
1336 */
1337 pio->bounce_buf_len = length;
1338 memset(pio->bounce_buf, 0, 4);
1339
1340 /*
1341 * On a read, get 4 bytes from FIFO, and distribute
1342 * (4-bouce_buf_len) bytes into consecutive
1343 * sgl buffers when msmsdcc_sg_consumed is called
1344 */
1345 if (host->curr.data->flags & MMC_DATA_READ) {
1346 buffer = pio->bounce_buf;
1347 length = 4;
1348 goto sg_next_end;
1349 } else {
1350 _msmsdcc_sg_consume_word(host);
1351 buffer = pio->bounce_buf;
1352 length = pio->bounce_buf_len;
1353 }
1354 }
1355
1356sg_next_end:
1357 *buf = buffer;
1358 *len = length;
1359 return 1;
1360}
1361
1362/*
1363 * Update sg_miter.consumed based on how many bytes were
1364 * consumed. If the bounce buffer was used to read from FIFO,
1365 * redistribute into sgls.
1366 */
1367static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1368 unsigned int length)
1369{
1370 struct msmsdcc_pio_data *pio = &host->pio;
1371
1372 if (host->curr.data->flags & MMC_DATA_READ) {
1373 if (length > pio->sg_miter.consumed)
1374 /*
1375 * consumed 4 bytes, but sgl
1376 * describes < 4 bytes
1377 */
1378 _msmsdcc_sg_consume_word(host);
1379 else
1380 pio->sg_miter.consumed = length;
1381 } else
1382 if (length < pio->sg_miter.consumed)
1383 pio->sg_miter.consumed = length;
1384}
1385
1386static void msmsdcc_sg_start(struct msmsdcc_host *host)
1387{
1388 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1389
1390 host->pio.bounce_buf_len = 0;
1391
1392 if (host->curr.data->flags & MMC_DATA_READ)
1393 sg_miter_flags |= SG_MITER_TO_SG;
1394 else
1395 sg_miter_flags |= SG_MITER_FROM_SG;
1396
1397 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1398 host->curr.data->sg_len, sg_miter_flags);
1399}
1400
1401static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1402{
1403 sg_miter_stop(&host->pio.sg_miter);
1404}
1405
San Mehat1cd22962010-02-03 12:59:29 -08001406static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001407msmsdcc_pio_irq(int irq, void *dev_id)
1408{
1409 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001411 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001412 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001413 unsigned int remain;
1414 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001415
Murali Palnati36448a42011-09-02 15:06:18 +05301416 spin_lock(&host->lock);
1417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301421 (MCI_IRQ_PIO)) == 0) {
1422 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301424 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425#if IRQ_DEBUG
1426 msmsdcc_print_status(host, "irq1-r", status);
1427#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001428 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001430 do {
1431 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1434 | MCI_RXDATAAVLBL)))
1435 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001436
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001437 if (!msmsdcc_sg_next(host, &buffer, &remain))
1438 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439
San Mehat9d2bd732009-09-22 16:44:22 -07001440 len = 0;
1441 if (status & MCI_RXACTIVE)
1442 len = msmsdcc_pio_read(host, buffer, remain);
1443 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001445
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301446 /* len might have aligned to 32bits above */
1447 if (len > remain)
1448 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001449
San Mehat9d2bd732009-09-22 16:44:22 -07001450 host->curr.xfer_remain -= len;
1451 host->curr.data_xfered += len;
1452 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001453 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 if (remain) /* Done with this page? */
1456 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001459 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001460
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001461 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001462 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1465 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1466 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1467 host->base + MMCIMASK0);
1468 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301469 /*
1470 * back to back write to MASK0 register don't need
1471 * synchronization delay.
1472 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1474 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1475 }
1476 mb();
1477 } else if (!host->curr.xfer_remain) {
1478 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1479 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1480 mb();
1481 }
San Mehat9d2bd732009-09-22 16:44:22 -07001482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001484
1485 return IRQ_HANDLED;
1486}
1487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488static void
1489msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1490
1491static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1492 struct mmc_data *data)
1493{
1494 u32 loop_cnt = 0;
1495
1496 /*
1497 * For read commands with data less than fifo size, it is possible to
1498 * get DATAEND first and RXDATA_AVAIL might be set later because of
1499 * synchronization delay through the asynchronous RX FIFO. Thus, for
1500 * such cases, even after DATAEND interrupt is received software
1501 * should poll for RXDATA_AVAIL until the requested data is read out
1502 * of FIFO. This change is needed to get around this abnormal but
1503 * sometimes expected behavior of SDCC3 controller.
1504 *
1505 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1506 * after the data is loaded into RX FIFO. This would amount to less
1507 * than a microsecond and thus looping for 1000 times is good enough
1508 * for that delay.
1509 */
1510 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1511 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1512 spin_unlock(&host->lock);
1513 msmsdcc_pio_irq(1, host);
1514 spin_lock(&host->lock);
1515 }
1516 }
1517 if (loop_cnt == 1000) {
1518 pr_info("%s: Timed out while polling for Rx Data\n",
1519 mmc_hostname(host->mmc));
1520 data->error = -ETIMEDOUT;
1521 msmsdcc_reset_and_restore(host);
1522 }
1523}
1524
San Mehat9d2bd732009-09-22 16:44:22 -07001525static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1526{
1527 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001528
1529 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1531 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1532 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1533 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301536 pr_debug("%s: CMD%d: Command timeout\n",
1537 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001538 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301540 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301541 pr_err("%s: CMD%d: Command CRC error\n",
1542 mmc_hostname(host->mmc), cmd->opcode);
1543 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001544 cmd->error = -EILSEQ;
1545 }
1546
1547 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 if (host->curr.data && host->dma.sg &&
1549 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001550 msm_dmov_stop_cmd(host->dma.channel,
1551 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552 else if (host->curr.data && host->sps.sg &&
1553 host->is_sps_mode){
1554 /* Stop current SPS transfer */
1555 msmsdcc_sps_exit_curr_xfer(host);
1556 }
San Mehat9d2bd732009-09-22 16:44:22 -07001557 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301558 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001559 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301560 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301561 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301562 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301563 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301565 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301567 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301568 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301569 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301570 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001571 if (host->dummy_52_needed)
1572 host->dummy_52_needed = 0;
1573 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301575 msmsdcc_request_end(host, cmd->mrq);
1576 }
1577 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301578 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1579 if (cmd->data->flags & MMC_DATA_READ)
1580 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1581 else
1582 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301583 } else if (cmd->data) {
1584 if (!(cmd->data->flags & MMC_DATA_READ))
1585 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001586 }
1587}
1588
San Mehat9d2bd732009-09-22 16:44:22 -07001589static irqreturn_t
1590msmsdcc_irq(int irq, void *dev_id)
1591{
1592 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001593 u32 status;
1594 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001596
1597 spin_lock(&host->lock);
1598
1599 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 struct mmc_command *cmd;
1601 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 if (timer) {
1604 timer = 0;
1605 msmsdcc_delay(host);
1606 }
San Mehat865c8062009-11-13 13:42:06 -08001607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 if (!host->clks_on) {
1609 pr_debug("%s: %s: SDIO async irq received\n",
1610 mmc_hostname(host->mmc), __func__);
1611 host->mmc->ios.clock = host->clk_rate;
1612 spin_unlock(&host->lock);
1613 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1614 spin_lock(&host->lock);
1615 if (host->plat->cfg_mpm_sdiowakeup &&
1616 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1617 wake_lock(&host->sdio_wlock);
1618 /* only ansyc interrupt can come when clocks are off */
1619 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301620 if (host->clk_rate <=
1621 msmsdcc_get_min_sup_clk_rate(host))
1622 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 }
1624
1625 status = readl_relaxed(host->base + MMCISTATUS);
1626
1627 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1628 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001629 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631#if IRQ_DEBUG
1632 msmsdcc_print_status(host, "irq0-r", status);
1633#endif
1634 status &= readl_relaxed(host->base + MMCIMASK0);
1635 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301636 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301637 if (host->clk_rate <=
1638 msmsdcc_get_min_sup_clk_rate(host))
1639 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640#if IRQ_DEBUG
1641 msmsdcc_print_status(host, "irq0-p", status);
1642#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1645 if (status & MCI_SDIOINTROPE) {
1646 if (host->sdcc_suspending)
1647 wake_lock(&host->sdio_suspend_wlock);
1648 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001649 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001651 data = host->curr.data;
1652
1653 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1655 MCI_CMDTIMEOUT)) {
1656 if (status & MCI_CMDTIMEOUT)
1657 pr_debug("%s: dummy CMD52 timeout\n",
1658 mmc_hostname(host->mmc));
1659 if (status & MCI_CMDCRCFAIL)
1660 pr_debug("%s: dummy CMD52 CRC failed\n",
1661 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001662 host->dummy_52_sent = 0;
1663 host->dummy_52_needed = 0;
1664 if (data) {
1665 msmsdcc_stop_data(host);
1666 msmsdcc_request_end(host, data->mrq);
1667 }
1668 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 spin_unlock(&host->lock);
1670 return IRQ_HANDLED;
1671 }
1672 break;
1673 }
1674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 /*
1676 * Check for proper command response
1677 */
1678 cmd = host->curr.cmd;
1679 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1680 MCI_CMDTIMEOUT | MCI_PROGDONE |
1681 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1682 msmsdcc_do_cmdirq(host, status);
1683 }
1684
Sathish Ambley081d7842011-11-29 11:19:41 -08001685 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 /* Check for data errors */
1687 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1688 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1689 msmsdcc_data_err(host, data, status);
1690 host->curr.data_xfered = 0;
1691 if (host->dma.sg && host->is_dma_mode)
1692 msm_dmov_stop_cmd(host->dma.channel,
1693 &host->dma.hdr, 0);
1694 else if (host->sps.sg && host->is_sps_mode) {
1695 /* Stop current SPS transfer */
1696 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301697 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 msmsdcc_reset_and_restore(host);
1699 if (host->curr.data)
1700 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301701 if (!data->stop || (host->curr.mrq->sbc
1702 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 timer |=
1704 msmsdcc_request_end(host,
1705 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301706 else if ((host->curr.mrq->sbc
1707 && data->error) ||
1708 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 msmsdcc_start_command(host,
1710 data->stop,
1711 0);
1712 timer = 1;
1713 }
1714 }
1715 }
1716
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301717 /* Check for prog done */
1718 if (host->curr.wait_for_auto_prog_done &&
1719 (status & MCI_PROGDONE))
1720 host->curr.got_auto_prog_done = 1;
1721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 /* Check for data done */
1723 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1724 host->curr.got_dataend = 1;
1725
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301726 if (host->curr.got_dataend &&
1727 (!host->curr.wait_for_auto_prog_done ||
1728 (host->curr.wait_for_auto_prog_done &&
1729 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 /*
1731 * If DMA is still in progress, we complete
1732 * via the completion handler
1733 */
1734 if (!host->dma.busy && !host->sps.busy) {
1735 /*
1736 * There appears to be an issue in the
1737 * controller where if you request a
1738 * small block transfer (< fifo size),
1739 * you may get your DATAEND/DATABLKEND
1740 * irq without the PIO data irq.
1741 *
1742 * Check to see if theres still data
1743 * to be read, and simulate a PIO irq.
1744 */
1745 if (data->flags & MMC_DATA_READ)
1746 msmsdcc_wait_for_rxdata(host,
1747 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 if (!data->error) {
1749 host->curr.data_xfered =
1750 host->curr.xfer_size;
1751 host->curr.xfer_remain -=
1752 host->curr.xfer_size;
1753 }
1754
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001755 if (!host->dummy_52_needed) {
1756 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301757 if (!data->stop ||
1758 (host->curr.mrq->sbc
1759 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001760 msmsdcc_request_end(
1761 host,
1762 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301763 else if ((host->curr.mrq->sbc
1764 && data->error) ||
1765 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001766 msmsdcc_start_command(
1767 host,
1768 data->stop, 0);
1769 timer = 1;
1770 }
1771 } else {
1772 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001774 &dummy52cmd,
1775 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 }
1777 }
1778 }
1779 }
1780
San Mehat9d2bd732009-09-22 16:44:22 -07001781 ret = 1;
1782 } while (status);
1783
1784 spin_unlock(&host->lock);
1785
San Mehat9d2bd732009-09-22 16:44:22 -07001786 return IRQ_RETVAL(ret);
1787}
1788
1789static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1791{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301792 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301794 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301795 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1796 else
1797 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 } else {
1799 msmsdcc_start_command(host, mrq->cmd, 0);
1800 }
1801}
1802
1803static void
San Mehat9d2bd732009-09-22 16:44:22 -07001804msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1805{
1806 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 /*
1810 * Get the SDIO AL client out of LPM.
1811 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001812 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 if (host->plat->is_sdio_al_client)
1814 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001815
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301816 /* check if sps pipe reset is pending? */
1817 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1818 msmsdcc_sps_pipes_reset_and_restore(host);
1819 host->sps.pipe_reset_pending = false;
1820 }
1821
San Mehat9d2bd732009-09-22 16:44:22 -07001822 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 WARN(host->curr.mrq, "Request in progress\n");
1824 WARN(!host->pwr, "SDCC power is turned off\n");
1825 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1826 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001827
1828 if (host->eject) {
1829 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1830 mrq->cmd->error = 0;
1831 mrq->data->bytes_xfered = mrq->data->blksz *
1832 mrq->data->blocks;
1833 } else
1834 mrq->cmd->error = -ENOMEDIUM;
1835
1836 spin_unlock_irqrestore(&host->lock, flags);
1837 mmc_request_done(mmc, mrq);
1838 return;
1839 }
1840
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301841 /*
1842 * Kick the software command timeout timer here.
1843 * Timer expires in 10 secs.
1844 */
1845 mod_timer(&host->req_tout_timer,
1846 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001847
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301848 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301849 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301850 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1851 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301852 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301854 else
1855 /*
1856 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1857 * write operations using CMD53 and CMD54.
1858 * Setting this bit with CMD53 would
1859 * automatically triggers PROG_DONE interrupt
1860 * without the need of sending dummy CMD52.
1861 */
1862 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301863 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1864 host->sdcc_version) {
1865 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 }
San Mehat9d2bd732009-09-22 16:44:22 -07001867 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301868
Pratibhasagar V00b94332011-10-18 14:57:27 +05301869 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301870 mrq->sbc->mrq = mrq;
1871 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301872 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301873 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301874 msmsdcc_start_command(host, mrq->sbc, 0);
1875 } else {
1876 msmsdcc_request_start(host, mrq);
1877 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301878 } else {
1879 msmsdcc_request_start(host, mrq);
1880 }
1881
San Mehat9d2bd732009-09-22 16:44:22 -07001882 spin_unlock_irqrestore(&host->lock, flags);
1883}
1884
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1886 int min_uV, int max_uV)
1887{
1888 int rc = 0;
1889
1890 if (vreg->set_voltage_sup) {
1891 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1892 if (rc) {
1893 pr_err("%s: regulator_set_voltage(%s) failed."
1894 " min_uV=%d, max_uV=%d, rc=%d\n",
1895 __func__, vreg->name, min_uV, max_uV, rc);
1896 }
1897 }
1898
1899 return rc;
1900}
1901
1902static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1903 int uA_load)
1904{
1905 int rc = 0;
1906
Krishna Kondafea60182011-11-01 16:01:34 -07001907 /* regulators that do not support regulator_set_voltage also
1908 do not support regulator_set_optimum_mode */
1909 if (vreg->set_voltage_sup) {
1910 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1911 if (rc < 0)
1912 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1913 "uA_load=%d) failed. rc=%d\n", __func__,
1914 vreg->name, uA_load, rc);
1915 else
1916 /* regulator_set_optimum_mode() can return non zero
1917 * value even for success case.
1918 */
1919 rc = 0;
1920 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921
1922 return rc;
1923}
1924
1925static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1926 struct device *dev)
1927{
1928 int rc = 0;
1929
1930 /* check if regulator is already initialized? */
1931 if (vreg->reg)
1932 goto out;
1933
1934 /* Get the regulator handle */
1935 vreg->reg = regulator_get(dev, vreg->name);
1936 if (IS_ERR(vreg->reg)) {
1937 rc = PTR_ERR(vreg->reg);
1938 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1939 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001940 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001942
1943 if (regulator_count_voltages(vreg->reg) > 0)
1944 vreg->set_voltage_sup = 1;
1945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946out:
1947 return rc;
1948}
1949
1950static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1951{
1952 if (vreg->reg)
1953 regulator_put(vreg->reg);
1954}
1955
1956/* This init function should be called only once for each SDCC slot */
1957static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1958{
1959 int rc = 0;
1960 struct msm_mmc_slot_reg_data *curr_slot;
1961 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1962 struct device *dev = mmc_dev(host->mmc);
1963
1964 curr_slot = host->plat->vreg_data;
1965 if (!curr_slot)
1966 goto out;
1967
1968 curr_vdd_reg = curr_slot->vdd_data;
1969 curr_vccq_reg = curr_slot->vccq_data;
1970 curr_vddp_reg = curr_slot->vddp_data;
1971
1972 if (is_init) {
1973 /*
1974 * Get the regulator handle from voltage regulator framework
1975 * and then try to set the voltage level for the regulator
1976 */
1977 if (curr_vdd_reg) {
1978 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1979 if (rc)
1980 goto out;
1981 }
1982 if (curr_vccq_reg) {
1983 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1984 if (rc)
1985 goto vdd_reg_deinit;
1986 }
1987 if (curr_vddp_reg) {
1988 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1989 if (rc)
1990 goto vccq_reg_deinit;
1991 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08001992 rc = msmsdcc_vreg_reset(host);
1993 if (rc)
1994 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
1995 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996 goto out;
1997 } else {
1998 /* Deregister all regulators from regulator framework */
1999 goto vddp_reg_deinit;
2000 }
2001vddp_reg_deinit:
2002 if (curr_vddp_reg)
2003 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2004vccq_reg_deinit:
2005 if (curr_vccq_reg)
2006 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2007vdd_reg_deinit:
2008 if (curr_vdd_reg)
2009 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2010out:
2011 return rc;
2012}
2013
2014static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2015{
2016 int rc = 0;
2017
Subhash Jadavanicc922692011-08-01 23:05:01 +05302018 /* Put regulator in HPM (high power mode) */
2019 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2020 if (rc < 0)
2021 goto out;
2022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 if (!vreg->is_enabled) {
2024 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302025 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2026 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 if (rc)
2028 goto out;
2029
2030 rc = regulator_enable(vreg->reg);
2031 if (rc) {
2032 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2033 __func__, vreg->name, rc);
2034 goto out;
2035 }
2036 vreg->is_enabled = true;
2037 }
2038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039out:
2040 return rc;
2041}
2042
2043static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2044{
2045 int rc = 0;
2046
2047 /* Never disable regulator marked as always_on */
2048 if (vreg->is_enabled && !vreg->always_on) {
2049 rc = regulator_disable(vreg->reg);
2050 if (rc) {
2051 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2052 __func__, vreg->name, rc);
2053 goto out;
2054 }
2055 vreg->is_enabled = false;
2056
2057 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2058 if (rc < 0)
2059 goto out;
2060
2061 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302062 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002063 if (rc)
2064 goto out;
2065 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2066 /* Put always_on regulator in LPM (low power mode) */
2067 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2068 if (rc < 0)
2069 goto out;
2070 }
2071out:
2072 return rc;
2073}
2074
2075static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2076{
2077 int rc = 0, i;
2078 struct msm_mmc_slot_reg_data *curr_slot;
2079 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2080 struct msm_mmc_reg_data *vreg_table[3];
2081
2082 curr_slot = host->plat->vreg_data;
2083 if (!curr_slot)
2084 goto out;
2085
2086 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2087 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2088 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2089
2090 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2091 if (vreg_table[i]) {
2092 if (enable)
2093 rc = msmsdcc_vreg_enable(vreg_table[i]);
2094 else
2095 rc = msmsdcc_vreg_disable(vreg_table[i]);
2096 if (rc)
2097 goto out;
2098 }
2099 }
2100out:
2101 return rc;
2102}
2103
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002104/*
2105 * Reset vreg by ensuring it is off during probe. A call
2106 * to enable vreg is needed to balance disable vreg
2107 */
2108static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2109{
2110 int rc;
2111
2112 rc = msmsdcc_setup_vreg(host, 1);
2113 if (rc)
2114 return rc;
2115 rc = msmsdcc_setup_vreg(host, 0);
2116 return rc;
2117}
2118
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302119static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120{
2121 int rc = 0;
2122
2123 if (host->plat->vreg_data) {
2124 struct msm_mmc_reg_data *vddp_reg =
2125 host->plat->vreg_data->vddp_data;
2126
2127 if (vddp_reg && vddp_reg->is_enabled)
2128 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2129 }
2130
2131 return rc;
2132}
2133
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302134static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2135{
2136 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2137 int rc = 0;
2138
2139 if (curr_slot && curr_slot->vddp_data) {
2140 rc = msmsdcc_set_vddp_level(host,
2141 curr_slot->vddp_data->low_vol_level);
2142
2143 if (rc)
2144 pr_err("%s: %s: failed to change vddp level to %d",
2145 mmc_hostname(host->mmc), __func__,
2146 curr_slot->vddp_data->low_vol_level);
2147 }
2148
2149 return rc;
2150}
2151
2152static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2153{
2154 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2155 int rc = 0;
2156
2157 if (curr_slot && curr_slot->vddp_data) {
2158 rc = msmsdcc_set_vddp_level(host,
2159 curr_slot->vddp_data->high_vol_level);
2160
2161 if (rc)
2162 pr_err("%s: %s: failed to change vddp level to %d",
2163 mmc_hostname(host->mmc), __func__,
2164 curr_slot->vddp_data->high_vol_level);
2165 }
2166
2167 return rc;
2168}
2169
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302170static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2171{
2172 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2173 int rc = 0;
2174
2175 if (curr_slot && curr_slot->vccq_data) {
2176 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2177 level, level);
2178 if (rc)
2179 pr_err("%s: %s: failed to change vccq level to %d",
2180 mmc_hostname(host->mmc), __func__, level);
2181 }
2182
2183 return rc;
2184}
2185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2187{
2188 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2189 return 1;
2190 return 0;
2191}
2192
2193static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2194{
2195 if (enable) {
2196 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2197 clk_enable(host->dfab_pclk);
2198 if (!IS_ERR(host->pclk))
2199 clk_enable(host->pclk);
2200 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302201 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302203 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 clk_disable(host->clk);
2205 if (!IS_ERR(host->pclk))
2206 clk_disable(host->pclk);
2207 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2208 clk_disable(host->dfab_pclk);
2209 }
2210}
2211
2212static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2213 unsigned int req_clk)
2214{
2215 unsigned int sel_clk = -1;
2216
2217 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2218 unsigned char cnt;
2219
2220 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2221 if (host->plat->sup_clk_table[cnt] > req_clk)
2222 break;
2223 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2224 sel_clk = host->plat->sup_clk_table[cnt];
2225 break;
2226 } else
2227 sel_clk = host->plat->sup_clk_table[cnt];
2228 }
2229 } else {
2230 if ((req_clk < host->plat->msmsdcc_fmax) &&
2231 (req_clk > host->plat->msmsdcc_fmid))
2232 sel_clk = host->plat->msmsdcc_fmid;
2233 else
2234 sel_clk = req_clk;
2235 }
2236
2237 return sel_clk;
2238}
2239
2240static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2241 struct msmsdcc_host *host)
2242{
2243 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2244 return host->plat->sup_clk_table[0];
2245 else
2246 return host->plat->msmsdcc_fmin;
2247}
2248
2249static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2250 struct msmsdcc_host *host)
2251{
2252 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2253 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2254 else
2255 return host->plat->msmsdcc_fmax;
2256}
2257
2258static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302259{
2260 struct msm_mmc_gpio_data *curr;
2261 int i, rc = 0;
2262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302264 for (i = 0; i < curr->size; i++) {
2265 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002266 if (curr->gpio[i].is_always_on &&
2267 curr->gpio[i].is_enabled)
2268 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302269 rc = gpio_request(curr->gpio[i].no,
2270 curr->gpio[i].name);
2271 if (rc) {
2272 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2273 mmc_hostname(host->mmc),
2274 curr->gpio[i].no,
2275 curr->gpio[i].name, rc);
2276 goto free_gpios;
2277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302279 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 if (curr->gpio[i].is_always_on)
2281 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302282 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302284 }
2285 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302287
2288free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302290 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 curr->gpio[i].is_enabled = false;
2292 }
2293out:
2294 return rc;
2295}
2296
2297static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2298{
2299 struct msm_mmc_pad_data *curr;
2300 int i;
2301
2302 curr = host->plat->pin_data->pad_data;
2303 for (i = 0; i < curr->drv->size; i++) {
2304 if (enable)
2305 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2306 curr->drv->on[i].val);
2307 else
2308 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2309 curr->drv->off[i].val);
2310 }
2311
2312 for (i = 0; i < curr->pull->size; i++) {
2313 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002314 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315 curr->pull->on[i].val);
2316 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002317 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002318 curr->pull->off[i].val);
2319 }
2320
2321 return 0;
2322}
2323
2324static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2325{
2326 int rc = 0;
2327
2328 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2329 return 0;
2330
2331 if (host->plat->pin_data->is_gpio)
2332 rc = msmsdcc_setup_gpio(host, enable);
2333 else
2334 rc = msmsdcc_setup_pad(host, enable);
2335
2336 if (!rc)
2337 host->plat->pin_data->cfg_sts = enable;
2338
2339 return rc;
2340}
2341
2342static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2343{
2344 unsigned int wakeup_irq;
2345
2346 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2347 host->plat->sdiowakeup_irq :
2348 host->core_irqres->start;
2349
2350 if (!host->irq_wake_enabled) {
2351 enable_irq_wake(wakeup_irq);
2352 host->irq_wake_enabled = true;
2353 }
2354}
2355
2356static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2357{
2358 unsigned int wakeup_irq;
2359
2360 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2361 host->plat->sdiowakeup_irq :
2362 host->core_irqres->start;
2363
2364 if (host->irq_wake_enabled) {
2365 disable_irq_wake(wakeup_irq);
2366 host->irq_wake_enabled = false;
2367 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302368}
2369
San Mehat9d2bd732009-09-22 16:44:22 -07002370static void
2371msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2372{
2373 struct msmsdcc_host *host = mmc_priv(mmc);
2374 u32 clk = 0, pwr = 0;
2375 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002376 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302380
San Mehat9d2bd732009-09-22 16:44:22 -07002381 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 spin_lock_irqsave(&host->lock, flags);
2383 if (!host->clks_on) {
2384 msmsdcc_setup_clocks(host, true);
2385 host->clks_on = 1;
2386 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2387 if (!host->plat->sdiowakeup_irq) {
2388 writel_relaxed(host->mci_irqenable,
2389 host->base + MMCIMASK0);
2390 mb();
2391 if (host->plat->cfg_mpm_sdiowakeup &&
2392 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2393 host->plat->cfg_mpm_sdiowakeup(
2394 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2395 msmsdcc_disable_irq_wake(host);
2396 } else if (!(mmc->pm_flags &
2397 MMC_PM_WAKE_SDIO_IRQ)) {
2398 writel_relaxed(host->mci_irqenable,
2399 host->base + MMCIMASK0);
2400 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302401 } else {
2402 writel_relaxed(host->mci_irqenable,
2403 host->base + MMCIMASK0);
2404 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405 }
San Mehat9d2bd732009-09-22 16:44:22 -07002406 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002407 spin_unlock_irqrestore(&host->lock, flags);
2408
2409 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2410 /*
2411 * For DDR50 mode, controller needs clock rate to be
2412 * double than what is required on the SD card CLK pin.
2413 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302414 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415 /*
2416 * Make sure that we don't double the clock if
2417 * doubled clock rate is already set
2418 */
2419 if (!host->ddr_doubled_clk_rate ||
2420 (host->ddr_doubled_clk_rate &&
2421 (host->ddr_doubled_clk_rate != ios->clock))) {
2422 host->ddr_doubled_clk_rate =
2423 msmsdcc_get_sup_clk_rate(
2424 host, (ios->clock * 2));
2425 clock = host->ddr_doubled_clk_rate;
2426 }
2427 } else {
2428 host->ddr_doubled_clk_rate = 0;
2429 }
2430
2431 if (clock != host->clk_rate) {
2432 rc = clk_set_rate(host->clk, clock);
2433 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302434 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435 mmc_hostname(mmc), clock);
2436 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302437 host->reg_write_delay =
2438 (1 + ((3 * USEC_PER_SEC) /
2439 (host->clk_rate ? host->clk_rate :
2440 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002441 }
2442 /*
2443 * give atleast 2 MCLK cycles delay for clocks
2444 * and SDCC core to stabilize
2445 */
2446 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002447 clk |= MCI_CLK_ENABLE;
2448 }
2449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 if (ios->bus_width == MMC_BUS_WIDTH_8)
2451 clk |= MCI_CLK_WIDEBUS_8;
2452 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2453 clk |= MCI_CLK_WIDEBUS_4;
2454 else
2455 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 if (msmsdcc_is_pwrsave(host))
2458 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 host->tuning_needed = 0;
2463 /*
2464 * Select the controller timing mode according
2465 * to current bus speed mode
2466 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302467 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2468 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002469 clk |= (4 << 14);
2470 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302471 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 clk |= (3 << 14);
2473 } else {
2474 clk |= (2 << 14); /* feedback clock */
2475 }
2476
2477 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2478 clk |= (2 << 23);
2479
Subhash Jadavani00083572012-02-15 16:18:01 +05302480 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2481 if (!ios->vdd)
2482 host->io_pad_pwr_switch = 0;
2483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 if (host->io_pad_pwr_switch)
2485 clk |= IO_PAD_PWR_SWITCH;
2486
2487 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002488 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2490 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002491
2492 switch (ios->power_mode) {
2493 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2495 if (!host->sdcc_irq_disabled) {
2496 if (host->plat->cfg_mpm_sdiowakeup)
2497 host->plat->cfg_mpm_sdiowakeup(
2498 mmc_dev(mmc), SDC_DAT1_DISABLE);
2499 disable_irq(host->core_irqres->start);
2500 host->sdcc_irq_disabled = 1;
2501 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302502 /*
2503 * As VDD pad rail is always on, set low voltage for VDD
2504 * pad rail when slot is unused (when card is not present
2505 * or during system suspend).
2506 */
2507 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002509 break;
2510 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302511 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002512 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 if (host->sdcc_irq_disabled) {
2514 if (host->plat->cfg_mpm_sdiowakeup)
2515 host->plat->cfg_mpm_sdiowakeup(
2516 mmc_dev(mmc), SDC_DAT1_ENABLE);
2517 enable_irq(host->core_irqres->start);
2518 host->sdcc_irq_disabled = 0;
2519 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302520 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002521 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002522 break;
2523 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002524 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002525 pwr |= MCI_PWR_ON;
2526 break;
2527 }
2528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 spin_lock_irqsave(&host->lock, flags);
2530 if (!host->clks_on) {
2531 /* force the clocks to be on */
2532 msmsdcc_setup_clocks(host, true);
2533 /*
2534 * give atleast 2 MCLK cycles delay for clocks
2535 * and SDCC core to stabilize
2536 */
2537 msmsdcc_delay(host);
2538 }
2539 writel_relaxed(clk, host->base + MMCICLOCK);
2540 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002541
2542 if (host->pwr != pwr) {
2543 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302545 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002546 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 if (!host->clks_on) {
2548 /* force the clocks to be off */
2549 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 }
2551
2552 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2553 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2554 if (!host->plat->sdiowakeup_irq) {
2555 writel_relaxed(MCI_SDIOINTMASK,
2556 host->base + MMCIMASK0);
2557 mb();
2558 if (host->plat->cfg_mpm_sdiowakeup &&
2559 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2560 host->plat->cfg_mpm_sdiowakeup(
2561 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2562 msmsdcc_enable_irq_wake(host);
2563 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2564 writel_relaxed(0, host->base + MMCIMASK0);
2565 } else {
2566 writel_relaxed(MCI_SDIOINTMASK,
2567 host->base + MMCIMASK0);
2568 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302569 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570 }
2571 msmsdcc_setup_clocks(host, false);
2572 host->clks_on = 0;
2573 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302574
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302575 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302576 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302577 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302578
San Mehat4adbbcc2009-11-08 13:00:37 -08002579 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002580}
2581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2583{
2584 struct msmsdcc_host *host = mmc_priv(mmc);
2585 u32 clk;
2586
2587 clk = readl_relaxed(host->base + MMCICLOCK);
2588 pr_debug("Changing to pwr_save=%d", pwrsave);
2589 if (pwrsave && msmsdcc_is_pwrsave(host))
2590 clk |= MCI_CLK_PWRSAVE;
2591 else
2592 clk &= ~MCI_CLK_PWRSAVE;
2593 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302594 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595
2596 return 0;
2597}
2598
2599static int msmsdcc_get_ro(struct mmc_host *mmc)
2600{
2601 int status = -ENOSYS;
2602 struct msmsdcc_host *host = mmc_priv(mmc);
2603
2604 if (host->plat->wpswitch) {
2605 status = host->plat->wpswitch(mmc_dev(mmc));
2606 } else if (host->plat->wpswitch_gpio) {
2607 status = gpio_request(host->plat->wpswitch_gpio,
2608 "SD_WP_Switch");
2609 if (status) {
2610 pr_err("%s: %s: Failed to request GPIO %d\n",
2611 mmc_hostname(mmc), __func__,
2612 host->plat->wpswitch_gpio);
2613 } else {
2614 status = gpio_direction_input(
2615 host->plat->wpswitch_gpio);
2616 if (!status) {
2617 /*
2618 * Wait for atleast 300ms as debounce
2619 * time for GPIO input to stabilize.
2620 */
2621 msleep(300);
2622 status = gpio_get_value_cansleep(
2623 host->plat->wpswitch_gpio);
2624 status ^= !host->plat->wpswitch_polarity;
2625 }
2626 gpio_free(host->plat->wpswitch_gpio);
2627 }
2628 }
2629
2630 if (status < 0)
2631 status = -ENOSYS;
2632 pr_debug("%s: Card read-only status %d\n", __func__, status);
2633
2634 return status;
2635}
2636
2637#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002638static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2639{
2640 struct msmsdcc_host *host = mmc_priv(mmc);
2641 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002642
2643 if (enable) {
2644 spin_lock_irqsave(&host->lock, flags);
2645 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2646 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2647 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2648 spin_unlock_irqrestore(&host->lock, flags);
2649 } else {
2650 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2651 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2652 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2653 }
2654 mb();
2655}
2656#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2657
2658#ifdef CONFIG_PM_RUNTIME
2659static int msmsdcc_enable(struct mmc_host *mmc)
2660{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302661 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302663 struct msmsdcc_host *host = mmc_priv(mmc);
2664
2665 msmsdcc_pm_qos_update_latency(host, 1);
2666
2667 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2668 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002669
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302670 if (dev->power.runtime_status == RPM_SUSPENDING) {
2671 if (mmc->suspend_task == current) {
2672 pm_runtime_get_noresume(dev);
2673 goto out;
2674 }
2675 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302677 rc = pm_runtime_get_sync(dev);
2678
2679 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002680 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2681 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302682 return rc;
2683 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302684
2685 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302686out:
2687 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688}
2689
2690static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2691{
2692 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302693 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302695 msmsdcc_pm_qos_update_latency(host, 0);
2696
2697 if (mmc->card && mmc_card_sdio(mmc->card))
2698 return 0;
2699
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302700 if (host->plat->disable_runtime_pm)
2701 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702
2703 rc = pm_runtime_put_sync(mmc->parent);
2704
2705 if (rc < 0)
2706 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2707 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302708 else
2709 host->is_resumed = false;
2710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711 return rc;
2712}
2713#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302714static int msmsdcc_enable(struct mmc_host *mmc)
2715{
2716 struct msmsdcc_host *host = mmc_priv(mmc);
2717 unsigned long flags;
2718
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302719 msmsdcc_pm_qos_update_latency(host, 1);
2720
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302721 spin_lock_irqsave(&host->lock, flags);
2722 if (!host->clks_on) {
2723 msmsdcc_setup_clocks(host, true);
2724 host->clks_on = 1;
2725 }
2726 spin_unlock_irqrestore(&host->lock, flags);
2727
2728 return 0;
2729}
2730
2731static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2732{
2733 struct msmsdcc_host *host = mmc_priv(mmc);
2734 unsigned long flags;
2735
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302736 msmsdcc_pm_qos_update_latency(host, 0);
2737
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302738 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302739 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302740
2741 spin_lock_irqsave(&host->lock, flags);
2742 if (host->clks_on) {
2743 msmsdcc_setup_clocks(host, false);
2744 host->clks_on = 0;
2745 }
2746 spin_unlock_irqrestore(&host->lock, flags);
2747
2748 return 0;
2749}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750#endif
2751
2752static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2753 struct mmc_ios *ios)
2754{
2755 struct msmsdcc_host *host = mmc_priv(mmc);
2756 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302757 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758
Subhash Jadavani00083572012-02-15 16:18:01 +05302759 spin_lock_irqsave(&host->lock, flags);
2760 host->io_pad_pwr_switch = 0;
2761 spin_unlock_irqrestore(&host->lock, flags);
2762
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302763 /*
2764 * For eMMC cards, VccQ voltage range must be changed
2765 * only if it operates in HS200 SDR 1.2V mode or in
2766 * DDR 1.2V mode.
2767 */
2768 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2769 rc = msmsdcc_set_vccq_vol(host, 1200000);
2770 goto out;
2771 }
2772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2774 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302775 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002776 goto out;
2777 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2778 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302779 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 goto out;
2781 }
San Mehat9d2bd732009-09-22 16:44:22 -07002782
2783 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 /*
2785 * If we are here means voltage switch from high voltage to
2786 * low voltage is required
2787 */
2788
2789 /*
2790 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2791 * register until they become all zeros.
2792 */
2793 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302794 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2796 mmc_hostname(mmc), __func__);
2797 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002798 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799
2800 /* Stop SD CLK output. */
2801 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2802 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302803 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002804 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805
2806 /*
2807 * Switch VDDPX from high voltage to low voltage
2808 * to change the VDD of the SD IO pads.
2809 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302810 rc = msmsdcc_set_vddp_low_vol(host);
2811 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813
2814 spin_lock_irqsave(&host->lock, flags);
2815 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2816 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302817 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818 host->io_pad_pwr_switch = 1;
2819 spin_unlock_irqrestore(&host->lock, flags);
2820
2821 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2822 usleep_range(5000, 5500);
2823
2824 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302825 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2827 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302828 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 spin_unlock_irqrestore(&host->lock, flags);
2830
2831 /*
2832 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2833 * don't become all ones within 1 ms then a Voltage Switch
2834 * sequence has failed and a power cycle to the card is required.
2835 * Otherwise Voltage Switch sequence is completed successfully.
2836 */
2837 usleep_range(1000, 1500);
2838
2839 spin_lock_irqsave(&host->lock, flags);
2840 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2841 != (0xF << 1)) {
2842 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2843 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302844 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 goto out_unlock;
2846 }
2847
2848out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302849 /* Enable PWRSAVE */
2850 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2851 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 spin_unlock_irqrestore(&host->lock, flags);
2853out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302854 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855}
2856
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302857static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002859 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860
2861 /* Program the MCLK value to MCLK_FREQ bit field */
2862 if (host->clk_rate <= 112000000)
2863 mclk_freq = 0;
2864 else if (host->clk_rate <= 125000000)
2865 mclk_freq = 1;
2866 else if (host->clk_rate <= 137000000)
2867 mclk_freq = 2;
2868 else if (host->clk_rate <= 150000000)
2869 mclk_freq = 3;
2870 else if (host->clk_rate <= 162000000)
2871 mclk_freq = 4;
2872 else if (host->clk_rate <= 175000000)
2873 mclk_freq = 5;
2874 else if (host->clk_rate <= 187000000)
2875 mclk_freq = 6;
2876 else if (host->clk_rate <= 200000000)
2877 mclk_freq = 7;
2878
2879 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2880 & ~(7 << 24)) | (mclk_freq << 24)),
2881 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882}
2883
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302884/* Initialize the DLL (Programmable Delay Line ) */
2885static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002886{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002887 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302888 unsigned long flags;
2889 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002890
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302891 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 /*
2893 * Make sure that clock is always enabled when DLL
2894 * tuning is in progress. Keeping PWRSAVE ON may
2895 * turn off the clock. So let's disable the PWRSAVE
2896 * here and re-enable it once tuning is completed.
2897 */
2898 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2899 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302900
2901 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2902 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2903 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2904
2905 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2906 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2907 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2908
2909 msmsdcc_cm_sdc4_dll_set_freq(host);
2910
2911 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2912 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2913 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2914
2915 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2916 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2917 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2918
2919 /* Set DLL_EN bit to 1. */
2920 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2921 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2922
2923 /* Set CK_OUT_EN bit to 1. */
2924 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2925 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2926
2927 wait_cnt = 50;
2928 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2929 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2930 /* max. wait for 50us sec for LOCK bit to be set */
2931 if (--wait_cnt == 0) {
2932 pr_err("%s: %s: DLL failed to LOCK\n",
2933 mmc_hostname(host->mmc), __func__);
2934 rc = -ETIMEDOUT;
2935 goto out;
2936 }
2937 /* wait for 1us before polling again */
2938 udelay(1);
2939 }
2940
2941out:
2942 /* re-enable PWRSAVE */
2943 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2944 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2945 spin_unlock_irqrestore(&host->lock, flags);
2946
2947 return rc;
2948}
2949
2950static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2951 u8 poll)
2952{
2953 int rc = 0;
2954 u32 wait_cnt = 50;
2955 u8 ck_out_en = 0;
2956
2957 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2958 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2959 MCI_CK_OUT_EN);
2960
2961 while (ck_out_en != poll) {
2962 if (--wait_cnt == 0) {
2963 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2964 mmc_hostname(host->mmc), __func__, poll);
2965 rc = -ETIMEDOUT;
2966 goto out;
2967 }
2968 udelay(1);
2969
2970 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2971 MCI_CK_OUT_EN);
2972 }
2973out:
2974 return rc;
2975}
2976
2977/*
2978 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2979 * calibration sequence. This function should be called before
2980 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2981 * commands (CMD17/CMD18).
2982 *
2983 * This function gets called when host spinlock acquired.
2984 */
2985static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2986{
2987 int rc = 0;
2988 u32 config;
2989
2990 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2991 config |= MCI_CDR_EN;
2992 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2993 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2994
2995 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2996 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2997 if (rc)
2998 goto err_out;
2999
3000 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3001 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3002 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3003
3004 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3005 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3006 if (rc)
3007 goto err_out;
3008
3009 goto out;
3010
3011err_out:
3012 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3013out:
3014 return rc;
3015}
3016
3017static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3018 u8 phase)
3019{
3020 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303021 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3022 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3023 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303024 unsigned long flags;
3025 u32 config;
3026
3027 spin_lock_irqsave(&host->lock, flags);
3028
3029 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3030 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3031 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3032 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3033
3034 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3035 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3036 if (rc)
3037 goto err_out;
3038
3039 /*
3040 * Write the selected DLL clock output phase (0 ... 15)
3041 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3042 */
3043 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3044 & ~(0xF << 20))
3045 | (grey_coded_phase_table[phase] << 20)),
3046 host->base + MCI_DLL_CONFIG);
3047
3048 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3049 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3050 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3051
3052 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3053 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3054 if (rc)
3055 goto err_out;
3056
3057 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3058 config |= MCI_CDR_EN;
3059 config &= ~MCI_CDR_EXT_EN;
3060 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3061 goto out;
3062
3063err_out:
3064 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3065 mmc_hostname(host->mmc), __func__, phase);
3066out:
3067 spin_unlock_irqrestore(&host->lock, flags);
3068 return rc;
3069}
3070
3071/*
3072 * Find out the greatest range of consecuitive selected
3073 * DLL clock output phases that can be used as sampling
3074 * setting for SD3.0 UHS-I card read operation (in SDR104
3075 * timing mode) or for eMMC4.5 card read operation (in HS200
3076 * timing mode).
3077 * Select the 3/4 of the range and configure the DLL with the
3078 * selected DLL clock output phase.
3079*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303080static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303081 u8 *phase_table, u8 total_phases)
3082{
Subhash Jadavani34187042012-03-02 10:59:49 +05303083 int ret;
3084 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303085 u8 phases_per_row[16] = {0};
3086 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303087 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3088 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303089
Subhash Jadavani34187042012-03-02 10:59:49 +05303090 if (total_phases > 16) {
3091 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3092 mmc_hostname(host->mmc), __func__, total_phases);
3093 return -EINVAL;
3094 }
3095
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303096 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303097 ranges[row_index][col_index] = phase_table[cnt];
3098 phases_per_row[row_index] += 1;
3099 col_index++;
3100
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303101 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303102 continue;
3103 /* check if next phase in phase_table is consecutive or not */
3104 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3105 row_index++;
3106 col_index = 0;
3107 }
3108 }
3109
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303110 /* Check if phase-0 is present in first valid window? */
3111 if (!ranges[0][0]) {
3112 phase_0_found = true;
3113 phase_0_raw_index = 0;
3114 /* Check if cycle exist between 2 valid windows */
3115 for (cnt = 1; cnt <= row_index; cnt++) {
3116 if (phases_per_row[cnt]) {
3117 for (i = 0; i <= phases_per_row[cnt]; i++) {
3118 if (ranges[cnt][i] == 15) {
3119 phase_15_found = true;
3120 phase_15_raw_index = cnt;
3121 break;
3122 }
3123 }
3124 }
3125 }
3126 }
3127
3128 /* If 2 valid windows form cycle then merge them as single window */
3129 if (phase_0_found && phase_15_found) {
3130 /* number of phases in raw where phase 0 is present */
3131 u8 phases_0 = phases_per_row[phase_0_raw_index];
3132 /* number of phases in raw where phase 15 is present */
3133 u8 phases_15 = phases_per_row[phase_15_raw_index];
3134
3135 cnt = 0;
3136 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3137 ranges[phase_15_raw_index][i] =
3138 ranges[phase_0_raw_index][cnt];
3139 cnt++;
3140 }
3141 phases_per_row[phase_0_raw_index] = 0;
3142 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3143 }
3144
3145 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303146 if (phases_per_row[cnt] > curr_max) {
3147 curr_max = phases_per_row[cnt];
3148 selected_row_index = cnt;
3149 }
3150 }
3151
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303152 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303153 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303154
3155 return ret;
3156}
3157
Girish K Sa3f41692012-02-29 12:00:09 +05303158static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303159{
3160 int rc = 0;
3161 struct msmsdcc_host *host = mmc_priv(mmc);
3162 unsigned long flags;
3163 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303164 const u32 *tuning_block_pattern = tuning_block_64;
3165 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303166
3167 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3168
3169 /* Tuning is only required for SDR104 modes */
3170 if (!host->tuning_needed) {
3171 rc = 0;
3172 goto exit;
3173 }
3174
3175 spin_lock_irqsave(&host->lock, flags);
3176 WARN(!host->pwr, "SDCC power is turned off\n");
3177 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3178 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3179
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303180 host->tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303181 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303182 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3183 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3184 tuning_block_pattern = tuning_block_128;
3185 size = sizeof(tuning_block_128);
3186 }
3187
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303188 spin_unlock_irqrestore(&host->lock, flags);
3189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 /* first of all reset the tuning block */
3191 rc = msmsdcc_init_cm_sdc4_dll(host);
3192 if (rc)
3193 goto out;
3194
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303195 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196 if (!data_buf) {
3197 rc = -ENOMEM;
3198 goto out;
3199 }
3200
3201 phase = 0;
3202 do {
3203 struct mmc_command cmd = {0};
3204 struct mmc_data data = {0};
3205 struct mmc_request mrq = {
3206 .cmd = &cmd,
3207 .data = &data
3208 };
3209 struct scatterlist sg;
3210
3211 /* set the phase in delay line hw block */
3212 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3213 if (rc)
3214 goto kfree;
3215
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303216 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3218
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303219 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220 data.blocks = 1;
3221 data.flags = MMC_DATA_READ;
3222 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3223
3224 data.sg = &sg;
3225 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303226 sg_init_one(&sg, data_buf, size);
3227 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003228 mmc_wait_for_req(mmc, &mrq);
3229
3230 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303231 !memcmp(data_buf, tuning_block_pattern, size)) {
3232 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003233 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303234 pr_debug("%s: %s: found good phase = %d\n",
3235 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003236 }
3237 } while (++phase < 16);
3238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003239 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303240 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303241 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303242 if (rc < 0)
3243 goto kfree;
3244 else
3245 phase = (u8)rc;
3246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003247 /*
3248 * Finally set the selected phase in delay
3249 * line hw block.
3250 */
3251 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3252 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303253 goto kfree;
3254 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3255 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256 } else {
3257 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303258 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303260 msmsdcc_dump_sdcc_state(host);
3261 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263
3264kfree:
3265 kfree(data_buf);
3266out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303267 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303268 msmsdcc_delay(host);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303269 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303270 spin_unlock_irqrestore(&host->lock, flags);
3271exit:
3272 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003274}
3275
3276static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 .enable = msmsdcc_enable,
3278 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003279 .request = msmsdcc_request,
3280 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003281 .get_ro = msmsdcc_get_ro,
3282#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003283 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003284#endif
3285 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3286 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003287};
3288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289static unsigned int
3290msmsdcc_slot_status(struct msmsdcc_host *host)
3291{
3292 int status;
3293 unsigned int gpio_no = host->plat->status_gpio;
3294
3295 status = gpio_request(gpio_no, "SD_HW_Detect");
3296 if (status) {
3297 pr_err("%s: %s: Failed to request GPIO %d\n",
3298 mmc_hostname(host->mmc), __func__, gpio_no);
3299 } else {
3300 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003301 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003302 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003303 if (host->plat->is_status_gpio_active_low)
3304 status = !status;
3305 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306 gpio_free(gpio_no);
3307 }
3308 return status;
3309}
3310
San Mehat9d2bd732009-09-22 16:44:22 -07003311static void
3312msmsdcc_check_status(unsigned long data)
3313{
3314 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3315 unsigned int status;
3316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003318 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003319 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003320 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003321 status = msmsdcc_slot_status(host);
3322
Krishna Konda941604a2012-01-10 17:46:34 -08003323 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003326 if (host->plat->status)
3327 pr_info("%s: Slot status change detected "
3328 "(%d -> %d)\n",
3329 mmc_hostname(host->mmc),
3330 host->oldstat, status);
3331 else if (host->plat->is_status_gpio_active_low)
3332 pr_info("%s: Slot status change detected "
3333 "(%d -> %d) and the card detect GPIO"
3334 " is ACTIVE_LOW\n",
3335 mmc_hostname(host->mmc),
3336 host->oldstat, status);
3337 else
3338 pr_info("%s: Slot status change detected "
3339 "(%d -> %d) and the card detect GPIO"
3340 " is ACTIVE_HIGH\n",
3341 mmc_hostname(host->mmc),
3342 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003343 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 }
3345 host->oldstat = status;
3346 } else {
3347 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003348 }
San Mehat9d2bd732009-09-22 16:44:22 -07003349}
3350
3351static irqreturn_t
3352msmsdcc_platform_status_irq(int irq, void *dev_id)
3353{
3354 struct msmsdcc_host *host = dev_id;
3355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003356 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003357 msmsdcc_check_status((unsigned long) host);
3358 return IRQ_HANDLED;
3359}
3360
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361static irqreturn_t
3362msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3363{
3364 struct msmsdcc_host *host = dev_id;
3365
3366 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3367 spin_lock(&host->lock);
3368 if (!host->sdio_irq_disabled) {
3369 disable_irq_nosync(irq);
3370 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3371 wake_lock(&host->sdio_wlock);
3372 msmsdcc_disable_irq_wake(host);
3373 }
3374 host->sdio_irq_disabled = 1;
3375 }
3376 if (host->plat->is_sdio_al_client) {
3377 if (!host->clks_on) {
3378 msmsdcc_setup_clocks(host, true);
3379 host->clks_on = 1;
3380 }
3381 if (host->sdcc_irq_disabled) {
3382 writel_relaxed(host->mci_irqenable,
3383 host->base + MMCIMASK0);
3384 mb();
3385 enable_irq(host->core_irqres->start);
3386 host->sdcc_irq_disabled = 0;
3387 }
3388 wake_lock(&host->sdio_wlock);
3389 }
3390 spin_unlock(&host->lock);
3391
3392 return IRQ_HANDLED;
3393}
3394
San Mehat9d2bd732009-09-22 16:44:22 -07003395static void
3396msmsdcc_status_notify_cb(int card_present, void *dev_id)
3397{
3398 struct msmsdcc_host *host = dev_id;
3399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003401 card_present);
3402 msmsdcc_check_status((unsigned long) host);
3403}
3404
San Mehat9d2bd732009-09-22 16:44:22 -07003405static int
3406msmsdcc_init_dma(struct msmsdcc_host *host)
3407{
3408 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3409 host->dma.host = host;
3410 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003411 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003412
3413 if (!host->dmares)
3414 return -ENODEV;
3415
3416 host->dma.nc = dma_alloc_coherent(NULL,
3417 sizeof(struct msmsdcc_nc_dmadata),
3418 &host->dma.nc_busaddr,
3419 GFP_KERNEL);
3420 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003421 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003422 return -ENOMEM;
3423 }
3424 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3425 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3426 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3427 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3428 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003429 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003430
3431 return 0;
3432}
3433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003434#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3435/**
3436 * Allocate and Connect a SDCC peripheral's SPS endpoint
3437 *
3438 * This function allocates endpoint context and
3439 * connect it with memory endpoint by calling
3440 * appropriate SPS driver APIs.
3441 *
3442 * Also registers a SPS callback function with
3443 * SPS driver
3444 *
3445 * This function should only be called once typically
3446 * during driver probe.
3447 *
3448 * @host - Pointer to sdcc host structure
3449 * @ep - Pointer to sps endpoint data structure
3450 * @is_produce - 1 means Producer endpoint
3451 * 0 means Consumer endpoint
3452 *
3453 * @return - 0 if successful else negative value.
3454 *
3455 */
3456static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3457 struct msmsdcc_sps_ep_conn_data *ep,
3458 bool is_producer)
3459{
3460 int rc = 0;
3461 struct sps_pipe *sps_pipe_handle;
3462 struct sps_connect *sps_config = &ep->config;
3463 struct sps_register_event *sps_event = &ep->event;
3464
3465 /* Allocate endpoint context */
3466 sps_pipe_handle = sps_alloc_endpoint();
3467 if (!sps_pipe_handle) {
3468 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3469 mmc_hostname(host->mmc), is_producer);
3470 rc = -ENOMEM;
3471 goto out;
3472 }
3473
3474 /* Get default connection configuration for an endpoint */
3475 rc = sps_get_config(sps_pipe_handle, sps_config);
3476 if (rc) {
3477 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3478 " rc=%d", mmc_hostname(host->mmc),
3479 (u32)sps_pipe_handle, rc);
3480 goto get_config_err;
3481 }
3482
3483 /* Modify the default connection configuration */
3484 if (is_producer) {
3485 /*
3486 * For SDCC producer transfer, source should be
3487 * SDCC peripheral where as destination should
3488 * be system memory.
3489 */
3490 sps_config->source = host->sps.bam_handle;
3491 sps_config->destination = SPS_DEV_HANDLE_MEM;
3492 /* Producer pipe will handle this connection */
3493 sps_config->mode = SPS_MODE_SRC;
3494 sps_config->options =
3495 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3496 } else {
3497 /*
3498 * For SDCC consumer transfer, source should be
3499 * system memory where as destination should
3500 * SDCC peripheral
3501 */
3502 sps_config->source = SPS_DEV_HANDLE_MEM;
3503 sps_config->destination = host->sps.bam_handle;
3504 sps_config->mode = SPS_MODE_DEST;
3505 sps_config->options =
3506 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3507 }
3508
3509 /* Producer pipe index */
3510 sps_config->src_pipe_index = host->sps.src_pipe_index;
3511 /* Consumer pipe index */
3512 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3513 /*
3514 * This event thresold value is only significant for BAM-to-BAM
3515 * transfer. It's ignored for BAM-to-System mode transfer.
3516 */
3517 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303518
3519 /* Allocate maximum descriptor fifo size */
3520 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3521 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3523 sps_config->desc.size,
3524 &sps_config->desc.phys_base,
3525 GFP_KERNEL);
3526
Pratibhasagar V00b94332011-10-18 14:57:27 +05303527 if (!sps_config->desc.base) {
3528 rc = -ENOMEM;
3529 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3530 , mmc_hostname(host->mmc));
3531 goto get_config_err;
3532 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003533 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3534
3535 /* Establish connection between peripheral and memory endpoint */
3536 rc = sps_connect(sps_pipe_handle, sps_config);
3537 if (rc) {
3538 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3539 " rc=%d", mmc_hostname(host->mmc),
3540 (u32)sps_pipe_handle, rc);
3541 goto sps_connect_err;
3542 }
3543
3544 sps_event->mode = SPS_TRIGGER_CALLBACK;
3545 sps_event->options = SPS_O_EOT;
3546 sps_event->callback = msmsdcc_sps_complete_cb;
3547 sps_event->xfer_done = NULL;
3548 sps_event->user = (void *)host;
3549
3550 /* Register callback event for EOT (End of transfer) event. */
3551 rc = sps_register_event(sps_pipe_handle, sps_event);
3552 if (rc) {
3553 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3554 " rc=%d", mmc_hostname(host->mmc),
3555 (u32)sps_pipe_handle, rc);
3556 goto reg_event_err;
3557 }
3558 /* Now save the sps pipe handle */
3559 ep->pipe_handle = sps_pipe_handle;
3560 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3561 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3562 __func__, is_producer ? "READ" : "WRITE",
3563 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3564 goto out;
3565
3566reg_event_err:
3567 sps_disconnect(sps_pipe_handle);
3568sps_connect_err:
3569 dma_free_coherent(mmc_dev(host->mmc),
3570 sps_config->desc.size,
3571 sps_config->desc.base,
3572 sps_config->desc.phys_base);
3573get_config_err:
3574 sps_free_endpoint(sps_pipe_handle);
3575out:
3576 return rc;
3577}
3578
3579/**
3580 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3581 *
3582 * This function disconnect endpoint and deallocates
3583 * endpoint context.
3584 *
3585 * This function should only be called once typically
3586 * during driver remove.
3587 *
3588 * @host - Pointer to sdcc host structure
3589 * @ep - Pointer to sps endpoint data structure
3590 *
3591 */
3592static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3593 struct msmsdcc_sps_ep_conn_data *ep)
3594{
3595 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3596 struct sps_connect *sps_config = &ep->config;
3597 struct sps_register_event *sps_event = &ep->event;
3598
3599 sps_event->xfer_done = NULL;
3600 sps_event->callback = NULL;
3601 sps_register_event(sps_pipe_handle, sps_event);
3602 sps_disconnect(sps_pipe_handle);
3603 dma_free_coherent(mmc_dev(host->mmc),
3604 sps_config->desc.size,
3605 sps_config->desc.base,
3606 sps_config->desc.phys_base);
3607 sps_free_endpoint(sps_pipe_handle);
3608}
3609
3610/**
3611 * Reset SDCC peripheral's SPS endpoint
3612 *
3613 * This function disconnects an endpoint.
3614 *
3615 * This function should be called for reseting
3616 * SPS endpoint when data transfer error is
3617 * encountered during data transfer. This
3618 * can be considered as soft reset to endpoint.
3619 *
3620 * This function should only be called if
3621 * msmsdcc_sps_init() is already called.
3622 *
3623 * @host - Pointer to sdcc host structure
3624 * @ep - Pointer to sps endpoint data structure
3625 *
3626 * @return - 0 if successful else negative value.
3627 */
3628static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3629 struct msmsdcc_sps_ep_conn_data *ep)
3630{
3631 int rc = 0;
3632 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3633
3634 rc = sps_disconnect(sps_pipe_handle);
3635 if (rc) {
3636 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3637 " rc=%d", mmc_hostname(host->mmc), __func__,
3638 (u32)sps_pipe_handle, rc);
3639 goto out;
3640 }
3641 out:
3642 return rc;
3643}
3644
3645/**
3646 * Restore SDCC peripheral's SPS endpoint
3647 *
3648 * This function connects an endpoint.
3649 *
3650 * This function should be called for restoring
3651 * SPS endpoint after data transfer error is
3652 * encountered during data transfer. This
3653 * can be considered as soft reset to endpoint.
3654 *
3655 * This function should only be called if
3656 * msmsdcc_sps_reset_ep() is called before.
3657 *
3658 * @host - Pointer to sdcc host structure
3659 * @ep - Pointer to sps endpoint data structure
3660 *
3661 * @return - 0 if successful else negative value.
3662 */
3663static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3664 struct msmsdcc_sps_ep_conn_data *ep)
3665{
3666 int rc = 0;
3667 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3668 struct sps_connect *sps_config = &ep->config;
3669 struct sps_register_event *sps_event = &ep->event;
3670
3671 /* Establish connection between peripheral and memory endpoint */
3672 rc = sps_connect(sps_pipe_handle, sps_config);
3673 if (rc) {
3674 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3675 " rc=%d", mmc_hostname(host->mmc), __func__,
3676 (u32)sps_pipe_handle, rc);
3677 goto out;
3678 }
3679
3680 /* Register callback event for EOT (End of transfer) event. */
3681 rc = sps_register_event(sps_pipe_handle, sps_event);
3682 if (rc) {
3683 pr_err("%s: %s: sps_register_event() failed!!!"
3684 " pipe_handle=0x%x, rc=%d",
3685 mmc_hostname(host->mmc), __func__,
3686 (u32)sps_pipe_handle, rc);
3687 goto reg_event_err;
3688 }
3689 goto out;
3690
3691reg_event_err:
3692 sps_disconnect(sps_pipe_handle);
3693out:
3694 return rc;
3695}
3696
3697/**
3698 * Initialize SPS HW connected with SDCC core
3699 *
3700 * This function register BAM HW resources with
3701 * SPS driver and then initialize 2 SPS endpoints
3702 *
3703 * This function should only be called once typically
3704 * during driver probe.
3705 *
3706 * @host - Pointer to sdcc host structure
3707 *
3708 * @return - 0 if successful else negative value.
3709 *
3710 */
3711static int msmsdcc_sps_init(struct msmsdcc_host *host)
3712{
3713 int rc = 0;
3714 struct sps_bam_props bam = {0};
3715
3716 host->bam_base = ioremap(host->bam_memres->start,
3717 resource_size(host->bam_memres));
3718 if (!host->bam_base) {
3719 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3720 " size=0x%x", mmc_hostname(host->mmc),
3721 host->bam_memres->start,
3722 (host->bam_memres->end -
3723 host->bam_memres->start));
3724 rc = -ENOMEM;
3725 goto out;
3726 }
3727
3728 bam.phys_addr = host->bam_memres->start;
3729 bam.virt_addr = host->bam_base;
3730 /*
3731 * This event thresold value is only significant for BAM-to-BAM
3732 * transfer. It's ignored for BAM-to-System mode transfer.
3733 */
3734 bam.event_threshold = 0x10; /* Pipe event threshold */
3735 /*
3736 * This threshold controls when the BAM publish
3737 * the descriptor size on the sideband interface.
3738 * SPS HW will only be used when
3739 * data transfer size > MCI_FIFOSIZE (64 bytes).
3740 * PIO mode will be used when
3741 * data transfer size < MCI_FIFOSIZE (64 bytes).
3742 * So set this thresold value to 64 bytes.
3743 */
3744 bam.summing_threshold = 64;
3745 /* SPS driver wll handle the SDCC BAM IRQ */
3746 bam.irq = (u32)host->bam_irqres->start;
3747 bam.manage = SPS_BAM_MGR_LOCAL;
3748
3749 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3750 (u32)bam.phys_addr);
3751 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3752 (u32)bam.virt_addr);
3753
3754 /* Register SDCC Peripheral BAM device to SPS driver */
3755 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3756 if (rc) {
3757 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3758 mmc_hostname(host->mmc), rc);
3759 goto reg_bam_err;
3760 }
3761 pr_info("%s: BAM device registered. bam_handle=0x%x",
3762 mmc_hostname(host->mmc), host->sps.bam_handle);
3763
3764 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3765 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3766
3767 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3768 SPS_PROD_PERIPHERAL);
3769 if (rc)
3770 goto sps_reset_err;
3771 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3772 SPS_CONS_PERIPHERAL);
3773 if (rc)
3774 goto cons_conn_err;
3775
3776 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3777 mmc_hostname(host->mmc),
3778 (unsigned long long)host->bam_memres->start,
3779 (unsigned int)host->bam_irqres->start);
3780 goto out;
3781
3782cons_conn_err:
3783 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3784sps_reset_err:
3785 sps_deregister_bam_device(host->sps.bam_handle);
3786reg_bam_err:
3787 iounmap(host->bam_base);
3788out:
3789 return rc;
3790}
3791
3792/**
3793 * De-initialize SPS HW connected with SDCC core
3794 *
3795 * This function deinitialize SPS endpoints and then
3796 * deregisters BAM resources from SPS driver.
3797 *
3798 * This function should only be called once typically
3799 * during driver remove.
3800 *
3801 * @host - Pointer to sdcc host structure
3802 *
3803 */
3804static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3805{
3806 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3807 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3808 sps_deregister_bam_device(host->sps.bam_handle);
3809 iounmap(host->bam_base);
3810}
3811#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3812
3813static ssize_t
3814show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3815{
3816 struct mmc_host *mmc = dev_get_drvdata(dev);
3817 struct msmsdcc_host *host = mmc_priv(mmc);
3818 int poll;
3819 unsigned long flags;
3820
3821 spin_lock_irqsave(&host->lock, flags);
3822 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3823 spin_unlock_irqrestore(&host->lock, flags);
3824
3825 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3826}
3827
3828static ssize_t
3829set_polling(struct device *dev, struct device_attribute *attr,
3830 const char *buf, size_t count)
3831{
3832 struct mmc_host *mmc = dev_get_drvdata(dev);
3833 struct msmsdcc_host *host = mmc_priv(mmc);
3834 int value;
3835 unsigned long flags;
3836
3837 sscanf(buf, "%d", &value);
3838
3839 spin_lock_irqsave(&host->lock, flags);
3840 if (value) {
3841 mmc->caps |= MMC_CAP_NEEDS_POLL;
3842 mmc_detect_change(host->mmc, 0);
3843 } else {
3844 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3845 }
3846#ifdef CONFIG_HAS_EARLYSUSPEND
3847 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3848#endif
3849 spin_unlock_irqrestore(&host->lock, flags);
3850 return count;
3851}
3852
3853static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3854 show_polling, set_polling);
3855static struct attribute *dev_attrs[] = {
3856 &dev_attr_polling.attr,
3857 NULL,
3858};
3859static struct attribute_group dev_attr_grp = {
3860 .attrs = dev_attrs,
3861};
3862
3863#ifdef CONFIG_HAS_EARLYSUSPEND
3864static void msmsdcc_early_suspend(struct early_suspend *h)
3865{
3866 struct msmsdcc_host *host =
3867 container_of(h, struct msmsdcc_host, early_suspend);
3868 unsigned long flags;
3869
3870 spin_lock_irqsave(&host->lock, flags);
3871 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3872 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3873 spin_unlock_irqrestore(&host->lock, flags);
3874};
3875static void msmsdcc_late_resume(struct early_suspend *h)
3876{
3877 struct msmsdcc_host *host =
3878 container_of(h, struct msmsdcc_host, early_suspend);
3879 unsigned long flags;
3880
3881 if (host->polling_enabled) {
3882 spin_lock_irqsave(&host->lock, flags);
3883 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3884 mmc_detect_change(host->mmc, 0);
3885 spin_unlock_irqrestore(&host->lock, flags);
3886 }
3887};
3888#endif
3889
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303890void msmsdcc_print_regs(const char *name, void __iomem *base,
3891 unsigned int no_of_regs)
3892{
3893 unsigned int i;
3894
3895 if (!base)
3896 return;
3897 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3898 name, (u32)base);
3899 for (i = 0; i < no_of_regs; i = i + 4) {
3900 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3901 (u32)readl_relaxed(base + i*4),
3902 (u32)readl_relaxed(base + ((i+1)*4)),
3903 (u32)readl_relaxed(base + ((i+2)*4)),
3904 (u32)readl_relaxed(base + ((i+3)*4)));
3905 }
3906}
3907
3908static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3909{
3910 /* Dump current state of SDCC clocks, power and irq */
3911 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3912 (host->pwr ? "ON" : "OFF"));
3913 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3914 mmc_hostname(host->mmc),
3915 (host->clks_on ? "ON" : "OFF"),
3916 (u32)clk_get_rate(host->clk));
3917 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3918 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3919
3920 /* Now dump SDCC registers. Don't print FIFO registers */
3921 if (host->clks_on)
3922 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3923
3924 if (host->curr.data) {
3925 if (msmsdcc_check_dma_op_req(host->curr.data))
3926 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3927 else if (host->is_dma_mode)
3928 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3929 mmc_hostname(host->mmc), host->dma.busy,
3930 host->dma.channel, host->dma.crci);
3931 else if (host->is_sps_mode)
3932 pr_info("%s: SPS mode: busy=%d\n",
3933 mmc_hostname(host->mmc), host->sps.busy);
3934
3935 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3936 mmc_hostname(host->mmc), host->curr.xfer_size,
3937 host->curr.data_xfered, host->curr.xfer_remain);
3938 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3939 " wait_for_auto_prog_done=%d,"
3940 " got_auto_prog_done=%d\n",
3941 mmc_hostname(host->mmc), host->curr.got_dataend,
3942 host->prog_enable, host->curr.wait_for_auto_prog_done,
3943 host->curr.got_auto_prog_done);
3944 }
3945
3946}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003947static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3948{
3949 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3950 struct mmc_request *mrq;
3951 unsigned long flags;
3952
3953 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003954 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 pr_info("%s: %s: dummy CMD52 timeout\n",
3956 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003957 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003958 }
3959
3960 mrq = host->curr.mrq;
3961
3962 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303963 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3964 mrq->cmd->opcode);
3965 msmsdcc_dump_sdcc_state(host);
3966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003967 if (!mrq->cmd->error)
3968 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303969 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003971 if (mrq->data && !mrq->data->error)
3972 mrq->data->error = -ETIMEDOUT;
3973 host->curr.data_xfered = 0;
3974 if (host->dma.sg && host->is_dma_mode) {
3975 msm_dmov_stop_cmd(host->dma.channel,
3976 &host->dma.hdr, 0);
3977 } else if (host->sps.sg && host->is_sps_mode) {
3978 /* Stop current SPS transfer */
3979 msmsdcc_sps_exit_curr_xfer(host);
3980 } else {
3981 msmsdcc_reset_and_restore(host);
3982 msmsdcc_stop_data(host);
3983 if (mrq->data && mrq->data->stop)
3984 msmsdcc_start_command(host,
3985 mrq->data->stop, 0);
3986 else
3987 msmsdcc_request_end(host, mrq);
3988 }
3989 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303990 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05303991 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003992 msmsdcc_reset_and_restore(host);
3993 msmsdcc_request_end(host, mrq);
3994 }
3995 }
3996 spin_unlock_irqrestore(&host->lock, flags);
3997}
3998
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303999static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4000{
4001 int i, ret;
4002 struct mmc_platform_data *pdata;
4003 struct device_node *np = dev->of_node;
4004 u32 bus_width = 0;
4005 u32 *clk_table;
4006 int clk_table_len;
4007 u32 *sup_voltages;
4008 int sup_volt_len;
4009
4010 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4011 if (!pdata) {
4012 dev_err(dev, "could not allocate memory for platform data\n");
4013 goto err;
4014 }
4015
4016 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4017 if (bus_width == 8) {
4018 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4019 } else if (bus_width == 4) {
4020 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4021 } else {
4022 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4023 pdata->mmc_bus_width = 0;
4024 }
4025
4026 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4027 size_t sz;
4028 sz = sup_volt_len / sizeof(*sup_voltages);
4029 if (sz > 0) {
4030 sup_voltages = devm_kzalloc(dev,
4031 sz * sizeof(*sup_voltages), GFP_KERNEL);
4032 if (!sup_voltages) {
4033 dev_err(dev, "No memory for supported voltage\n");
4034 goto err;
4035 }
4036
4037 ret = of_property_read_u32_array(np,
4038 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4039 if (ret < 0) {
4040 dev_err(dev, "error while reading voltage"
4041 "ranges %d\n", ret);
4042 goto err;
4043 }
4044 } else {
4045 dev_err(dev, "No supported voltages\n");
4046 goto err;
4047 }
4048 for (i = 0; i < sz; i += 2) {
4049 u32 mask;
4050
4051 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4052 sup_voltages[i + 1]);
4053 if (!mask)
4054 dev_err(dev, "Invalide voltage range %d\n", i);
4055 pdata->ocr_mask |= mask;
4056 }
4057 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4058 } else {
4059 dev_err(dev, "Supported voltage range not specified\n");
4060 }
4061
4062 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4063 size_t sz;
4064 sz = clk_table_len / sizeof(*clk_table);
4065
4066 if (sz > 0) {
4067 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4068 GFP_KERNEL);
4069 if (!clk_table) {
4070 dev_err(dev, "No memory for clock table\n");
4071 goto err;
4072 }
4073
4074 ret = of_property_read_u32_array(np,
4075 "qcom,sdcc-clk-rates", clk_table, sz);
4076 if (ret < 0) {
4077 dev_err(dev, "error while reading clk"
4078 "table %d\n", ret);
4079 goto err;
4080 }
4081 } else {
4082 dev_err(dev, "clk_table not specified\n");
4083 goto err;
4084 }
4085 pdata->sup_clk_table = clk_table;
4086 pdata->sup_clk_cnt = sz;
4087 } else {
4088 dev_err(dev, "Supported clock rates not specified\n");
4089 }
4090
4091 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4092 pdata->nonremovable = true;
4093 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4094 pdata->disable_cmd23 = true;
4095
4096 return pdata;
4097err:
4098 return NULL;
4099}
4100
San Mehat9d2bd732009-09-22 16:44:22 -07004101static int
4102msmsdcc_probe(struct platform_device *pdev)
4103{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304104 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004105 struct msmsdcc_host *host;
4106 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 unsigned long flags;
4108 struct resource *core_irqres = NULL;
4109 struct resource *bam_irqres = NULL;
4110 struct resource *core_memres = NULL;
4111 struct resource *dml_memres = NULL;
4112 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004113 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004114 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304115 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004117
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304118 if (pdev->dev.of_node) {
4119 plat = msmsdcc_populate_pdata(&pdev->dev);
4120 of_property_read_u32((&pdev->dev)->of_node,
4121 "cell-index", &pdev->id);
4122 } else {
4123 plat = pdev->dev.platform_data;
4124 }
4125
San Mehat9d2bd732009-09-22 16:44:22 -07004126 /* must have platform data */
4127 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004128 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004129 ret = -EINVAL;
4130 goto out;
4131 }
4132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004133 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004134 return -EINVAL;
4135
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304136 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4137 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4138 return -EINVAL;
4139 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140
San Mehat9d2bd732009-09-22 16:44:22 -07004141 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004142 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004143 return -ENXIO;
4144 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304145 if (pdev->dev.of_node) {
4146 /*
4147 * Device tree iomem resources are only accessible by index.
4148 * index = 0 -> SDCC register interface
4149 * index = 1 -> DML register interface
4150 * index = 2 -> BAM register interface
4151 * IRQ resources:
4152 * index = 0 -> SDCC IRQ
4153 * index = 1 -> BAM IRQ
4154 */
4155 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4156 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4157 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4158 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4159 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4160 } else {
4161 for (i = 0; i < pdev->num_resources; i++) {
4162 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4163 if (!strncmp(pdev->resource[i].name,
4164 "sdcc_dml_addr",
4165 sizeof("sdcc_dml_addr")))
4166 dml_memres = &pdev->resource[i];
4167 else if (!strncmp(pdev->resource[i].name,
4168 "sdcc_bam_addr",
4169 sizeof("sdcc_bam_addr")))
4170 bam_memres = &pdev->resource[i];
4171 else
4172 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004173
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304174 }
4175 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4176 if (!strncmp(pdev->resource[i].name,
4177 "sdcc_bam_irq",
4178 sizeof("sdcc_bam_irq")))
4179 bam_irqres = &pdev->resource[i];
4180 else
4181 core_irqres = &pdev->resource[i];
4182 }
4183 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4184 if (!strncmp(pdev->resource[i].name,
4185 "sdcc_dma_chnl",
4186 sizeof("sdcc_dma_chnl")))
4187 dmares = &pdev->resource[i];
4188 else if (!strncmp(pdev->resource[i].name,
4189 "sdcc_dma_crci",
4190 sizeof("sdcc_dma_crci")))
4191 dma_crci_res = &pdev->resource[i];
4192 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004193 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194 }
4195
4196 if (!core_irqres || !core_memres) {
4197 pr_err("%s: Invalid sdcc core resource\n", __func__);
4198 return -ENXIO;
4199 }
4200
4201 /*
4202 * Both BAM and DML memory resource should be preset.
4203 * BAM IRQ resource should also be present.
4204 */
4205 if ((bam_memres && !dml_memres) ||
4206 (!bam_memres && dml_memres) ||
4207 ((bam_memres && dml_memres) && !bam_irqres)) {
4208 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004209 return -ENXIO;
4210 }
4211
4212 /*
4213 * Setup our host structure
4214 */
San Mehat9d2bd732009-09-22 16:44:22 -07004215 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4216 if (!mmc) {
4217 ret = -ENOMEM;
4218 goto out;
4219 }
4220
4221 host = mmc_priv(mmc);
4222 host->pdev_id = pdev->id;
4223 host->plat = plat;
4224 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004225 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304226
4227 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004228 host->is_sps_mode = 1;
4229 else if (dmares)
4230 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004232 host->base = ioremap(core_memres->start,
4233 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004234 if (!host->base) {
4235 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004237 }
4238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004239 host->core_irqres = core_irqres;
4240 host->bam_irqres = bam_irqres;
4241 host->core_memres = core_memres;
4242 host->dml_memres = dml_memres;
4243 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004244 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004245 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004246 spin_lock_init(&host->lock);
4247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004248#ifdef CONFIG_MMC_EMBEDDED_SDIO
4249 if (plat->embedded_sdio)
4250 mmc_set_embedded_sdio_data(mmc,
4251 &plat->embedded_sdio->cis,
4252 &plat->embedded_sdio->cccr,
4253 plat->embedded_sdio->funcs,
4254 plat->embedded_sdio->num_funcs);
4255#endif
4256
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304257 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4258 (unsigned long)host);
4259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004260 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4261 (unsigned long)host);
4262 if (host->is_dma_mode) {
4263 /* Setup DMA */
4264 ret = msmsdcc_init_dma(host);
4265 if (ret)
4266 goto ioremap_free;
4267 } else {
4268 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004269 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004270 }
4271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004272 /*
4273 * Setup SDCC clock if derived from Dayatona
4274 * fabric core clock.
4275 */
4276 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004277 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 if (!IS_ERR(host->dfab_pclk)) {
4279 /* Set the clock rate to 64MHz for max. performance */
4280 ret = clk_set_rate(host->dfab_pclk, 64000000);
4281 if (ret)
4282 goto dfab_pclk_put;
4283 ret = clk_enable(host->dfab_pclk);
4284 if (ret)
4285 goto dfab_pclk_put;
4286 } else
4287 goto dma_free;
4288 }
4289
4290 /*
4291 * Setup main peripheral bus clock
4292 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004293 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004294 if (!IS_ERR(host->pclk)) {
4295 ret = clk_enable(host->pclk);
4296 if (ret)
4297 goto pclk_put;
4298
4299 host->pclk_rate = clk_get_rate(host->pclk);
4300 }
4301
4302 /*
4303 * Setup SDC MMC clock
4304 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004305 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004306 if (IS_ERR(host->clk)) {
4307 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004309 }
4310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004311 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4312 if (ret) {
4313 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4314 goto clk_put;
4315 }
4316
4317 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004318 if (ret)
4319 goto clk_put;
4320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004321 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304322 if (!host->clk_rate)
4323 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304324
4325 /*
4326 * Lookup the Controller Version, to identify the supported features
4327 * Version number read as 0 would indicate SDCC3 or earlier versions
4328 */
4329 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4330 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4331 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304332 /*
4333 * Set the register write delay according to min. clock frequency
4334 * supported and update later when the host->clk_rate changes.
4335 */
4336 host->reg_write_delay =
4337 (1 + ((3 * USEC_PER_SEC) /
4338 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004339
4340 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304341 /* Apply Hard reset to SDCC to put it in power on default state */
4342 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004343
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304344 /* pm qos request to prevent apps idle power collapse */
4345 if (host->plat->swfi_latency)
4346 pm_qos_add_request(&host->pm_qos_req_dma,
4347 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004349 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004350 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004351 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004352 goto clk_disable;
4353 }
4354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004355
4356 /* Clocks has to be running before accessing SPS/DML HW blocks */
4357 if (host->is_sps_mode) {
4358 /* Initialize SPS */
4359 ret = msmsdcc_sps_init(host);
4360 if (ret)
4361 goto vreg_deinit;
4362 /* Initialize DML */
4363 ret = msmsdcc_dml_init(host);
4364 if (ret)
4365 goto sps_exit;
4366 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304367 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004368
San Mehat9d2bd732009-09-22 16:44:22 -07004369 /*
4370 * Setup MMC host structure
4371 */
4372 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004373 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4374 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004375 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004376 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4377 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004378
San Mehat9d2bd732009-09-22 16:44:22 -07004379 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304380 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304381
4382 /*
4383 * If we send the CMD23 before multi block write/read command
4384 * then we need not to send CMD12 at the end of the transfer.
4385 * If we don't send the CMD12 then only way to detect the PROG_DONE
4386 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4387 * controller. So let's enable the CMD23 for SDCC4 only.
4388 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304389 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304390 mmc->caps |= MMC_CAP_CMD23;
4391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392 mmc->caps |= plat->uhs_caps;
4393 /*
4394 * XPC controls the maximum current in the default speed mode of SDXC
4395 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4396 * XPC=1 means 150mA (max.) and speed class is supported.
4397 */
4398 if (plat->xpc_cap)
4399 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4400 MMC_CAP_SET_XPC_180);
4401
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304402 if (pdev->dev.of_node) {
4403 if (of_get_property((&pdev->dev)->of_node,
4404 "qcom,sdcc-hs200", NULL))
4405 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4406 }
4407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004408 if (plat->nonremovable)
4409 mmc->caps |= MMC_CAP_NONREMOVABLE;
4410#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4411 mmc->caps |= MMC_CAP_SDIO_IRQ;
4412#endif
4413
4414 if (plat->is_sdio_al_client)
4415 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004416
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304417 mmc->max_segs = msmsdcc_get_nr_sg(host);
4418 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4419 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004420
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304421 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304422 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004424 writel_relaxed(0, host->base + MMCIMASK0);
4425 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004427 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4428 mb();
4429 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004431 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4432 DRIVER_NAME " (cmd)", host);
4433 if (ret)
4434 goto dml_exit;
4435
4436 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4437 DRIVER_NAME " (pio)", host);
4438 if (ret)
4439 goto irq_free;
4440
4441 /*
4442 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4443 * IRQ is un-necessarily being monitored by MPM (Modem power
4444 * management block) during idle-power collapse. The MPM will be
4445 * configured to monitor the DATA1 GPIO line with level-low trigger
4446 * and thus depending on the GPIO status, it prevents TCXO shutdown
4447 * during idle-power collapse.
4448 */
4449 disable_irq(core_irqres->start);
4450 host->sdcc_irq_disabled = 1;
4451
4452 if (plat->sdiowakeup_irq) {
4453 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4454 mmc_hostname(mmc));
4455 ret = request_irq(plat->sdiowakeup_irq,
4456 msmsdcc_platform_sdiowakeup_irq,
4457 IRQF_SHARED | IRQF_TRIGGER_LOW,
4458 DRIVER_NAME "sdiowakeup", host);
4459 if (ret) {
4460 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4461 plat->sdiowakeup_irq, ret);
4462 goto pio_irq_free;
4463 } else {
4464 spin_lock_irqsave(&host->lock, flags);
4465 if (!host->sdio_irq_disabled) {
4466 disable_irq_nosync(plat->sdiowakeup_irq);
4467 host->sdio_irq_disabled = 1;
4468 }
4469 spin_unlock_irqrestore(&host->lock, flags);
4470 }
4471 }
4472
4473 if (plat->cfg_mpm_sdiowakeup) {
4474 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4475 mmc_hostname(mmc));
4476 }
4477
4478 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4479 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004480 /*
4481 * Setup card detect change
4482 */
4483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004484 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004485 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004486 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004487 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004488 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004489
Krishna Konda941604a2012-01-10 17:46:34 -08004490 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004491 }
San Mehat9d2bd732009-09-22 16:44:22 -07004492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004493 if (plat->status_irq) {
4494 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004495 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004496 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004497 DRIVER_NAME " (slot)",
4498 host);
4499 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004500 pr_err("Unable to get slot IRQ %d (%d)\n",
4501 plat->status_irq, ret);
4502 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004503 }
4504 } else if (plat->register_status_notify) {
4505 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4506 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004507 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004508 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004509
4510 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511
4512 ret = pm_runtime_set_active(&(pdev)->dev);
4513 if (ret < 0)
4514 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4515 __func__, ret);
4516 /*
4517 * There is no notion of suspend/resume for SD/MMC/SDIO
4518 * cards. So host can be suspended/resumed with out
4519 * worrying about its children.
4520 */
4521 pm_suspend_ignore_children(&(pdev)->dev, true);
4522
4523 /*
4524 * MMC/SD/SDIO bus suspend/resume operations are defined
4525 * only for the slots that will be used for non-removable
4526 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4527 * defined. Otherwise, they simply become card removal and
4528 * insertion events during suspend and resume respectively.
4529 * Hence, enable run-time PM only for slots for which bus
4530 * suspend/resume operations are defined.
4531 */
4532#ifdef CONFIG_MMC_UNSAFE_RESUME
4533 /*
4534 * If this capability is set, MMC core will enable/disable host
4535 * for every claim/release operation on a host. We use this
4536 * notification to increment/decrement runtime pm usage count.
4537 */
4538 mmc->caps |= MMC_CAP_DISABLE;
4539 pm_runtime_enable(&(pdev)->dev);
4540#else
4541 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4542 mmc->caps |= MMC_CAP_DISABLE;
4543 pm_runtime_enable(&(pdev)->dev);
4544 }
4545#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304546#ifndef CONFIG_PM_RUNTIME
4547 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4548#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004549 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4550 (unsigned long)host);
4551
San Mehat9d2bd732009-09-22 16:44:22 -07004552 mmc_add_host(mmc);
4553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004554#ifdef CONFIG_HAS_EARLYSUSPEND
4555 host->early_suspend.suspend = msmsdcc_early_suspend;
4556 host->early_suspend.resume = msmsdcc_late_resume;
4557 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4558 register_early_suspend(&host->early_suspend);
4559#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004560
Krishna Konda25786ec2011-07-25 16:21:36 -07004561 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4562 " dmacrcri %d\n", mmc_hostname(mmc),
4563 (unsigned long long)core_memres->start,
4564 (unsigned int) core_irqres->start,
4565 (unsigned int) plat->status_irq, host->dma.channel,
4566 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004567
4568 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4569 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4570 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4571 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4572 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4573 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4574 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4575 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4576 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4577 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4578 host->eject);
4579 pr_info("%s: Power save feature enable = %d\n",
4580 mmc_hostname(mmc), msmsdcc_pwrsave);
4581
Krishna Konda25786ec2011-07-25 16:21:36 -07004582 if (host->is_dma_mode && host->dma.channel != -1
4583 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004584 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004585 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004586 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004587 mmc_hostname(mmc), host->dma.cmd_busaddr,
4588 host->dma.cmdptr_busaddr);
4589 } else if (host->is_sps_mode) {
4590 pr_info("%s: SPS-BAM data transfer mode available\n",
4591 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004592 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004593 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004595#if defined(CONFIG_DEBUG_FS)
4596 msmsdcc_dbg_createhost(host);
4597#endif
4598 if (!plat->status_irq) {
4599 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4600 if (ret)
4601 goto platform_irq_free;
4602 }
San Mehat9d2bd732009-09-22 16:44:22 -07004603 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604
4605 platform_irq_free:
4606 del_timer_sync(&host->req_tout_timer);
4607 pm_runtime_disable(&(pdev)->dev);
4608 pm_runtime_set_suspended(&(pdev)->dev);
4609
4610 if (plat->status_irq)
4611 free_irq(plat->status_irq, host);
4612 sdiowakeup_irq_free:
4613 wake_lock_destroy(&host->sdio_suspend_wlock);
4614 if (plat->sdiowakeup_irq)
4615 free_irq(plat->sdiowakeup_irq, host);
4616 pio_irq_free:
4617 if (plat->sdiowakeup_irq)
4618 wake_lock_destroy(&host->sdio_wlock);
4619 free_irq(core_irqres->start, host);
4620 irq_free:
4621 free_irq(core_irqres->start, host);
4622 dml_exit:
4623 if (host->is_sps_mode)
4624 msmsdcc_dml_exit(host);
4625 sps_exit:
4626 if (host->is_sps_mode)
4627 msmsdcc_sps_exit(host);
4628 vreg_deinit:
4629 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004630 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004631 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304632 if (host->plat->swfi_latency)
4633 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004634 clk_put:
4635 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004636 pclk_disable:
4637 if (!IS_ERR(host->pclk))
4638 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004639 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 if (!IS_ERR(host->pclk))
4641 clk_put(host->pclk);
4642 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4643 clk_disable(host->dfab_pclk);
4644 dfab_pclk_put:
4645 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4646 clk_put(host->dfab_pclk);
4647 dma_free:
4648 if (host->is_dma_mode) {
4649 if (host->dmares)
4650 dma_free_coherent(NULL,
4651 sizeof(struct msmsdcc_nc_dmadata),
4652 host->dma.nc, host->dma.nc_busaddr);
4653 }
4654 ioremap_free:
4655 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004656 host_free:
4657 mmc_free_host(mmc);
4658 out:
4659 return ret;
4660}
4661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004662static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004663{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004664 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4665 struct mmc_platform_data *plat;
4666 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 if (!mmc)
4669 return -ENXIO;
4670
4671 if (pm_runtime_suspended(&(pdev)->dev))
4672 pm_runtime_resume(&(pdev)->dev);
4673
4674 host = mmc_priv(mmc);
4675
4676 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4677 plat = host->plat;
4678
4679 if (!plat->status_irq)
4680 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4681
4682 del_timer_sync(&host->req_tout_timer);
4683 tasklet_kill(&host->dma_tlet);
4684 tasklet_kill(&host->sps.tlet);
4685 mmc_remove_host(mmc);
4686
4687 if (plat->status_irq)
4688 free_irq(plat->status_irq, host);
4689
4690 wake_lock_destroy(&host->sdio_suspend_wlock);
4691 if (plat->sdiowakeup_irq) {
4692 wake_lock_destroy(&host->sdio_wlock);
4693 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4694 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004695 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004696
4697 free_irq(host->core_irqres->start, host);
4698 free_irq(host->core_irqres->start, host);
4699
4700 clk_put(host->clk);
4701 if (!IS_ERR(host->pclk))
4702 clk_put(host->pclk);
4703 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4704 clk_put(host->dfab_pclk);
4705
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304706 if (host->plat->swfi_latency)
4707 pm_qos_remove_request(&host->pm_qos_req_dma);
4708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004709 msmsdcc_vreg_init(host, false);
4710
4711 if (host->is_dma_mode) {
4712 if (host->dmares)
4713 dma_free_coherent(NULL,
4714 sizeof(struct msmsdcc_nc_dmadata),
4715 host->dma.nc, host->dma.nc_busaddr);
4716 }
4717
4718 if (host->is_sps_mode) {
4719 msmsdcc_dml_exit(host);
4720 msmsdcc_sps_exit(host);
4721 }
4722
4723 iounmap(host->base);
4724 mmc_free_host(mmc);
4725
4726#ifdef CONFIG_HAS_EARLYSUSPEND
4727 unregister_early_suspend(&host->early_suspend);
4728#endif
4729 pm_runtime_disable(&(pdev)->dev);
4730 pm_runtime_set_suspended(&(pdev)->dev);
4731
4732 return 0;
4733}
4734
4735#ifdef CONFIG_MSM_SDIO_AL
4736int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4737{
4738 struct msmsdcc_host *host = mmc_priv(mmc);
4739 unsigned long flags;
4740
4741 spin_lock_irqsave(&host->lock, flags);
4742 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4743 enable ? "En" : "Dis");
4744
4745 if (enable) {
4746 if (!host->sdcc_irq_disabled) {
4747 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304748 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004749 host->sdcc_irq_disabled = 1;
4750 }
4751
4752 if (host->clks_on) {
4753 msmsdcc_setup_clocks(host, false);
4754 host->clks_on = 0;
4755 }
4756
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304757 if (host->plat->sdio_lpm_gpio_setup &&
4758 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004759 spin_unlock_irqrestore(&host->lock, flags);
4760 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4761 spin_lock_irqsave(&host->lock, flags);
4762 host->sdio_gpio_lpm = 1;
4763 }
4764
4765 if (host->sdio_irq_disabled) {
4766 msmsdcc_enable_irq_wake(host);
4767 enable_irq(host->plat->sdiowakeup_irq);
4768 host->sdio_irq_disabled = 0;
4769 }
4770 } else {
4771 if (!host->sdio_irq_disabled) {
4772 disable_irq_nosync(host->plat->sdiowakeup_irq);
4773 host->sdio_irq_disabled = 1;
4774 msmsdcc_disable_irq_wake(host);
4775 }
4776
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304777 if (host->plat->sdio_lpm_gpio_setup &&
4778 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004779 spin_unlock_irqrestore(&host->lock, flags);
4780 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4781 spin_lock_irqsave(&host->lock, flags);
4782 host->sdio_gpio_lpm = 0;
4783 }
4784
4785 if (!host->clks_on) {
4786 msmsdcc_setup_clocks(host, true);
4787 host->clks_on = 1;
4788 }
4789
4790 if (host->sdcc_irq_disabled) {
4791 writel_relaxed(host->mci_irqenable,
4792 host->base + MMCIMASK0);
4793 mb();
4794 enable_irq(host->core_irqres->start);
4795 host->sdcc_irq_disabled = 0;
4796 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797 }
4798 spin_unlock_irqrestore(&host->lock, flags);
4799 return 0;
4800}
4801#else
4802int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4803{
4804 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004805}
4806#endif
4807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004809static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004810msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004811{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 struct mmc_host *mmc = dev_get_drvdata(dev);
4813 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004814 int rc = 0;
4815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004816 if (host->plat->is_sdio_al_client)
4817 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304818 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004819 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004820 host->sdcc_suspending = 1;
4821 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004823 /*
4824 * If the clocks are already turned off by SDIO clients (as
4825 * part of LPM), then clocks should be turned on before
4826 * calling mmc_suspend_host() because mmc_suspend_host might
4827 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304828 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829 * cards, clocks will be turned on before mmc_suspend_host
4830 * and turned off after mmc_suspend_host.
4831 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304832 if (mmc->card && mmc_card_sdio(mmc->card)) {
4833 mmc->ios.clock = host->clk_rate;
4834 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4835 }
San Mehat9d2bd732009-09-22 16:44:22 -07004836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004837 /*
4838 * MMC core thinks that host is disabled by now since
4839 * runtime suspend is scheduled after msmsdcc_disable()
4840 * is called. Thus, MMC core will try to enable the host
4841 * while suspending it. This results in a synchronous
4842 * runtime resume request while in runtime suspending
4843 * context and hence inorder to complete this resume
4844 * requet, it will wait for suspend to be complete,
4845 * but runtime suspend also can not proceed further
4846 * until the host is resumed. Thus, it leads to a hang.
4847 * Hence, increase the pm usage count before suspending
4848 * the host so that any resume requests after this will
4849 * simple become pm usage counter increment operations.
4850 */
4851 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304852 /* If there is pending detect work abort runtime suspend */
4853 if (unlikely(work_busy(&mmc->detect.work)))
4854 rc = -EAGAIN;
4855 else
4856 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004857 pm_runtime_put_noidle(dev);
4858
4859 if (!rc) {
4860 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4861 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4862 disable_irq(host->core_irqres->start);
4863 host->sdcc_irq_disabled = 1;
4864
4865 /*
4866 * If MMC core level suspend is not supported,
4867 * turn off clocks to allow deep sleep (TCXO
4868 * shutdown).
4869 */
4870 mmc->ios.clock = 0;
4871 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4872 enable_irq(host->core_irqres->start);
4873 host->sdcc_irq_disabled = 0;
4874
4875 if (host->plat->sdiowakeup_irq) {
4876 host->sdio_irq_disabled = 0;
4877 msmsdcc_enable_irq_wake(host);
4878 enable_irq(host->plat->sdiowakeup_irq);
4879 }
4880 }
4881 }
4882 host->sdcc_suspending = 0;
4883 mmc->suspend_task = NULL;
4884 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4885 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004886 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304887 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004888 return rc;
4889}
4890
4891static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004892msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004893{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004894 struct mmc_host *mmc = dev_get_drvdata(dev);
4895 struct msmsdcc_host *host = mmc_priv(mmc);
4896 unsigned long flags;
4897
4898 if (host->plat->is_sdio_al_client)
4899 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004900
Sahitya Tummala7661a452011-07-18 13:28:35 +05304901 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004902 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004903 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4904 if (host->sdcc_irq_disabled) {
4905 enable_irq(host->core_irqres->start);
4906 host->sdcc_irq_disabled = 0;
4907 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304908 mmc->ios.clock = host->clk_rate;
4909 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004910
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304911 spin_lock_irqsave(&host->lock, flags);
4912 writel_relaxed(host->mci_irqenable,
4913 host->base + MMCIMASK0);
4914 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004915
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304916 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4917 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004918 if (host->plat->sdiowakeup_irq) {
4919 disable_irq_nosync(
4920 host->plat->sdiowakeup_irq);
4921 msmsdcc_disable_irq_wake(host);
4922 host->sdio_irq_disabled = 1;
4923 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304924 }
San Mehat9d2bd732009-09-22 16:44:22 -07004925
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304926 spin_unlock_irqrestore(&host->lock, flags);
4927 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004928
4929 mmc_resume_host(mmc);
4930
4931 /*
4932 * FIXME: Clearing of flags must be handled in clients
4933 * resume handler.
4934 */
4935 spin_lock_irqsave(&host->lock, flags);
4936 mmc->pm_flags = 0;
4937 spin_unlock_irqrestore(&host->lock, flags);
4938
4939 /*
4940 * After resuming the host wait for sometime so that
4941 * the SDIO work will be processed.
4942 */
4943 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4944 if ((host->plat->cfg_mpm_sdiowakeup ||
4945 host->plat->sdiowakeup_irq) &&
4946 wake_lock_active(&host->sdio_wlock))
4947 wake_lock_timeout(&host->sdio_wlock, 1);
4948 }
4949
4950 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004951 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304952 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004953 return 0;
4954}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955
4956static int msmsdcc_runtime_idle(struct device *dev)
4957{
4958 struct mmc_host *mmc = dev_get_drvdata(dev);
4959 struct msmsdcc_host *host = mmc_priv(mmc);
4960
4961 if (host->plat->is_sdio_al_client)
4962 return 0;
4963
4964 /* Idle timeout is not configurable for now */
4965 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4966
4967 return -EAGAIN;
4968}
4969
4970static int msmsdcc_pm_suspend(struct device *dev)
4971{
4972 struct mmc_host *mmc = dev_get_drvdata(dev);
4973 struct msmsdcc_host *host = mmc_priv(mmc);
4974 int rc = 0;
4975
4976 if (host->plat->is_sdio_al_client)
4977 return 0;
4978
4979
4980 if (host->plat->status_irq)
4981 disable_irq(host->plat->status_irq);
4982
4983 if (!pm_runtime_suspended(dev))
4984 rc = msmsdcc_runtime_suspend(dev);
4985
4986 return rc;
4987}
4988
4989static int msmsdcc_pm_resume(struct device *dev)
4990{
4991 struct mmc_host *mmc = dev_get_drvdata(dev);
4992 struct msmsdcc_host *host = mmc_priv(mmc);
4993 int rc = 0;
4994
4995 if (host->plat->is_sdio_al_client)
4996 return 0;
4997
Sahitya Tummalafb486372011-09-02 19:01:49 +05304998 if (!pm_runtime_suspended(dev))
4999 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005000 if (host->plat->status_irq) {
5001 msmsdcc_check_status((unsigned long)host);
5002 enable_irq(host->plat->status_irq);
5003 }
5004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005005 return rc;
5006}
5007
Daniel Walker08ecfde2010-06-23 12:32:20 -07005008#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005009#define msmsdcc_runtime_suspend NULL
5010#define msmsdcc_runtime_resume NULL
5011#define msmsdcc_runtime_idle NULL
5012#define msmsdcc_pm_suspend NULL
5013#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005014#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5017 .runtime_suspend = msmsdcc_runtime_suspend,
5018 .runtime_resume = msmsdcc_runtime_resume,
5019 .runtime_idle = msmsdcc_runtime_idle,
5020 .suspend = msmsdcc_pm_suspend,
5021 .resume = msmsdcc_pm_resume,
5022};
5023
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305024static const struct of_device_id msmsdcc_dt_match[] = {
5025 {.compatible = "qcom,msm-sdcc"},
5026
5027};
5028MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5029
San Mehat9d2bd732009-09-22 16:44:22 -07005030static struct platform_driver msmsdcc_driver = {
5031 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005032 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005033 .driver = {
5034 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305036 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005037 },
5038};
5039
5040static int __init msmsdcc_init(void)
5041{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005042#if defined(CONFIG_DEBUG_FS)
5043 int ret = 0;
5044 ret = msmsdcc_dbg_init();
5045 if (ret) {
5046 pr_err("Failed to create debug fs dir \n");
5047 return ret;
5048 }
5049#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005050 return platform_driver_register(&msmsdcc_driver);
5051}
5052
5053static void __exit msmsdcc_exit(void)
5054{
5055 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005056
5057#if defined(CONFIG_DEBUG_FS)
5058 debugfs_remove(debugfs_file);
5059 debugfs_remove(debugfs_dir);
5060#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005061}
5062
5063module_init(msmsdcc_init);
5064module_exit(msmsdcc_exit);
5065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005066MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005067MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005068
5069#if defined(CONFIG_DEBUG_FS)
5070
5071static int
5072msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5073{
5074 file->private_data = inode->i_private;
5075 return 0;
5076}
5077
5078static ssize_t
5079msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5080 size_t count, loff_t *ppos)
5081{
5082 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005083 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005084 int max, i;
5085
5086 i = 0;
5087 max = sizeof(buf) - 1;
5088
5089 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5090 host->curr.cmd, host->curr.data);
5091 if (host->curr.cmd) {
5092 struct mmc_command *cmd = host->curr.cmd;
5093
5094 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5095 cmd->opcode, cmd->arg, cmd->flags);
5096 }
5097 if (host->curr.data) {
5098 struct mmc_data *data = host->curr.data;
5099 i += scnprintf(buf + i, max - i,
5100 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5101 data->timeout_ns, data->timeout_clks,
5102 data->blksz, data->blocks, data->error,
5103 data->flags);
5104 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5105 host->curr.xfer_size, host->curr.xfer_remain,
5106 host->curr.data_xfered, host->dma.sg);
5107 }
5108
5109 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5110}
5111
5112static const struct file_operations msmsdcc_dbg_state_ops = {
5113 .read = msmsdcc_dbg_state_read,
5114 .open = msmsdcc_dbg_state_open,
5115};
5116
5117static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5118{
5119 if (debugfs_dir) {
5120 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5121 0644, debugfs_dir, host,
5122 &msmsdcc_dbg_state_ops);
5123 }
5124}
5125
5126static int __init msmsdcc_dbg_init(void)
5127{
5128 int err;
5129
5130 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5131 if (IS_ERR(debugfs_dir)) {
5132 err = PTR_ERR(debugfs_dir);
5133 debugfs_dir = NULL;
5134 return err;
5135 }
5136
5137 return 0;
5138}
5139#endif