blob: 69ec6478baa8ddc9e4c1361a6f9a0f85b1069703 [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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070057
San Mehat9d2bd732009-09-22 16:44:22 -070058#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070060
61#define DRIVER_NAME "msm-sdcc"
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define DBG(host, fmt, args...) \
64 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
65
66#define IRQ_DEBUG 0
67#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
68#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
69#define SPS_CONS_PERIPHERAL 0
70#define SPS_PROD_PERIPHERAL 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72#if defined(CONFIG_DEBUG_FS)
73static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
74static struct dentry *debugfs_dir;
75static struct dentry *debugfs_file;
76static int msmsdcc_dbg_init(void);
77#endif
78
Subhash Jadavani8766e352011-11-30 11:30:32 +053079static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070080static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082static struct mmc_command dummy52cmd;
83static struct mmc_request dummy52mrq = {
84 .cmd = &dummy52cmd,
85 .data = NULL,
86 .stop = NULL,
87};
88static struct mmc_command dummy52cmd = {
89 .opcode = SD_IO_RW_DIRECT,
90 .flags = MMC_RSP_PRESENT,
91 .data = NULL,
92 .mrq = &dummy52mrq,
93};
94/*
95 * An array holding the Tuning pattern to compare with when
96 * executing a tuning cycle.
97 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +053098static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
100 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
101 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
102 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
103};
San Mehat865c8062009-11-13 13:42:06 -0800104
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530105static const u32 tuning_block_128[] = {
106 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
107 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
108 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
109 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
110 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
111 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
112 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
113 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
114};
115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116#if IRQ_DEBUG == 1
117static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
118 "dattimeout", "txunderrun", "rxoverrun",
119 "cmdrespend", "cmdsent", "dataend", NULL,
120 "datablkend", "cmdactive", "txactive",
121 "rxactive", "txhalfempty", "rxhalffull",
122 "txfifofull", "rxfifofull", "txfifoempty",
123 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
124 "sdiointr", "progdone", "atacmdcompl",
125 "sdiointrope", "ccstimeout", NULL, NULL,
126 NULL, NULL, NULL };
127
128static void
129msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800130{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
134 for (i = 0; i < 32; i++) {
135 if (status & (1 << i))
136 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800139}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140#endif
San Mehat865c8062009-11-13 13:42:06 -0800141
San Mehat9d2bd732009-09-22 16:44:22 -0700142static void
143msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
144 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530145static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
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 Jadavanidd432952012-03-28 11:25:56 +0530264 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530266 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530267}
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
Subhash Jadavanidd432952012-03-28 11:25:56 +0530286 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530287 /* Give some delay for clock reset to propogate to controller */
288 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530289}
290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
292{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530293 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530294 if (host->is_sps_mode) {
295 /* Reset DML first */
296 msmsdcc_dml_reset(host);
297 /*
298 * delay the SPS pipe reset in thread context as
299 * sps_connect/sps_disconnect APIs can be called
300 * only from non-atomic context.
301 */
302 host->sps.pipe_reset_pending = true;
303 }
304 mb();
305 msmsdcc_soft_reset(host);
306
307 pr_debug("%s: Applied soft reset to Controller\n",
308 mmc_hostname(host->mmc));
309
310 if (host->is_sps_mode)
311 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 } else {
313 /* Give Clock reset (hard reset) to controller */
314 u32 mci_clk = 0;
315 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316
317 /* Save the controller state */
318 mci_clk = readl_relaxed(host->base + MMCICLOCK);
319 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530320 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530323 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 pr_debug("%s: Controller has been reinitialized\n",
325 mmc_hostname(host->mmc));
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 /* Restore the contoller state */
328 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530329 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530331 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530333 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530335
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700336 if (host->dummy_52_needed)
337 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338}
339
340static int
San Mehat9d2bd732009-09-22 16:44:22 -0700341msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
342{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 int retval = 0;
344
San Mehat9d2bd732009-09-22 16:44:22 -0700345 BUG_ON(host->curr.data);
346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 del_timer(&host->req_tout_timer);
348
San Mehat9d2bd732009-09-22 16:44:22 -0700349 if (mrq->data)
350 mrq->data->bytes_xfered = host->curr.data_xfered;
351 if (mrq->cmd->error == -ETIMEDOUT)
352 mdelay(5);
353
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530354 /* Clear current request information as current request has ended */
355 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
356
San Mehat9d2bd732009-09-22 16:44:22 -0700357 /*
358 * Need to drop the host lock here; mmc_request_done may call
359 * back into the driver...
360 */
361 spin_unlock(&host->lock);
362 mmc_request_done(host->mmc, mrq);
363 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
365 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700366}
367
368static void
369msmsdcc_stop_data(struct msmsdcc_host *host)
370{
San Mehat9d2bd732009-09-22 16:44:22 -0700371 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530372 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530373 host->curr.wait_for_auto_prog_done = 0;
374 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700375 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
376 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530377 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700378}
379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700381{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 return host->core_memres->start + MMCIFIFO;
383}
384
385static inline unsigned int msmsdcc_get_min_sup_clk_rate(
386 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530387
Subhash Jadavanidd432952012-03-28 11:25:56 +0530388static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389{
390 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530391 if (!host->sdcc_version)
392 udelay(host->reg_write_delay);
393 else if (readl_relaxed(host->base + MCI_STATUS2) &
394 MCI_MCLK_REG_WR_ACTIVE) {
395 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530396
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530397 start = ktime_get();
398 while (readl_relaxed(host->base + MCI_STATUS2) &
399 MCI_MCLK_REG_WR_ACTIVE) {
400 diff = ktime_sub(ktime_get(), start);
401 /* poll for max. 1 ms */
402 if (ktime_to_us(diff) > 1000) {
403 pr_warning("%s: previous reg. write is"
404 " still active\n",
405 mmc_hostname(host->mmc));
406 break;
407 }
408 }
409 }
San Mehat9d2bd732009-09-22 16:44:22 -0700410}
411
Subhash Jadavanidd432952012-03-28 11:25:56 +0530412static inline void msmsdcc_delay(struct msmsdcc_host *host)
413{
414 udelay(host->reg_write_delay);
415
416}
417
San Mehat56a8b5b2009-11-21 12:29:46 -0800418static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
420{
421 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530423 /*
424 * As after sending the command, we don't write any of the
425 * controller registers and just wait for the
426 * CMD_RESPOND_END/CMD_SENT/Command failure notication
427 * from Controller.
428 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800430}
431
432static void
433msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
434{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
438 writel_relaxed((unsigned int)host->curr.xfer_size,
439 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530441 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800442
San Mehat6ac9ea62009-12-02 17:24:58 -0800443 if (host->cmd_cmd) {
444 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800446 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800447}
448
San Mehat9d2bd732009-09-22 16:44:22 -0700449static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530450msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700451{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700453 unsigned long flags;
454 struct mmc_request *mrq;
455
456 spin_lock_irqsave(&host->lock, flags);
457 mrq = host->curr.mrq;
458 BUG_ON(!mrq);
459
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530460 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700461 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700462 goto out;
463 }
464
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530465 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700466 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700468 } else {
469 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530470 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700471 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530472 mmc_hostname(host->mmc), host->dma.result);
473 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700474 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530476 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 host->dma.err.flush[0], host->dma.err.flush[1],
478 host->dma.err.flush[2], host->dma.err.flush[3],
479 host->dma.err.flush[4],
480 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530481 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700482 if (!mrq->data->error)
483 mrq->data->error = -EIO;
484 }
San Mehat9d2bd732009-09-22 16:44:22 -0700485 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
486 host->dma.dir);
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 if (host->curr.user_pages) {
489 struct scatterlist *sg = host->dma.sg;
490 int i;
491
492 for (i = 0; i < host->dma.num_ents; i++, sg++)
493 flush_dcache_page(sg_page(sg));
494 }
495
San Mehat9d2bd732009-09-22 16:44:22 -0700496 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800497 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700498
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530499 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
500 (host->curr.wait_for_auto_prog_done &&
501 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700502 /*
503 * If we've already gotten our DATAEND / DATABLKEND
504 * for this request, then complete it through here.
505 */
San Mehat9d2bd732009-09-22 16:44:22 -0700506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700508 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 host->curr.xfer_remain -= host->curr.xfer_size;
510 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700511 if (host->dummy_52_needed) {
512 mrq->data->bytes_xfered = host->curr.data_xfered;
513 host->dummy_52_sent = 1;
514 msmsdcc_start_command(host, &dummy52cmd,
515 MCI_CPSM_PROGENA);
516 goto out;
517 }
518 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530519 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530520 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700521 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530523 /*
524 * Clear current request information as current
525 * request has ended
526 */
527 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700528 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529
San Mehat9d2bd732009-09-22 16:44:22 -0700530 mmc_request_done(host->mmc, mrq);
531 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530532 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
533 || !mrq->sbc)) {
534 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530535 }
San Mehat9d2bd732009-09-22 16:44:22 -0700536 }
537
538out:
539 spin_unlock_irqrestore(&host->lock, flags);
540 return;
541}
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
544/**
545 * Callback notification from SPS driver
546 *
547 * This callback function gets triggered called from
548 * SPS driver when requested SPS data transfer is
549 * completed.
550 *
551 * SPS driver invokes this callback in BAM irq context so
552 * SDCC driver schedule a tasklet for further processing
553 * this callback notification at later point of time in
554 * tasklet context and immediately returns control back
555 * to SPS driver.
556 *
557 * @nofity - Pointer to sps event notify sturcture
558 *
559 */
560static void
561msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
562{
563 struct msmsdcc_host *host =
564 (struct msmsdcc_host *)
565 ((struct sps_event_notify *)notify)->user;
566
567 host->sps.notify = *notify;
568 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
569 mmc_hostname(host->mmc), __func__, notify->event_id,
570 notify->data.transfer.iovec.addr,
571 notify->data.transfer.iovec.size,
572 notify->data.transfer.iovec.flags);
573 /* Schedule a tasklet for completing data transfer */
574 tasklet_schedule(&host->sps.tlet);
575}
576
577/**
578 * Tasklet handler for processing SPS callback event
579 *
580 * This function processing SPS event notification and
581 * checks if the SPS transfer is completed or not and
582 * then accordingly notifies status to MMC core layer.
583 *
584 * This function is called in tasklet context.
585 *
586 * @data - Pointer to sdcc driver data
587 *
588 */
589static void msmsdcc_sps_complete_tlet(unsigned long data)
590{
591 unsigned long flags;
592 int i, rc;
593 u32 data_xfered = 0;
594 struct mmc_request *mrq;
595 struct sps_iovec iovec;
596 struct sps_pipe *sps_pipe_handle;
597 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
598 struct sps_event_notify *notify = &host->sps.notify;
599
600 spin_lock_irqsave(&host->lock, flags);
601 if (host->sps.dir == DMA_FROM_DEVICE)
602 sps_pipe_handle = host->sps.prod.pipe_handle;
603 else
604 sps_pipe_handle = host->sps.cons.pipe_handle;
605 mrq = host->curr.mrq;
606
607 if (!mrq) {
608 spin_unlock_irqrestore(&host->lock, flags);
609 return;
610 }
611
612 pr_debug("%s: %s: sps event_id=%d\n",
613 mmc_hostname(host->mmc), __func__,
614 notify->event_id);
615
616 if (msmsdcc_is_dml_busy(host)) {
617 /* oops !!! this should never happen. */
618 pr_err("%s: %s: Received SPS EOT event"
619 " but DML HW is still busy !!!\n",
620 mmc_hostname(host->mmc), __func__);
621 }
622 /*
623 * Got End of transfer event!!! Check if all of the data
624 * has been transferred?
625 */
626 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
627 rc = sps_get_iovec(sps_pipe_handle, &iovec);
628 if (rc) {
629 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
630 mmc_hostname(host->mmc), __func__, rc, i);
631 break;
632 }
633 data_xfered += iovec.size;
634 }
635
636 if (data_xfered == host->curr.xfer_size) {
637 host->curr.data_xfered = host->curr.xfer_size;
638 host->curr.xfer_remain -= host->curr.xfer_size;
639 pr_debug("%s: Data xfer success. data_xfered=0x%x",
640 mmc_hostname(host->mmc),
641 host->curr.xfer_size);
642 } else {
643 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
644 " xfer_size=%d", mmc_hostname(host->mmc),
645 data_xfered, host->curr.xfer_size);
646 msmsdcc_reset_and_restore(host);
647 if (!mrq->data->error)
648 mrq->data->error = -EIO;
649 }
650
651 /* Unmap sg buffers */
652 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
653 host->sps.dir);
654
655 host->sps.sg = NULL;
656 host->sps.busy = 0;
657
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530658 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
659 (host->curr.wait_for_auto_prog_done &&
660 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 /*
662 * If we've already gotten our DATAEND / DATABLKEND
663 * for this request, then complete it through here.
664 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665
666 if (!mrq->data->error) {
667 host->curr.data_xfered = host->curr.xfer_size;
668 host->curr.xfer_remain -= host->curr.xfer_size;
669 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700670 if (host->dummy_52_needed) {
671 mrq->data->bytes_xfered = host->curr.data_xfered;
672 host->dummy_52_sent = 1;
673 msmsdcc_start_command(host, &dummy52cmd,
674 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700675 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700676 return;
677 }
678 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530679 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530680 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 mrq->data->bytes_xfered = host->curr.data_xfered;
682 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530683 /*
684 * Clear current request information as current
685 * request has ended
686 */
687 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 spin_unlock_irqrestore(&host->lock, flags);
689
690 mmc_request_done(host->mmc, mrq);
691 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530692 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
693 || !mrq->sbc)) {
694 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 }
696 }
697 spin_unlock_irqrestore(&host->lock, flags);
698}
699
700/**
701 * Exit from current SPS data transfer
702 *
703 * This function exits from current SPS data transfer.
704 *
705 * This function should be called when error condition
706 * is encountered during data transfer.
707 *
708 * @host - Pointer to sdcc host structure
709 *
710 */
711static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
712{
713 struct mmc_request *mrq;
714
715 mrq = host->curr.mrq;
716 BUG_ON(!mrq);
717
718 msmsdcc_reset_and_restore(host);
719 if (!mrq->data->error)
720 mrq->data->error = -EIO;
721
722 /* Unmap sg buffers */
723 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
724 host->sps.dir);
725
726 host->sps.sg = NULL;
727 host->sps.busy = 0;
728 if (host->curr.data)
729 msmsdcc_stop_data(host);
730
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530731 if (!mrq->data->stop || mrq->cmd->error ||
732 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530734 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
735 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 msmsdcc_start_command(host, mrq->data->stop, 0);
737
738}
739#else
740static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
741static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
742static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
743#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
744
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530745static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530747static void
748msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
749 unsigned int result,
750 struct msm_dmov_errdata *err)
751{
752 struct msmsdcc_dma_data *dma_data =
753 container_of(cmd, struct msmsdcc_dma_data, hdr);
754 struct msmsdcc_host *host = dma_data->host;
755
756 dma_data->result = result;
757 if (err)
758 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
759
760 tasklet_schedule(&host->dma_tlet);
761}
762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700764{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
766 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700767 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 else
769 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700770}
771
772static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
773{
774 struct msmsdcc_nc_dmadata *nc;
775 dmov_box *box;
776 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700777 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530778 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700779 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530780 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700781
Krishna Konda25786ec2011-07-25 16:21:36 -0700782 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700784
Krishna Konda25786ec2011-07-25 16:21:36 -0700785 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
786
San Mehat9d2bd732009-09-22 16:44:22 -0700787 host->dma.sg = data->sg;
788 host->dma.num_ents = data->sg_len;
789
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530790 /* Prevent memory corruption */
791 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800792
San Mehat9d2bd732009-09-22 16:44:22 -0700793 nc = host->dma.nc;
794
San Mehat9d2bd732009-09-22 16:44:22 -0700795 if (data->flags & MMC_DATA_READ)
796 host->dma.dir = DMA_FROM_DEVICE;
797 else
798 host->dma.dir = DMA_TO_DEVICE;
799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
801 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802
803 if (n != host->dma.num_ents) {
804 pr_err("%s: Unable to map in all sg elements\n",
805 mmc_hostname(host->mmc));
806 host->dma.sg = NULL;
807 host->dma.num_ents = 0;
808 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800809 }
San Mehat9d2bd732009-09-22 16:44:22 -0700810
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530811 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
812 host->curr.user_pages = 0;
813 box = &nc->cmd[0];
814 for (i = 0; i < host->dma.num_ents; i++) {
815 len = sg_dma_len(sg);
816 offset = 0;
817
818 do {
819 /* Check if we can do DMA */
820 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
821 err = -ENOTSUPP;
822 goto unmap;
823 }
824
825 box->cmd = CMD_MODE_BOX;
826
827 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
828 len = MMC_MAX_DMA_BOX_LENGTH;
829 len -= len % data->blksz;
830 }
831 rows = (len % MCI_FIFOSIZE) ?
832 (len / MCI_FIFOSIZE) + 1 :
833 (len / MCI_FIFOSIZE);
834
835 if (data->flags & MMC_DATA_READ) {
836 box->src_row_addr = msmsdcc_fifo_addr(host);
837 box->dst_row_addr = sg_dma_address(sg) + offset;
838 box->src_dst_len = (MCI_FIFOSIZE << 16) |
839 (MCI_FIFOSIZE);
840 box->row_offset = MCI_FIFOSIZE;
841 box->num_rows = rows * ((1 << 16) + 1);
842 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
843 } else {
844 box->src_row_addr = sg_dma_address(sg) + offset;
845 box->dst_row_addr = msmsdcc_fifo_addr(host);
846 box->src_dst_len = (MCI_FIFOSIZE << 16) |
847 (MCI_FIFOSIZE);
848 box->row_offset = (MCI_FIFOSIZE << 16);
849 box->num_rows = rows * ((1 << 16) + 1);
850 box->cmd |= CMD_DST_CRCI(host->dma.crci);
851 }
852
853 offset += len;
854 len = sg_dma_len(sg) - offset;
855 box++;
856 box_cmd_cnt++;
857 } while (len);
858 sg++;
859 }
860 /* Mark last command */
861 box--;
862 box->cmd |= CMD_LC;
863
864 /* location of command block must be 64 bit aligned */
865 BUG_ON(host->dma.cmd_busaddr & 0x07);
866
867 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
868 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
869 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
870 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
871
872 /* Flush all data to memory before starting dma */
873 mb();
874
875unmap:
876 if (err) {
877 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
878 host->dma.num_ents, host->dma.dir);
879 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
880 mmc_hostname(host->mmc), err);
881 }
882
883 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700884}
885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
887/**
888 * Submits data transfer request to SPS driver
889 *
890 * This function make sg (scatter gather) data buffers
891 * DMA ready and then submits them to SPS driver for
892 * transfer.
893 *
894 * @host - Pointer to sdcc host structure
895 * @data - Pointer to mmc_data structure
896 *
897 * @return 0 if success else negative value
898 */
899static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
900 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800901{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 int rc = 0;
903 u32 flags;
904 int i;
905 u32 addr, len, data_cnt;
906 struct scatterlist *sg = data->sg;
907 struct sps_pipe *sps_pipe_handle;
908
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530909 /* Prevent memory corruption */
910 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911
912 host->sps.sg = data->sg;
913 host->sps.num_ents = data->sg_len;
914 host->sps.xfer_req_cnt = 0;
915 if (data->flags & MMC_DATA_READ) {
916 host->sps.dir = DMA_FROM_DEVICE;
917 sps_pipe_handle = host->sps.prod.pipe_handle;
918 } else {
919 host->sps.dir = DMA_TO_DEVICE;
920 sps_pipe_handle = host->sps.cons.pipe_handle;
921 }
922
923 /* Make sg buffers DMA ready */
924 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
925 host->sps.dir);
926
927 if (rc != data->sg_len) {
928 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
929 mmc_hostname(host->mmc), rc);
930 host->sps.sg = NULL;
931 host->sps.num_ents = 0;
932 rc = -ENOMEM;
933 goto dma_map_err;
934 }
935
936 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
937 mmc_hostname(host->mmc), __func__,
938 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
939 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
940
941 for (i = 0; i < data->sg_len; i++) {
942 /*
943 * Check if this is the last buffer to transfer?
944 * If yes then set the INT and EOT flags.
945 */
946 len = sg_dma_len(sg);
947 addr = sg_dma_address(sg);
948 flags = 0;
949 while (len > 0) {
950 if (len > SPS_MAX_DESC_SIZE) {
951 data_cnt = SPS_MAX_DESC_SIZE;
952 } else {
953 data_cnt = len;
954 if (i == data->sg_len - 1)
955 flags = SPS_IOVEC_FLAG_INT |
956 SPS_IOVEC_FLAG_EOT;
957 }
958 rc = sps_transfer_one(sps_pipe_handle, addr,
959 data_cnt, host, flags);
960 if (rc) {
961 pr_err("%s: sps_transfer_one() error! rc=%d,"
962 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
963 mmc_hostname(host->mmc), rc,
964 (u32)sps_pipe_handle, (u32)sg, i);
965 goto dma_map_err;
966 }
967 addr += data_cnt;
968 len -= data_cnt;
969 host->sps.xfer_req_cnt++;
970 }
971 sg++;
972 }
973 goto out;
974
975dma_map_err:
976 /* unmap sg buffers */
977 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
978 host->sps.dir);
979out:
980 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700981}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982#else
983static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
984 struct mmc_data *data) { return 0; }
985#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700986
987static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800988msmsdcc_start_command_deferred(struct msmsdcc_host *host,
989 struct mmc_command *cmd, u32 *c)
990{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530991 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 cmd->opcode, cmd->arg, cmd->flags);
993
San Mehat56a8b5b2009-11-21 12:29:46 -0800994 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
995
996 if (cmd->flags & MMC_RSP_PRESENT) {
997 if (cmd->flags & MMC_RSP_136)
998 *c |= MCI_CPSM_LONGRSP;
999 *c |= MCI_CPSM_RESPONSE;
1000 }
1001
1002 if (/*interrupt*/0)
1003 *c |= MCI_CPSM_INTERRUPT;
1004
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301005 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1006 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
1007 cmd->opcode == MMC_WRITE_BLOCK ||
1008 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
1009 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -08001010 *c |= MCI_CSPM_DATCMD;
1011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301013 if (host->tuning_needed &&
1014 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1015
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301016 /*
1017 * For open ended block read operation (without CMD23),
1018 * AUTO_CMD19 bit should be set while sending the READ command.
1019 * For close ended block read operation (with CMD23),
1020 * AUTO_CMD19 bit should be set while sending CMD23.
1021 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301022 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1023 host->curr.mrq->cmd->opcode ==
1024 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301025 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301026 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1027 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301028 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1029 *c |= MCI_CSPM_AUTO_CMD19;
1030 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 }
1032
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301033 /* Clear CDR_EN bit for write operations */
1034 if (host->tuning_needed && cmd->mrq->data &&
1035 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1036 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1037 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1038
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301039 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301040 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301042 }
1043
San Mehat56a8b5b2009-11-21 12:29:46 -08001044 if (cmd == cmd->mrq->stop)
1045 *c |= MCI_CSPM_MCIABORT;
1046
San Mehat56a8b5b2009-11-21 12:29:46 -08001047 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 pr_err("%s: Overlapping command requests\n",
1049 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001050 }
1051 host->curr.cmd = cmd;
1052}
1053
1054static void
1055msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1056 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001057{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301058 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001059 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001061 unsigned int pio_irqmask = 0;
1062
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301063 BUG_ON(!data->sg);
1064 BUG_ON(!data->sg_len);
1065
San Mehat9d2bd732009-09-22 16:44:22 -07001066 host->curr.data = data;
1067 host->curr.xfer_size = data->blksz * data->blocks;
1068 host->curr.xfer_remain = host->curr.xfer_size;
1069 host->curr.data_xfered = 0;
1070 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301071 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001072
San Mehat9d2bd732009-09-22 16:44:22 -07001073 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1074
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301075 if (host->curr.wait_for_auto_prog_done)
1076 datactrl |= MCI_AUTO_PROG_DONE;
1077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 if (!msmsdcc_check_dma_op_req(data)) {
1079 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1080 datactrl |= MCI_DPSM_DMAENABLE;
1081 } else if (host->is_sps_mode) {
1082 if (!msmsdcc_is_dml_busy(host)) {
1083 if (!msmsdcc_sps_start_xfer(host, data)) {
1084 /* Now kick start DML transfer */
1085 mb();
1086 msmsdcc_dml_start_xfer(host, data);
1087 datactrl |= MCI_DPSM_DMAENABLE;
1088 host->sps.busy = 1;
1089 }
1090 } else {
1091 /*
1092 * Can't proceed with new transfer as
1093 * previous trasnfer is already in progress.
1094 * There is no point of going into PIO mode
1095 * as well. Is this a time to do kernel panic?
1096 */
1097 pr_err("%s: %s: DML HW is busy!!!"
1098 " Can't perform new SPS transfers"
1099 " now\n", mmc_hostname(host->mmc),
1100 __func__);
1101 }
1102 }
1103 }
1104
1105 /* Is data transfer in PIO mode required? */
1106 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001107 if (data->flags & MMC_DATA_READ) {
1108 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1109 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1110 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001111 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1113 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001114
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001115 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001116 }
1117
1118 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301119 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001120
San Mehat56a8b5b2009-11-21 12:29:46 -08001121 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001123 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1126 /* Use ADM (Application Data Mover) HW for Data transfer */
1127 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001128 host->cmd_timeout = timeout;
1129 host->cmd_pio_irqmask = pio_irqmask;
1130 host->cmd_datactrl = datactrl;
1131 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1134 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001135 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001136
1137 if (cmd) {
1138 msmsdcc_start_command_deferred(host, cmd, &c);
1139 host->cmd_c = c;
1140 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1142 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1143 host->base + MMCIMASK0);
1144 mb();
1145 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001146 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1153 (~(MCI_IRQ_PIO))) | pio_irqmask,
1154 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001156
1157 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301158 /* Delay between data/command */
1159 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001160 /* Daisy-chain the command if requested */
1161 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301162 } else {
1163 /*
1164 * We don't need delay after writing to DATA_CTRL
1165 * register if we are not writing to CMD register
1166 * immediately after this. As we already have delay
1167 * before sending the command, we just need mb() here.
1168 */
1169 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001170 }
San Mehat9d2bd732009-09-22 16:44:22 -07001171 }
1172}
1173
1174static void
1175msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1176{
San Mehat56a8b5b2009-11-21 12:29:46 -08001177 msmsdcc_start_command_deferred(host, cmd, &c);
1178 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001179}
1180
1181static void
1182msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1183 unsigned int status)
1184{
1185 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301187 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1188 || data->mrq->cmd->opcode ==
1189 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 pr_err("%s: Data CRC error\n",
1191 mmc_hostname(host->mmc));
1192 pr_err("%s: opcode 0x%.8x\n", __func__,
1193 data->mrq->cmd->opcode);
1194 pr_err("%s: blksz %d, blocks %d\n", __func__,
1195 data->blksz, data->blocks);
1196 data->error = -EILSEQ;
1197 }
San Mehat9d2bd732009-09-22 16:44:22 -07001198 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 /* CRC is optional for the bus test commands, not all
1200 * cards respond back with CRC. However controller
1201 * waits for the CRC and times out. Hence ignore the
1202 * data timeouts during the Bustest.
1203 */
1204 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1205 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301206 pr_err("%s: CMD%d: Data timeout\n",
1207 mmc_hostname(host->mmc),
1208 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301210 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 }
San Mehat9d2bd732009-09-22 16:44:22 -07001212 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001213 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001214 data->error = -EIO;
1215 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001216 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001217 data->error = -EIO;
1218 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001219 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001221 data->error = -EIO;
1222 }
San Mehat9d2bd732009-09-22 16:44:22 -07001223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001225 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 host->dummy_52_needed = 0;
1227}
San Mehat9d2bd732009-09-22 16:44:22 -07001228
1229static int
1230msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1231{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001233 uint32_t *ptr = (uint32_t *) buffer;
1234 int count = 0;
1235
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301236 if (remain % 4)
1237 remain = ((remain >> 2) + 1) << 2;
1238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1240
1241 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001242 ptr++;
1243 count += sizeof(uint32_t);
1244
1245 remain -= sizeof(uint32_t);
1246 if (remain == 0)
1247 break;
1248 }
1249 return count;
1250}
1251
1252static int
1253msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001255{
1256 void __iomem *base = host->base;
1257 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 while (readl_relaxed(base + MMCISTATUS) &
1261 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1262 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001263
San Mehat9d2bd732009-09-22 16:44:22 -07001264 count = min(remain, maxcnt);
1265
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301266 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1267 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001268 ptr += count;
1269 remain -= count;
1270
1271 if (remain == 0)
1272 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 }
1274 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001275
1276 return ptr - buffer;
1277}
1278
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001279/*
1280 * Copy up to a word (4 bytes) between a scatterlist
1281 * and a temporary bounce buffer when the word lies across
1282 * two pages. The temporary buffer can then be read to/
1283 * written from the FIFO once.
1284 */
1285static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1286{
1287 struct msmsdcc_pio_data *pio = &host->pio;
1288 unsigned int bytes_avail;
1289
1290 if (host->curr.data->flags & MMC_DATA_READ)
1291 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1292 pio->bounce_buf_len);
1293 else
1294 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1295 pio->bounce_buf_len);
1296
1297 while (pio->bounce_buf_len != 4) {
1298 if (!sg_miter_next(&pio->sg_miter))
1299 break;
1300 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1301 4 - pio->bounce_buf_len);
1302 if (host->curr.data->flags & MMC_DATA_READ)
1303 memcpy(pio->sg_miter.addr,
1304 &pio->bounce_buf[pio->bounce_buf_len],
1305 bytes_avail);
1306 else
1307 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1308 pio->sg_miter.addr, bytes_avail);
1309
1310 pio->sg_miter.consumed = bytes_avail;
1311 pio->bounce_buf_len += bytes_avail;
1312 }
1313}
1314
1315/*
1316 * Use sg_miter_next to return as many 4-byte aligned
1317 * chunks as possible, using a temporary 4 byte buffer
1318 * for alignment if necessary
1319 */
1320static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1321{
1322 struct msmsdcc_pio_data *pio = &host->pio;
1323 unsigned int length, rlength;
1324 char *buffer;
1325
1326 if (!sg_miter_next(&pio->sg_miter))
1327 return 0;
1328
1329 buffer = pio->sg_miter.addr;
1330 length = pio->sg_miter.length;
1331
1332 if (length < host->curr.xfer_remain) {
1333 rlength = round_down(length, 4);
1334 if (rlength) {
1335 /*
1336 * We have a 4-byte aligned chunk.
1337 * The rounding will be reflected by
1338 * a call to msmsdcc_sg_consumed
1339 */
1340 length = rlength;
1341 goto sg_next_end;
1342 }
1343 /*
1344 * We have a length less than 4 bytes. Check to
1345 * see if more buffer is available, and combine
1346 * to make 4 bytes if possible.
1347 */
1348 pio->bounce_buf_len = length;
1349 memset(pio->bounce_buf, 0, 4);
1350
1351 /*
1352 * On a read, get 4 bytes from FIFO, and distribute
1353 * (4-bouce_buf_len) bytes into consecutive
1354 * sgl buffers when msmsdcc_sg_consumed is called
1355 */
1356 if (host->curr.data->flags & MMC_DATA_READ) {
1357 buffer = pio->bounce_buf;
1358 length = 4;
1359 goto sg_next_end;
1360 } else {
1361 _msmsdcc_sg_consume_word(host);
1362 buffer = pio->bounce_buf;
1363 length = pio->bounce_buf_len;
1364 }
1365 }
1366
1367sg_next_end:
1368 *buf = buffer;
1369 *len = length;
1370 return 1;
1371}
1372
1373/*
1374 * Update sg_miter.consumed based on how many bytes were
1375 * consumed. If the bounce buffer was used to read from FIFO,
1376 * redistribute into sgls.
1377 */
1378static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1379 unsigned int length)
1380{
1381 struct msmsdcc_pio_data *pio = &host->pio;
1382
1383 if (host->curr.data->flags & MMC_DATA_READ) {
1384 if (length > pio->sg_miter.consumed)
1385 /*
1386 * consumed 4 bytes, but sgl
1387 * describes < 4 bytes
1388 */
1389 _msmsdcc_sg_consume_word(host);
1390 else
1391 pio->sg_miter.consumed = length;
1392 } else
1393 if (length < pio->sg_miter.consumed)
1394 pio->sg_miter.consumed = length;
1395}
1396
1397static void msmsdcc_sg_start(struct msmsdcc_host *host)
1398{
1399 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1400
1401 host->pio.bounce_buf_len = 0;
1402
1403 if (host->curr.data->flags & MMC_DATA_READ)
1404 sg_miter_flags |= SG_MITER_TO_SG;
1405 else
1406 sg_miter_flags |= SG_MITER_FROM_SG;
1407
1408 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1409 host->curr.data->sg_len, sg_miter_flags);
1410}
1411
1412static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1413{
1414 sg_miter_stop(&host->pio.sg_miter);
1415}
1416
San Mehat1cd22962010-02-03 12:59:29 -08001417static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001418msmsdcc_pio_irq(int irq, void *dev_id)
1419{
1420 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001422 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001423 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001424 unsigned int remain;
1425 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001426
Murali Palnati36448a42011-09-02 15:06:18 +05301427 spin_lock(&host->lock);
1428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301432 (MCI_IRQ_PIO)) == 0) {
1433 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301435 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436#if IRQ_DEBUG
1437 msmsdcc_print_status(host, "irq1-r", status);
1438#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001439 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001441 do {
1442 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1445 | MCI_RXDATAAVLBL)))
1446 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001447
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001448 if (!msmsdcc_sg_next(host, &buffer, &remain))
1449 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450
San Mehat9d2bd732009-09-22 16:44:22 -07001451 len = 0;
1452 if (status & MCI_RXACTIVE)
1453 len = msmsdcc_pio_read(host, buffer, remain);
1454 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001456
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301457 /* len might have aligned to 32bits above */
1458 if (len > remain)
1459 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001460
San Mehat9d2bd732009-09-22 16:44:22 -07001461 host->curr.xfer_remain -= len;
1462 host->curr.data_xfered += len;
1463 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001464 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 if (remain) /* Done with this page? */
1467 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001470 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001471
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001472 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001473 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1476 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1477 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1478 host->base + MMCIMASK0);
1479 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301480 /*
1481 * back to back write to MASK0 register don't need
1482 * synchronization delay.
1483 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1485 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1486 }
1487 mb();
1488 } else if (!host->curr.xfer_remain) {
1489 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1490 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1491 mb();
1492 }
San Mehat9d2bd732009-09-22 16:44:22 -07001493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001495
1496 return IRQ_HANDLED;
1497}
1498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499static void
1500msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1501
1502static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1503 struct mmc_data *data)
1504{
1505 u32 loop_cnt = 0;
1506
1507 /*
1508 * For read commands with data less than fifo size, it is possible to
1509 * get DATAEND first and RXDATA_AVAIL might be set later because of
1510 * synchronization delay through the asynchronous RX FIFO. Thus, for
1511 * such cases, even after DATAEND interrupt is received software
1512 * should poll for RXDATA_AVAIL until the requested data is read out
1513 * of FIFO. This change is needed to get around this abnormal but
1514 * sometimes expected behavior of SDCC3 controller.
1515 *
1516 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1517 * after the data is loaded into RX FIFO. This would amount to less
1518 * than a microsecond and thus looping for 1000 times is good enough
1519 * for that delay.
1520 */
1521 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1522 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1523 spin_unlock(&host->lock);
1524 msmsdcc_pio_irq(1, host);
1525 spin_lock(&host->lock);
1526 }
1527 }
1528 if (loop_cnt == 1000) {
1529 pr_info("%s: Timed out while polling for Rx Data\n",
1530 mmc_hostname(host->mmc));
1531 data->error = -ETIMEDOUT;
1532 msmsdcc_reset_and_restore(host);
1533 }
1534}
1535
San Mehat9d2bd732009-09-22 16:44:22 -07001536static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1537{
1538 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001539
1540 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1542 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1543 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1544 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301547 pr_debug("%s: CMD%d: Command timeout\n",
1548 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001549 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301551 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301552 pr_err("%s: CMD%d: Command CRC error\n",
1553 mmc_hostname(host->mmc), cmd->opcode);
1554 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001555 cmd->error = -EILSEQ;
1556 }
1557
1558 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 if (host->curr.data && host->dma.sg &&
1560 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001561 msm_dmov_stop_cmd(host->dma.channel,
1562 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 else if (host->curr.data && host->sps.sg &&
1564 host->is_sps_mode){
1565 /* Stop current SPS transfer */
1566 msmsdcc_sps_exit_curr_xfer(host);
1567 }
San Mehat9d2bd732009-09-22 16:44:22 -07001568 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301569 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001570 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301571 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301572 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301573 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301574 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301576 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301578 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301579 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301580 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301581 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001582 if (host->dummy_52_needed)
1583 host->dummy_52_needed = 0;
1584 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301586 msmsdcc_request_end(host, cmd->mrq);
1587 }
1588 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301589 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1590 if (cmd->data->flags & MMC_DATA_READ)
1591 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1592 else
1593 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301594 } else if (cmd->data) {
1595 if (!(cmd->data->flags & MMC_DATA_READ))
1596 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001597 }
1598}
1599
San Mehat9d2bd732009-09-22 16:44:22 -07001600static irqreturn_t
1601msmsdcc_irq(int irq, void *dev_id)
1602{
1603 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001604 u32 status;
1605 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001607
1608 spin_lock(&host->lock);
1609
1610 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 struct mmc_command *cmd;
1612 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 if (timer) {
1615 timer = 0;
1616 msmsdcc_delay(host);
1617 }
San Mehat865c8062009-11-13 13:42:06 -08001618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 if (!host->clks_on) {
1620 pr_debug("%s: %s: SDIO async irq received\n",
1621 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301622
1623 /*
1624 * Only async interrupt can come when clocks are off,
1625 * disable further interrupts and enable them when
1626 * clocks are on.
1627 */
1628 if (!host->sdcc_irq_disabled) {
1629 disable_irq_nosync(irq);
1630 host->sdcc_irq_disabled = 1;
1631 }
1632
1633 /*
1634 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1635 * will take care of signaling sdio irq during
1636 * mmc_sdio_resume().
1637 */
1638 if (host->sdcc_suspended)
1639 /*
1640 * This is a wakeup interrupt so hold wakelock
1641 * until SDCC resume is handled.
1642 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301644 else
1645 mmc_signal_sdio_irq(host->mmc);
1646 ret = 1;
1647 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 }
1649
1650 status = readl_relaxed(host->base + MMCISTATUS);
1651
1652 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1653 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001654 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656#if IRQ_DEBUG
1657 msmsdcc_print_status(host, "irq0-r", status);
1658#endif
1659 status &= readl_relaxed(host->base + MMCIMASK0);
1660 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301661 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301662 if (host->clk_rate <=
1663 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301664 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665#if IRQ_DEBUG
1666 msmsdcc_print_status(host, "irq0-p", status);
1667#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1670 if (status & MCI_SDIOINTROPE) {
1671 if (host->sdcc_suspending)
1672 wake_lock(&host->sdio_suspend_wlock);
1673 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001674 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001676 data = host->curr.data;
1677
1678 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1680 MCI_CMDTIMEOUT)) {
1681 if (status & MCI_CMDTIMEOUT)
1682 pr_debug("%s: dummy CMD52 timeout\n",
1683 mmc_hostname(host->mmc));
1684 if (status & MCI_CMDCRCFAIL)
1685 pr_debug("%s: dummy CMD52 CRC failed\n",
1686 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001687 host->dummy_52_sent = 0;
1688 host->dummy_52_needed = 0;
1689 if (data) {
1690 msmsdcc_stop_data(host);
1691 msmsdcc_request_end(host, data->mrq);
1692 }
1693 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 spin_unlock(&host->lock);
1695 return IRQ_HANDLED;
1696 }
1697 break;
1698 }
1699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 /*
1701 * Check for proper command response
1702 */
1703 cmd = host->curr.cmd;
1704 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1705 MCI_CMDTIMEOUT | MCI_PROGDONE |
1706 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1707 msmsdcc_do_cmdirq(host, status);
1708 }
1709
Sathish Ambley081d7842011-11-29 11:19:41 -08001710 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 /* Check for data errors */
1712 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1713 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1714 msmsdcc_data_err(host, data, status);
1715 host->curr.data_xfered = 0;
1716 if (host->dma.sg && host->is_dma_mode)
1717 msm_dmov_stop_cmd(host->dma.channel,
1718 &host->dma.hdr, 0);
1719 else if (host->sps.sg && host->is_sps_mode) {
1720 /* Stop current SPS transfer */
1721 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301722 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 msmsdcc_reset_and_restore(host);
1724 if (host->curr.data)
1725 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301726 if (!data->stop || (host->curr.mrq->sbc
1727 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 timer |=
1729 msmsdcc_request_end(host,
1730 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301731 else if ((host->curr.mrq->sbc
1732 && data->error) ||
1733 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 msmsdcc_start_command(host,
1735 data->stop,
1736 0);
1737 timer = 1;
1738 }
1739 }
1740 }
1741
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301742 /* Check for prog done */
1743 if (host->curr.wait_for_auto_prog_done &&
1744 (status & MCI_PROGDONE))
1745 host->curr.got_auto_prog_done = 1;
1746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 /* Check for data done */
1748 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1749 host->curr.got_dataend = 1;
1750
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301751 if (host->curr.got_dataend &&
1752 (!host->curr.wait_for_auto_prog_done ||
1753 (host->curr.wait_for_auto_prog_done &&
1754 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 /*
1756 * If DMA is still in progress, we complete
1757 * via the completion handler
1758 */
1759 if (!host->dma.busy && !host->sps.busy) {
1760 /*
1761 * There appears to be an issue in the
1762 * controller where if you request a
1763 * small block transfer (< fifo size),
1764 * you may get your DATAEND/DATABLKEND
1765 * irq without the PIO data irq.
1766 *
1767 * Check to see if theres still data
1768 * to be read, and simulate a PIO irq.
1769 */
1770 if (data->flags & MMC_DATA_READ)
1771 msmsdcc_wait_for_rxdata(host,
1772 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 if (!data->error) {
1774 host->curr.data_xfered =
1775 host->curr.xfer_size;
1776 host->curr.xfer_remain -=
1777 host->curr.xfer_size;
1778 }
1779
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001780 if (!host->dummy_52_needed) {
1781 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301782 if (!data->stop ||
1783 (host->curr.mrq->sbc
1784 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001785 msmsdcc_request_end(
1786 host,
1787 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301788 else if ((host->curr.mrq->sbc
1789 && data->error) ||
1790 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001791 msmsdcc_start_command(
1792 host,
1793 data->stop, 0);
1794 timer = 1;
1795 }
1796 } else {
1797 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001799 &dummy52cmd,
1800 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 }
1802 }
1803 }
1804 }
1805
San Mehat9d2bd732009-09-22 16:44:22 -07001806 ret = 1;
1807 } while (status);
1808
1809 spin_unlock(&host->lock);
1810
San Mehat9d2bd732009-09-22 16:44:22 -07001811 return IRQ_RETVAL(ret);
1812}
1813
1814static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1816{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301817 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301819 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301820 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1821 else
1822 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 } else {
1824 msmsdcc_start_command(host, mrq->cmd, 0);
1825 }
1826}
1827
1828static void
San Mehat9d2bd732009-09-22 16:44:22 -07001829msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1830{
1831 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 /*
1835 * Get the SDIO AL client out of LPM.
1836 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001837 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838 if (host->plat->is_sdio_al_client)
1839 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001840
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301841 /* check if sps pipe reset is pending? */
1842 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1843 msmsdcc_sps_pipes_reset_and_restore(host);
1844 host->sps.pipe_reset_pending = false;
1845 }
1846
San Mehat9d2bd732009-09-22 16:44:22 -07001847 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 WARN(host->curr.mrq, "Request in progress\n");
1849 WARN(!host->pwr, "SDCC power is turned off\n");
1850 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1851 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001852
1853 if (host->eject) {
1854 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1855 mrq->cmd->error = 0;
1856 mrq->data->bytes_xfered = mrq->data->blksz *
1857 mrq->data->blocks;
1858 } else
1859 mrq->cmd->error = -ENOMEDIUM;
1860
1861 spin_unlock_irqrestore(&host->lock, flags);
1862 mmc_request_done(mmc, mrq);
1863 return;
1864 }
1865
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301866 /*
1867 * Kick the software command timeout timer here.
1868 * Timer expires in 10 secs.
1869 */
1870 mod_timer(&host->req_tout_timer,
1871 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001872
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301873 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301874 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301875 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1876 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301877 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301879 else
1880 /*
1881 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1882 * write operations using CMD53 and CMD54.
1883 * Setting this bit with CMD53 would
1884 * automatically triggers PROG_DONE interrupt
1885 * without the need of sending dummy CMD52.
1886 */
1887 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301888 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1889 host->sdcc_version) {
1890 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891 }
San Mehat9d2bd732009-09-22 16:44:22 -07001892 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301893
Pratibhasagar V00b94332011-10-18 14:57:27 +05301894 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301895 mrq->sbc->mrq = mrq;
1896 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301897 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301898 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301899 msmsdcc_start_command(host, mrq->sbc, 0);
1900 } else {
1901 msmsdcc_request_start(host, mrq);
1902 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301903 } else {
1904 msmsdcc_request_start(host, mrq);
1905 }
1906
San Mehat9d2bd732009-09-22 16:44:22 -07001907 spin_unlock_irqrestore(&host->lock, flags);
1908}
1909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1911 int min_uV, int max_uV)
1912{
1913 int rc = 0;
1914
1915 if (vreg->set_voltage_sup) {
1916 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1917 if (rc) {
1918 pr_err("%s: regulator_set_voltage(%s) failed."
1919 " min_uV=%d, max_uV=%d, rc=%d\n",
1920 __func__, vreg->name, min_uV, max_uV, rc);
1921 }
1922 }
1923
1924 return rc;
1925}
1926
1927static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1928 int uA_load)
1929{
1930 int rc = 0;
1931
Krishna Kondafea60182011-11-01 16:01:34 -07001932 /* regulators that do not support regulator_set_voltage also
1933 do not support regulator_set_optimum_mode */
1934 if (vreg->set_voltage_sup) {
1935 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1936 if (rc < 0)
1937 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1938 "uA_load=%d) failed. rc=%d\n", __func__,
1939 vreg->name, uA_load, rc);
1940 else
1941 /* regulator_set_optimum_mode() can return non zero
1942 * value even for success case.
1943 */
1944 rc = 0;
1945 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946
1947 return rc;
1948}
1949
1950static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1951 struct device *dev)
1952{
1953 int rc = 0;
1954
1955 /* check if regulator is already initialized? */
1956 if (vreg->reg)
1957 goto out;
1958
1959 /* Get the regulator handle */
1960 vreg->reg = regulator_get(dev, vreg->name);
1961 if (IS_ERR(vreg->reg)) {
1962 rc = PTR_ERR(vreg->reg);
1963 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1964 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001965 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001967
1968 if (regulator_count_voltages(vreg->reg) > 0)
1969 vreg->set_voltage_sup = 1;
1970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971out:
1972 return rc;
1973}
1974
1975static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1976{
1977 if (vreg->reg)
1978 regulator_put(vreg->reg);
1979}
1980
1981/* This init function should be called only once for each SDCC slot */
1982static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1983{
1984 int rc = 0;
1985 struct msm_mmc_slot_reg_data *curr_slot;
1986 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1987 struct device *dev = mmc_dev(host->mmc);
1988
1989 curr_slot = host->plat->vreg_data;
1990 if (!curr_slot)
1991 goto out;
1992
1993 curr_vdd_reg = curr_slot->vdd_data;
1994 curr_vccq_reg = curr_slot->vccq_data;
1995 curr_vddp_reg = curr_slot->vddp_data;
1996
1997 if (is_init) {
1998 /*
1999 * Get the regulator handle from voltage regulator framework
2000 * and then try to set the voltage level for the regulator
2001 */
2002 if (curr_vdd_reg) {
2003 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2004 if (rc)
2005 goto out;
2006 }
2007 if (curr_vccq_reg) {
2008 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2009 if (rc)
2010 goto vdd_reg_deinit;
2011 }
2012 if (curr_vddp_reg) {
2013 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2014 if (rc)
2015 goto vccq_reg_deinit;
2016 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002017 rc = msmsdcc_vreg_reset(host);
2018 if (rc)
2019 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2020 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 goto out;
2022 } else {
2023 /* Deregister all regulators from regulator framework */
2024 goto vddp_reg_deinit;
2025 }
2026vddp_reg_deinit:
2027 if (curr_vddp_reg)
2028 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2029vccq_reg_deinit:
2030 if (curr_vccq_reg)
2031 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2032vdd_reg_deinit:
2033 if (curr_vdd_reg)
2034 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2035out:
2036 return rc;
2037}
2038
2039static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2040{
2041 int rc = 0;
2042
Subhash Jadavanicc922692011-08-01 23:05:01 +05302043 /* Put regulator in HPM (high power mode) */
2044 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2045 if (rc < 0)
2046 goto out;
2047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 if (!vreg->is_enabled) {
2049 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302050 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2051 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 if (rc)
2053 goto out;
2054
2055 rc = regulator_enable(vreg->reg);
2056 if (rc) {
2057 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2058 __func__, vreg->name, rc);
2059 goto out;
2060 }
2061 vreg->is_enabled = true;
2062 }
2063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064out:
2065 return rc;
2066}
2067
2068static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2069{
2070 int rc = 0;
2071
2072 /* Never disable regulator marked as always_on */
2073 if (vreg->is_enabled && !vreg->always_on) {
2074 rc = regulator_disable(vreg->reg);
2075 if (rc) {
2076 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2077 __func__, vreg->name, rc);
2078 goto out;
2079 }
2080 vreg->is_enabled = false;
2081
2082 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2083 if (rc < 0)
2084 goto out;
2085
2086 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302087 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 if (rc)
2089 goto out;
2090 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2091 /* Put always_on regulator in LPM (low power mode) */
2092 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2093 if (rc < 0)
2094 goto out;
2095 }
2096out:
2097 return rc;
2098}
2099
2100static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2101{
2102 int rc = 0, i;
2103 struct msm_mmc_slot_reg_data *curr_slot;
2104 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2105 struct msm_mmc_reg_data *vreg_table[3];
2106
2107 curr_slot = host->plat->vreg_data;
2108 if (!curr_slot)
2109 goto out;
2110
2111 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2112 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2113 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2114
2115 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2116 if (vreg_table[i]) {
2117 if (enable)
2118 rc = msmsdcc_vreg_enable(vreg_table[i]);
2119 else
2120 rc = msmsdcc_vreg_disable(vreg_table[i]);
2121 if (rc)
2122 goto out;
2123 }
2124 }
2125out:
2126 return rc;
2127}
2128
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002129/*
2130 * Reset vreg by ensuring it is off during probe. A call
2131 * to enable vreg is needed to balance disable vreg
2132 */
2133static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2134{
2135 int rc;
2136
2137 rc = msmsdcc_setup_vreg(host, 1);
2138 if (rc)
2139 return rc;
2140 rc = msmsdcc_setup_vreg(host, 0);
2141 return rc;
2142}
2143
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302144static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145{
2146 int rc = 0;
2147
2148 if (host->plat->vreg_data) {
2149 struct msm_mmc_reg_data *vddp_reg =
2150 host->plat->vreg_data->vddp_data;
2151
2152 if (vddp_reg && vddp_reg->is_enabled)
2153 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2154 }
2155
2156 return rc;
2157}
2158
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302159static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2160{
2161 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2162 int rc = 0;
2163
2164 if (curr_slot && curr_slot->vddp_data) {
2165 rc = msmsdcc_set_vddp_level(host,
2166 curr_slot->vddp_data->low_vol_level);
2167
2168 if (rc)
2169 pr_err("%s: %s: failed to change vddp level to %d",
2170 mmc_hostname(host->mmc), __func__,
2171 curr_slot->vddp_data->low_vol_level);
2172 }
2173
2174 return rc;
2175}
2176
2177static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2178{
2179 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2180 int rc = 0;
2181
2182 if (curr_slot && curr_slot->vddp_data) {
2183 rc = msmsdcc_set_vddp_level(host,
2184 curr_slot->vddp_data->high_vol_level);
2185
2186 if (rc)
2187 pr_err("%s: %s: failed to change vddp level to %d",
2188 mmc_hostname(host->mmc), __func__,
2189 curr_slot->vddp_data->high_vol_level);
2190 }
2191
2192 return rc;
2193}
2194
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302195static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2196{
2197 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2198 int rc = 0;
2199
2200 if (curr_slot && curr_slot->vccq_data) {
2201 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2202 level, level);
2203 if (rc)
2204 pr_err("%s: %s: failed to change vccq level to %d",
2205 mmc_hostname(host->mmc), __func__, level);
2206 }
2207
2208 return rc;
2209}
2210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2212{
2213 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2214 return 1;
2215 return 0;
2216}
2217
2218static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2219{
2220 if (enable) {
2221 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2222 clk_enable(host->dfab_pclk);
2223 if (!IS_ERR(host->pclk))
2224 clk_enable(host->pclk);
2225 clk_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302226 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302227 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302229 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302230 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231 clk_disable(host->clk);
2232 if (!IS_ERR(host->pclk))
2233 clk_disable(host->pclk);
2234 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2235 clk_disable(host->dfab_pclk);
2236 }
2237}
2238
2239static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2240 unsigned int req_clk)
2241{
2242 unsigned int sel_clk = -1;
2243
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302244 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2245 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2246 goto out;
2247 }
2248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2250 unsigned char cnt;
2251
2252 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2253 if (host->plat->sup_clk_table[cnt] > req_clk)
2254 break;
2255 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2256 sel_clk = host->plat->sup_clk_table[cnt];
2257 break;
2258 } else
2259 sel_clk = host->plat->sup_clk_table[cnt];
2260 }
2261 } else {
2262 if ((req_clk < host->plat->msmsdcc_fmax) &&
2263 (req_clk > host->plat->msmsdcc_fmid))
2264 sel_clk = host->plat->msmsdcc_fmid;
2265 else
2266 sel_clk = req_clk;
2267 }
2268
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302269out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 return sel_clk;
2271}
2272
2273static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2274 struct msmsdcc_host *host)
2275{
2276 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2277 return host->plat->sup_clk_table[0];
2278 else
2279 return host->plat->msmsdcc_fmin;
2280}
2281
2282static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2283 struct msmsdcc_host *host)
2284{
2285 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2286 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2287 else
2288 return host->plat->msmsdcc_fmax;
2289}
2290
2291static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302292{
2293 struct msm_mmc_gpio_data *curr;
2294 int i, rc = 0;
2295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302297 for (i = 0; i < curr->size; i++) {
2298 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 if (curr->gpio[i].is_always_on &&
2300 curr->gpio[i].is_enabled)
2301 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302302 rc = gpio_request(curr->gpio[i].no,
2303 curr->gpio[i].name);
2304 if (rc) {
2305 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2306 mmc_hostname(host->mmc),
2307 curr->gpio[i].no,
2308 curr->gpio[i].name, rc);
2309 goto free_gpios;
2310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302312 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 if (curr->gpio[i].is_always_on)
2314 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302315 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302317 }
2318 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302320
2321free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302323 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 curr->gpio[i].is_enabled = false;
2325 }
2326out:
2327 return rc;
2328}
2329
2330static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2331{
2332 struct msm_mmc_pad_data *curr;
2333 int i;
2334
2335 curr = host->plat->pin_data->pad_data;
2336 for (i = 0; i < curr->drv->size; i++) {
2337 if (enable)
2338 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2339 curr->drv->on[i].val);
2340 else
2341 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2342 curr->drv->off[i].val);
2343 }
2344
2345 for (i = 0; i < curr->pull->size; i++) {
2346 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002347 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 curr->pull->on[i].val);
2349 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002350 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351 curr->pull->off[i].val);
2352 }
2353
2354 return 0;
2355}
2356
2357static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2358{
2359 int rc = 0;
2360
2361 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2362 return 0;
2363
2364 if (host->plat->pin_data->is_gpio)
2365 rc = msmsdcc_setup_gpio(host, enable);
2366 else
2367 rc = msmsdcc_setup_pad(host, enable);
2368
2369 if (!rc)
2370 host->plat->pin_data->cfg_sts = enable;
2371
2372 return rc;
2373}
2374
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302375static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2376{
2377 u32 pwr = 0;
2378 int ret = 0;
2379 struct mmc_host *mmc = host->mmc;
2380
2381 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2382 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2383 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2384 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2385
2386 if (ret) {
2387 pr_err("%s: Failed to setup voltage regulators\n",
2388 mmc_hostname(host->mmc));
2389 goto out;
2390 }
2391
2392 switch (ios->power_mode) {
2393 case MMC_POWER_OFF:
2394 pwr = MCI_PWR_OFF;
2395 if (host->plat->cfg_mpm_sdiowakeup)
2396 host->plat->cfg_mpm_sdiowakeup(
2397 mmc_dev(mmc), SDC_DAT1_DISABLE);
2398 /*
2399 * As VDD pad rail is always on, set low voltage for VDD
2400 * pad rail when slot is unused (when card is not present
2401 * or during system suspend).
2402 */
2403 msmsdcc_set_vddp_low_vol(host);
2404 msmsdcc_setup_pins(host, false);
2405 break;
2406 case MMC_POWER_UP:
2407 /* writing PWR_UP bit is redundant */
2408 pwr = MCI_PWR_UP;
2409 if (host->plat->cfg_mpm_sdiowakeup)
2410 host->plat->cfg_mpm_sdiowakeup(
2411 mmc_dev(mmc), SDC_DAT1_ENABLE);
2412
2413 msmsdcc_set_vddp_high_vol(host);
2414 msmsdcc_setup_pins(host, true);
2415 break;
2416 case MMC_POWER_ON:
2417 pwr = MCI_PWR_ON;
2418 break;
2419 }
2420
2421out:
2422 return pwr;
2423}
2424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2426{
2427 unsigned int wakeup_irq;
2428
2429 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2430 host->plat->sdiowakeup_irq :
2431 host->core_irqres->start;
2432
2433 if (!host->irq_wake_enabled) {
2434 enable_irq_wake(wakeup_irq);
2435 host->irq_wake_enabled = true;
2436 }
2437}
2438
2439static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2440{
2441 unsigned int wakeup_irq;
2442
2443 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2444 host->plat->sdiowakeup_irq :
2445 host->core_irqres->start;
2446
2447 if (host->irq_wake_enabled) {
2448 disable_irq_wake(wakeup_irq);
2449 host->irq_wake_enabled = false;
2450 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302451}
2452
San Mehat9d2bd732009-09-22 16:44:22 -07002453static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302454msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2455{
2456 struct mmc_host *mmc = host->mmc;
2457
2458 /*
2459 * SDIO_AL clients has different mechanism of handling LPM through
2460 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2461 * part of that. Here, we are interested only in clients like WLAN.
2462 */
2463 if (!(mmc->card && mmc_card_sdio(mmc->card))
2464 || host->plat->is_sdio_al_client)
2465 goto out;
2466
2467 if (!host->sdcc_suspended) {
2468 /*
2469 * When MSM is not in power collapse and we
2470 * are disabling clocks, enable bit 22 in MASK0
2471 * to handle asynchronous SDIO interrupts.
2472 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302473 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302474 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302475 mb();
2476 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302477 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302478 msmsdcc_sync_reg_wr(host);
2479 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302480 goto out;
2481 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2482 /*
2483 * Wakeup MSM only if SDIO function drivers set
2484 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2485 */
2486 goto out;
2487 }
2488
2489 if (enable_wakeup_irq) {
2490 if (!host->plat->sdiowakeup_irq) {
2491 /*
2492 * When there is no gpio line that can be configured
2493 * as wakeup interrupt handle it by configuring
2494 * asynchronous sdio interrupts and DAT1 line.
2495 */
2496 writel_relaxed(MCI_SDIOINTMASK,
2497 host->base + MMCIMASK0);
2498 mb();
2499 if (host->plat->cfg_mpm_sdiowakeup)
2500 host->plat->cfg_mpm_sdiowakeup(
2501 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2502 /* configure sdcc core interrupt as wakeup interrupt */
2503 msmsdcc_enable_irq_wake(host);
2504 } else {
2505 /* Let gpio line handle wakeup interrupt */
2506 writel_relaxed(0, host->base + MMCIMASK0);
2507 mb();
2508 if (host->sdio_wakeupirq_disabled) {
2509 host->sdio_wakeupirq_disabled = 0;
2510 /* configure gpio line as wakeup interrupt */
2511 msmsdcc_enable_irq_wake(host);
2512 enable_irq(host->plat->sdiowakeup_irq);
2513 }
2514 }
2515 } else {
2516 if (!host->plat->sdiowakeup_irq) {
2517 /*
2518 * We may not have cleared bit 22 in the interrupt
2519 * handler as the clocks might be off at that time.
2520 */
2521 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302522 msmsdcc_sync_reg_wr(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302523 if (host->plat->cfg_mpm_sdiowakeup)
2524 host->plat->cfg_mpm_sdiowakeup(
2525 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2526 msmsdcc_disable_irq_wake(host);
2527 } else if (!host->sdio_wakeupirq_disabled) {
2528 disable_irq_nosync(host->plat->sdiowakeup_irq);
2529 msmsdcc_disable_irq_wake(host);
2530 host->sdio_wakeupirq_disabled = 1;
2531 }
2532 }
2533out:
2534 return;
2535}
2536
2537static void
San Mehat9d2bd732009-09-22 16:44:22 -07002538msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2539{
2540 struct msmsdcc_host *host = mmc_priv(mmc);
2541 u32 clk = 0, pwr = 0;
2542 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002543 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302547
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302548 /*
2549 * Disable SDCC core interrupt until set_ios is completed.
2550 * This avoids any race conditions with interrupt raised
2551 * when turning on/off the clocks. One possible
2552 * scenario is SDIO operational interrupt while the clock
2553 * is turned off.
2554 */
2555
2556 spin_lock_irqsave(&host->lock, flags);
2557 if (!host->sdcc_irq_disabled) {
2558 spin_unlock_irqrestore(&host->lock, flags);
2559 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302561 host->sdcc_irq_disabled = 1;
2562 }
2563 spin_unlock_irqrestore(&host->lock, flags);
2564
2565 pwr = msmsdcc_setup_pwr(host, ios);
2566
2567 spin_lock_irqsave(&host->lock, flags);
2568 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569 if (!host->clks_on) {
2570 msmsdcc_setup_clocks(host, true);
2571 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302572 writel_relaxed(host->mci_irqenable,
2573 host->base + MMCIMASK0);
2574 mb();
2575 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002576 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577
2578 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2579 /*
2580 * For DDR50 mode, controller needs clock rate to be
2581 * double than what is required on the SD card CLK pin.
2582 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302583 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 /*
2585 * Make sure that we don't double the clock if
2586 * doubled clock rate is already set
2587 */
2588 if (!host->ddr_doubled_clk_rate ||
2589 (host->ddr_doubled_clk_rate &&
2590 (host->ddr_doubled_clk_rate != ios->clock))) {
2591 host->ddr_doubled_clk_rate =
2592 msmsdcc_get_sup_clk_rate(
2593 host, (ios->clock * 2));
2594 clock = host->ddr_doubled_clk_rate;
2595 }
2596 } else {
2597 host->ddr_doubled_clk_rate = 0;
2598 }
2599
2600 if (clock != host->clk_rate) {
2601 rc = clk_set_rate(host->clk, clock);
2602 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302603 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604 mmc_hostname(mmc), clock);
2605 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302606 host->reg_write_delay =
2607 (1 + ((3 * USEC_PER_SEC) /
2608 (host->clk_rate ? host->clk_rate :
2609 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002610 }
2611 /*
2612 * give atleast 2 MCLK cycles delay for clocks
2613 * and SDCC core to stabilize
2614 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302615 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002616 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002617 clk |= MCI_CLK_ENABLE;
2618 }
2619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 if (ios->bus_width == MMC_BUS_WIDTH_8)
2621 clk |= MCI_CLK_WIDEBUS_8;
2622 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2623 clk |= MCI_CLK_WIDEBUS_4;
2624 else
2625 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002627 if (msmsdcc_is_pwrsave(host))
2628 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632 host->tuning_needed = 0;
2633 /*
2634 * Select the controller timing mode according
2635 * to current bus speed mode
2636 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302637 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2638 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 clk |= (4 << 14);
2640 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302641 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002642 clk |= (3 << 14);
2643 } else {
2644 clk |= (2 << 14); /* feedback clock */
2645 }
2646
2647 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2648 clk |= (2 << 23);
2649
Subhash Jadavani00083572012-02-15 16:18:01 +05302650 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2651 if (!ios->vdd)
2652 host->io_pad_pwr_switch = 0;
2653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 if (host->io_pad_pwr_switch)
2655 clk |= IO_PAD_PWR_SWITCH;
2656
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302657 /* Don't write into registers if clocks are disabled */
2658 if (host->clks_on) {
2659 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2660 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302661 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302663 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2664 host->pwr = pwr;
2665 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302666 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 }
2669
2670 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302671 msmsdcc_cfg_sdio_wakeup(host, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672 msmsdcc_setup_clocks(host, false);
2673 host->clks_on = 0;
2674 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302675
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302676 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302677 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302678 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302679
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302680 /* Let interrupts be disabled if the host is powered off */
2681 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2682 enable_irq(host->core_irqres->start);
2683 host->sdcc_irq_disabled = 0;
2684 }
2685
San Mehat4adbbcc2009-11-08 13:00:37 -08002686 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002687}
2688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2690{
2691 struct msmsdcc_host *host = mmc_priv(mmc);
2692 u32 clk;
2693
2694 clk = readl_relaxed(host->base + MMCICLOCK);
2695 pr_debug("Changing to pwr_save=%d", pwrsave);
2696 if (pwrsave && msmsdcc_is_pwrsave(host))
2697 clk |= MCI_CLK_PWRSAVE;
2698 else
2699 clk &= ~MCI_CLK_PWRSAVE;
2700 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302701 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702
2703 return 0;
2704}
2705
2706static int msmsdcc_get_ro(struct mmc_host *mmc)
2707{
2708 int status = -ENOSYS;
2709 struct msmsdcc_host *host = mmc_priv(mmc);
2710
2711 if (host->plat->wpswitch) {
2712 status = host->plat->wpswitch(mmc_dev(mmc));
2713 } else if (host->plat->wpswitch_gpio) {
2714 status = gpio_request(host->plat->wpswitch_gpio,
2715 "SD_WP_Switch");
2716 if (status) {
2717 pr_err("%s: %s: Failed to request GPIO %d\n",
2718 mmc_hostname(mmc), __func__,
2719 host->plat->wpswitch_gpio);
2720 } else {
2721 status = gpio_direction_input(
2722 host->plat->wpswitch_gpio);
2723 if (!status) {
2724 /*
2725 * Wait for atleast 300ms as debounce
2726 * time for GPIO input to stabilize.
2727 */
2728 msleep(300);
2729 status = gpio_get_value_cansleep(
2730 host->plat->wpswitch_gpio);
2731 status ^= !host->plat->wpswitch_polarity;
2732 }
2733 gpio_free(host->plat->wpswitch_gpio);
2734 }
2735 }
2736
2737 if (status < 0)
2738 status = -ENOSYS;
2739 pr_debug("%s: Card read-only status %d\n", __func__, status);
2740
2741 return status;
2742}
2743
2744#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002745static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2746{
2747 struct msmsdcc_host *host = mmc_priv(mmc);
2748 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302750 /*
2751 * We may come here with clocks turned off in that case don't
2752 * attempt to write into MASK0 register. While turning on the
2753 * clocks mci_irqenable will be written to MASK0 register.
2754 */
2755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 if (enable) {
2757 spin_lock_irqsave(&host->lock, flags);
2758 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302759 if (host->clks_on) {
2760 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302762 mb();
2763 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 spin_unlock_irqrestore(&host->lock, flags);
2765 } else {
2766 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302767 if (host->clks_on) {
2768 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302770 mb();
2771 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773}
2774#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2775
2776#ifdef CONFIG_PM_RUNTIME
2777static int msmsdcc_enable(struct mmc_host *mmc)
2778{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302779 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302781 struct msmsdcc_host *host = mmc_priv(mmc);
2782
2783 msmsdcc_pm_qos_update_latency(host, 1);
2784
2785 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2786 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302788 if (dev->power.runtime_status == RPM_SUSPENDING) {
2789 if (mmc->suspend_task == current) {
2790 pm_runtime_get_noresume(dev);
2791 goto out;
2792 }
2793 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302795 rc = pm_runtime_get_sync(dev);
2796
2797 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2799 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302800 return rc;
2801 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302802
2803 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302804out:
2805 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806}
2807
2808static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2809{
2810 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302811 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302813 msmsdcc_pm_qos_update_latency(host, 0);
2814
2815 if (mmc->card && mmc_card_sdio(mmc->card))
2816 return 0;
2817
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302818 if (host->plat->disable_runtime_pm)
2819 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820
2821 rc = pm_runtime_put_sync(mmc->parent);
2822
2823 if (rc < 0)
2824 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2825 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302826 else
2827 host->is_resumed = false;
2828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 return rc;
2830}
2831#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302832static int msmsdcc_enable(struct mmc_host *mmc)
2833{
2834 struct msmsdcc_host *host = mmc_priv(mmc);
2835 unsigned long flags;
2836
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302837 msmsdcc_pm_qos_update_latency(host, 1);
2838
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302839 spin_lock_irqsave(&host->lock, flags);
2840 if (!host->clks_on) {
2841 msmsdcc_setup_clocks(host, true);
2842 host->clks_on = 1;
2843 }
2844 spin_unlock_irqrestore(&host->lock, flags);
2845
2846 return 0;
2847}
2848
2849static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2850{
2851 struct msmsdcc_host *host = mmc_priv(mmc);
2852 unsigned long flags;
2853
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302854 msmsdcc_pm_qos_update_latency(host, 0);
2855
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302856 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302857 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302858
2859 spin_lock_irqsave(&host->lock, flags);
2860 if (host->clks_on) {
2861 msmsdcc_setup_clocks(host, false);
2862 host->clks_on = 0;
2863 }
2864 spin_unlock_irqrestore(&host->lock, flags);
2865
2866 return 0;
2867}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002868#endif
2869
2870static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2871 struct mmc_ios *ios)
2872{
2873 struct msmsdcc_host *host = mmc_priv(mmc);
2874 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302875 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876
Subhash Jadavani00083572012-02-15 16:18:01 +05302877 spin_lock_irqsave(&host->lock, flags);
2878 host->io_pad_pwr_switch = 0;
2879 spin_unlock_irqrestore(&host->lock, flags);
2880
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302881 /*
2882 * For eMMC cards, VccQ voltage range must be changed
2883 * only if it operates in HS200 SDR 1.2V mode or in
2884 * DDR 1.2V mode.
2885 */
2886 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2887 rc = msmsdcc_set_vccq_vol(host, 1200000);
2888 goto out;
2889 }
2890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2892 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302893 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 goto out;
2895 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2896 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302897 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 goto out;
2899 }
San Mehat9d2bd732009-09-22 16:44:22 -07002900
2901 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902 /*
2903 * If we are here means voltage switch from high voltage to
2904 * low voltage is required
2905 */
2906
2907 /*
2908 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2909 * register until they become all zeros.
2910 */
2911 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302912 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2914 mmc_hostname(mmc), __func__);
2915 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002916 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917
2918 /* Stop SD CLK output. */
2919 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2920 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302921 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002922 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923
2924 /*
2925 * Switch VDDPX from high voltage to low voltage
2926 * to change the VDD of the SD IO pads.
2927 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302928 rc = msmsdcc_set_vddp_low_vol(host);
2929 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931
2932 spin_lock_irqsave(&host->lock, flags);
2933 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2934 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302935 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 host->io_pad_pwr_switch = 1;
2937 spin_unlock_irqrestore(&host->lock, flags);
2938
2939 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2940 usleep_range(5000, 5500);
2941
2942 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302943 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002944 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2945 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302946 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 spin_unlock_irqrestore(&host->lock, flags);
2948
2949 /*
2950 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2951 * don't become all ones within 1 ms then a Voltage Switch
2952 * sequence has failed and a power cycle to the card is required.
2953 * Otherwise Voltage Switch sequence is completed successfully.
2954 */
2955 usleep_range(1000, 1500);
2956
2957 spin_lock_irqsave(&host->lock, flags);
2958 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2959 != (0xF << 1)) {
2960 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2961 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302962 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963 goto out_unlock;
2964 }
2965
2966out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302967 /* Enable PWRSAVE */
2968 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2969 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302970 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 spin_unlock_irqrestore(&host->lock, flags);
2972out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302973 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974}
2975
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302976static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979
2980 /* Program the MCLK value to MCLK_FREQ bit field */
2981 if (host->clk_rate <= 112000000)
2982 mclk_freq = 0;
2983 else if (host->clk_rate <= 125000000)
2984 mclk_freq = 1;
2985 else if (host->clk_rate <= 137000000)
2986 mclk_freq = 2;
2987 else if (host->clk_rate <= 150000000)
2988 mclk_freq = 3;
2989 else if (host->clk_rate <= 162000000)
2990 mclk_freq = 4;
2991 else if (host->clk_rate <= 175000000)
2992 mclk_freq = 5;
2993 else if (host->clk_rate <= 187000000)
2994 mclk_freq = 6;
2995 else if (host->clk_rate <= 200000000)
2996 mclk_freq = 7;
2997
2998 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2999 & ~(7 << 24)) | (mclk_freq << 24)),
3000 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003001}
3002
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303003/* Initialize the DLL (Programmable Delay Line ) */
3004static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303007 unsigned long flags;
3008 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003009
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303010 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003011 /*
3012 * Make sure that clock is always enabled when DLL
3013 * tuning is in progress. Keeping PWRSAVE ON may
3014 * turn off the clock. So let's disable the PWRSAVE
3015 * here and re-enable it once tuning is completed.
3016 */
3017 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3018 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303019 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303020
3021 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3022 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3023 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3024
3025 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3026 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3027 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3028
3029 msmsdcc_cm_sdc4_dll_set_freq(host);
3030
3031 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3032 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3033 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3034
3035 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3036 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3037 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3038
3039 /* Set DLL_EN bit to 1. */
3040 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3041 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3042
3043 /* Set CK_OUT_EN bit to 1. */
3044 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3045 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3046
3047 wait_cnt = 50;
3048 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3049 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3050 /* max. wait for 50us sec for LOCK bit to be set */
3051 if (--wait_cnt == 0) {
3052 pr_err("%s: %s: DLL failed to LOCK\n",
3053 mmc_hostname(host->mmc), __func__);
3054 rc = -ETIMEDOUT;
3055 goto out;
3056 }
3057 /* wait for 1us before polling again */
3058 udelay(1);
3059 }
3060
3061out:
3062 /* re-enable PWRSAVE */
3063 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3064 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303065 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303066 spin_unlock_irqrestore(&host->lock, flags);
3067
3068 return rc;
3069}
3070
3071static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3072 u8 poll)
3073{
3074 int rc = 0;
3075 u32 wait_cnt = 50;
3076 u8 ck_out_en = 0;
3077
3078 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3079 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3080 MCI_CK_OUT_EN);
3081
3082 while (ck_out_en != poll) {
3083 if (--wait_cnt == 0) {
3084 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3085 mmc_hostname(host->mmc), __func__, poll);
3086 rc = -ETIMEDOUT;
3087 goto out;
3088 }
3089 udelay(1);
3090
3091 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3092 MCI_CK_OUT_EN);
3093 }
3094out:
3095 return rc;
3096}
3097
3098/*
3099 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3100 * calibration sequence. This function should be called before
3101 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3102 * commands (CMD17/CMD18).
3103 *
3104 * This function gets called when host spinlock acquired.
3105 */
3106static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3107{
3108 int rc = 0;
3109 u32 config;
3110
3111 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3112 config |= MCI_CDR_EN;
3113 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3114 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3115
3116 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3117 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3118 if (rc)
3119 goto err_out;
3120
3121 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3122 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3123 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3124
3125 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3126 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3127 if (rc)
3128 goto err_out;
3129
3130 goto out;
3131
3132err_out:
3133 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3134out:
3135 return rc;
3136}
3137
3138static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3139 u8 phase)
3140{
3141 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303142 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3143 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3144 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303145 unsigned long flags;
3146 u32 config;
3147
3148 spin_lock_irqsave(&host->lock, flags);
3149
3150 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3151 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3152 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3153 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3154
3155 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3156 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3157 if (rc)
3158 goto err_out;
3159
3160 /*
3161 * Write the selected DLL clock output phase (0 ... 15)
3162 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3163 */
3164 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3165 & ~(0xF << 20))
3166 | (grey_coded_phase_table[phase] << 20)),
3167 host->base + MCI_DLL_CONFIG);
3168
3169 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3170 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3171 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3172
3173 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3174 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3175 if (rc)
3176 goto err_out;
3177
3178 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3179 config |= MCI_CDR_EN;
3180 config &= ~MCI_CDR_EXT_EN;
3181 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3182 goto out;
3183
3184err_out:
3185 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3186 mmc_hostname(host->mmc), __func__, phase);
3187out:
3188 spin_unlock_irqrestore(&host->lock, flags);
3189 return rc;
3190}
3191
3192/*
3193 * Find out the greatest range of consecuitive selected
3194 * DLL clock output phases that can be used as sampling
3195 * setting for SD3.0 UHS-I card read operation (in SDR104
3196 * timing mode) or for eMMC4.5 card read operation (in HS200
3197 * timing mode).
3198 * Select the 3/4 of the range and configure the DLL with the
3199 * selected DLL clock output phase.
3200*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303201static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303202 u8 *phase_table, u8 total_phases)
3203{
Subhash Jadavani34187042012-03-02 10:59:49 +05303204 int ret;
3205 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303206 u8 phases_per_row[16] = {0};
3207 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303208 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3209 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303210
Subhash Jadavani34187042012-03-02 10:59:49 +05303211 if (total_phases > 16) {
3212 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3213 mmc_hostname(host->mmc), __func__, total_phases);
3214 return -EINVAL;
3215 }
3216
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303217 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303218 ranges[row_index][col_index] = phase_table[cnt];
3219 phases_per_row[row_index] += 1;
3220 col_index++;
3221
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303222 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303223 continue;
3224 /* check if next phase in phase_table is consecutive or not */
3225 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3226 row_index++;
3227 col_index = 0;
3228 }
3229 }
3230
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303231 /* Check if phase-0 is present in first valid window? */
3232 if (!ranges[0][0]) {
3233 phase_0_found = true;
3234 phase_0_raw_index = 0;
3235 /* Check if cycle exist between 2 valid windows */
3236 for (cnt = 1; cnt <= row_index; cnt++) {
3237 if (phases_per_row[cnt]) {
3238 for (i = 0; i <= phases_per_row[cnt]; i++) {
3239 if (ranges[cnt][i] == 15) {
3240 phase_15_found = true;
3241 phase_15_raw_index = cnt;
3242 break;
3243 }
3244 }
3245 }
3246 }
3247 }
3248
3249 /* If 2 valid windows form cycle then merge them as single window */
3250 if (phase_0_found && phase_15_found) {
3251 /* number of phases in raw where phase 0 is present */
3252 u8 phases_0 = phases_per_row[phase_0_raw_index];
3253 /* number of phases in raw where phase 15 is present */
3254 u8 phases_15 = phases_per_row[phase_15_raw_index];
3255
3256 cnt = 0;
3257 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3258 ranges[phase_15_raw_index][i] =
3259 ranges[phase_0_raw_index][cnt];
3260 cnt++;
3261 }
3262 phases_per_row[phase_0_raw_index] = 0;
3263 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3264 }
3265
3266 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303267 if (phases_per_row[cnt] > curr_max) {
3268 curr_max = phases_per_row[cnt];
3269 selected_row_index = cnt;
3270 }
3271 }
3272
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303273 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303274 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303275
3276 return ret;
3277}
3278
Girish K Sa3f41692012-02-29 12:00:09 +05303279static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303280{
3281 int rc = 0;
3282 struct msmsdcc_host *host = mmc_priv(mmc);
3283 unsigned long flags;
3284 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303285 const u32 *tuning_block_pattern = tuning_block_64;
3286 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303287
3288 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3289
3290 /* Tuning is only required for SDR104 modes */
3291 if (!host->tuning_needed) {
3292 rc = 0;
3293 goto exit;
3294 }
3295
3296 spin_lock_irqsave(&host->lock, flags);
3297 WARN(!host->pwr, "SDCC power is turned off\n");
3298 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3299 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3300
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303301 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303302 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3303 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3304 tuning_block_pattern = tuning_block_128;
3305 size = sizeof(tuning_block_128);
3306 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303307 spin_unlock_irqrestore(&host->lock, flags);
3308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 /* first of all reset the tuning block */
3310 rc = msmsdcc_init_cm_sdc4_dll(host);
3311 if (rc)
3312 goto out;
3313
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303314 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003315 if (!data_buf) {
3316 rc = -ENOMEM;
3317 goto out;
3318 }
3319
3320 phase = 0;
3321 do {
3322 struct mmc_command cmd = {0};
3323 struct mmc_data data = {0};
3324 struct mmc_request mrq = {
3325 .cmd = &cmd,
3326 .data = &data
3327 };
3328 struct scatterlist sg;
3329
3330 /* set the phase in delay line hw block */
3331 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3332 if (rc)
3333 goto kfree;
3334
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303335 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003336 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3337
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303338 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 data.blocks = 1;
3340 data.flags = MMC_DATA_READ;
3341 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3342
3343 data.sg = &sg;
3344 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303345 sg_init_one(&sg, data_buf, size);
3346 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347 mmc_wait_for_req(mmc, &mrq);
3348
3349 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303350 !memcmp(data_buf, tuning_block_pattern, size)) {
3351 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303353 pr_debug("%s: %s: found good phase = %d\n",
3354 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003355 }
3356 } while (++phase < 16);
3357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303359 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303360 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303361 if (rc < 0)
3362 goto kfree;
3363 else
3364 phase = (u8)rc;
3365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003366 /*
3367 * Finally set the selected phase in delay
3368 * line hw block.
3369 */
3370 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3371 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303372 goto kfree;
3373 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3374 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375 } else {
3376 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303377 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303379 msmsdcc_dump_sdcc_state(host);
3380 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003381 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382
3383kfree:
3384 kfree(data_buf);
3385out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303386 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303387 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303388 spin_unlock_irqrestore(&host->lock, flags);
3389exit:
3390 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003391 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003392}
3393
3394static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003395 .enable = msmsdcc_enable,
3396 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003397 .request = msmsdcc_request,
3398 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399 .get_ro = msmsdcc_get_ro,
3400#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003401 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402#endif
3403 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3404 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003405};
3406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003407static unsigned int
3408msmsdcc_slot_status(struct msmsdcc_host *host)
3409{
3410 int status;
3411 unsigned int gpio_no = host->plat->status_gpio;
3412
3413 status = gpio_request(gpio_no, "SD_HW_Detect");
3414 if (status) {
3415 pr_err("%s: %s: Failed to request GPIO %d\n",
3416 mmc_hostname(host->mmc), __func__, gpio_no);
3417 } else {
3418 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003419 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003420 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003421 if (host->plat->is_status_gpio_active_low)
3422 status = !status;
3423 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003424 gpio_free(gpio_no);
3425 }
3426 return status;
3427}
3428
San Mehat9d2bd732009-09-22 16:44:22 -07003429static void
3430msmsdcc_check_status(unsigned long data)
3431{
3432 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3433 unsigned int status;
3434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003436 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003438 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 status = msmsdcc_slot_status(host);
3440
Krishna Konda941604a2012-01-10 17:46:34 -08003441 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003444 if (host->plat->status)
3445 pr_info("%s: Slot status change detected "
3446 "(%d -> %d)\n",
3447 mmc_hostname(host->mmc),
3448 host->oldstat, status);
3449 else if (host->plat->is_status_gpio_active_low)
3450 pr_info("%s: Slot status change detected "
3451 "(%d -> %d) and the card detect GPIO"
3452 " is ACTIVE_LOW\n",
3453 mmc_hostname(host->mmc),
3454 host->oldstat, status);
3455 else
3456 pr_info("%s: Slot status change detected "
3457 "(%d -> %d) and the card detect GPIO"
3458 " is ACTIVE_HIGH\n",
3459 mmc_hostname(host->mmc),
3460 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003461 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003462 }
3463 host->oldstat = status;
3464 } else {
3465 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003466 }
San Mehat9d2bd732009-09-22 16:44:22 -07003467}
3468
3469static irqreturn_t
3470msmsdcc_platform_status_irq(int irq, void *dev_id)
3471{
3472 struct msmsdcc_host *host = dev_id;
3473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003475 msmsdcc_check_status((unsigned long) host);
3476 return IRQ_HANDLED;
3477}
3478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003479static irqreturn_t
3480msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3481{
3482 struct msmsdcc_host *host = dev_id;
3483
3484 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3485 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303486 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303488 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489 wake_lock(&host->sdio_wlock);
3490 msmsdcc_disable_irq_wake(host);
3491 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303492 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003493 }
3494 if (host->plat->is_sdio_al_client) {
3495 if (!host->clks_on) {
3496 msmsdcc_setup_clocks(host, true);
3497 host->clks_on = 1;
3498 }
3499 if (host->sdcc_irq_disabled) {
3500 writel_relaxed(host->mci_irqenable,
3501 host->base + MMCIMASK0);
3502 mb();
3503 enable_irq(host->core_irqres->start);
3504 host->sdcc_irq_disabled = 0;
3505 }
3506 wake_lock(&host->sdio_wlock);
3507 }
3508 spin_unlock(&host->lock);
3509
3510 return IRQ_HANDLED;
3511}
3512
San Mehat9d2bd732009-09-22 16:44:22 -07003513static void
3514msmsdcc_status_notify_cb(int card_present, void *dev_id)
3515{
3516 struct msmsdcc_host *host = dev_id;
3517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003519 card_present);
3520 msmsdcc_check_status((unsigned long) host);
3521}
3522
San Mehat9d2bd732009-09-22 16:44:22 -07003523static int
3524msmsdcc_init_dma(struct msmsdcc_host *host)
3525{
3526 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3527 host->dma.host = host;
3528 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003529 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003530
3531 if (!host->dmares)
3532 return -ENODEV;
3533
3534 host->dma.nc = dma_alloc_coherent(NULL,
3535 sizeof(struct msmsdcc_nc_dmadata),
3536 &host->dma.nc_busaddr,
3537 GFP_KERNEL);
3538 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003539 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003540 return -ENOMEM;
3541 }
3542 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3543 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3544 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3545 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3546 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003547 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003548
3549 return 0;
3550}
3551
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003552#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3553/**
3554 * Allocate and Connect a SDCC peripheral's SPS endpoint
3555 *
3556 * This function allocates endpoint context and
3557 * connect it with memory endpoint by calling
3558 * appropriate SPS driver APIs.
3559 *
3560 * Also registers a SPS callback function with
3561 * SPS driver
3562 *
3563 * This function should only be called once typically
3564 * during driver probe.
3565 *
3566 * @host - Pointer to sdcc host structure
3567 * @ep - Pointer to sps endpoint data structure
3568 * @is_produce - 1 means Producer endpoint
3569 * 0 means Consumer endpoint
3570 *
3571 * @return - 0 if successful else negative value.
3572 *
3573 */
3574static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3575 struct msmsdcc_sps_ep_conn_data *ep,
3576 bool is_producer)
3577{
3578 int rc = 0;
3579 struct sps_pipe *sps_pipe_handle;
3580 struct sps_connect *sps_config = &ep->config;
3581 struct sps_register_event *sps_event = &ep->event;
3582
3583 /* Allocate endpoint context */
3584 sps_pipe_handle = sps_alloc_endpoint();
3585 if (!sps_pipe_handle) {
3586 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3587 mmc_hostname(host->mmc), is_producer);
3588 rc = -ENOMEM;
3589 goto out;
3590 }
3591
3592 /* Get default connection configuration for an endpoint */
3593 rc = sps_get_config(sps_pipe_handle, sps_config);
3594 if (rc) {
3595 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3596 " rc=%d", mmc_hostname(host->mmc),
3597 (u32)sps_pipe_handle, rc);
3598 goto get_config_err;
3599 }
3600
3601 /* Modify the default connection configuration */
3602 if (is_producer) {
3603 /*
3604 * For SDCC producer transfer, source should be
3605 * SDCC peripheral where as destination should
3606 * be system memory.
3607 */
3608 sps_config->source = host->sps.bam_handle;
3609 sps_config->destination = SPS_DEV_HANDLE_MEM;
3610 /* Producer pipe will handle this connection */
3611 sps_config->mode = SPS_MODE_SRC;
3612 sps_config->options =
3613 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3614 } else {
3615 /*
3616 * For SDCC consumer transfer, source should be
3617 * system memory where as destination should
3618 * SDCC peripheral
3619 */
3620 sps_config->source = SPS_DEV_HANDLE_MEM;
3621 sps_config->destination = host->sps.bam_handle;
3622 sps_config->mode = SPS_MODE_DEST;
3623 sps_config->options =
3624 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3625 }
3626
3627 /* Producer pipe index */
3628 sps_config->src_pipe_index = host->sps.src_pipe_index;
3629 /* Consumer pipe index */
3630 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3631 /*
3632 * This event thresold value is only significant for BAM-to-BAM
3633 * transfer. It's ignored for BAM-to-System mode transfer.
3634 */
3635 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303636
3637 /* Allocate maximum descriptor fifo size */
3638 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3639 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003640 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3641 sps_config->desc.size,
3642 &sps_config->desc.phys_base,
3643 GFP_KERNEL);
3644
Pratibhasagar V00b94332011-10-18 14:57:27 +05303645 if (!sps_config->desc.base) {
3646 rc = -ENOMEM;
3647 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3648 , mmc_hostname(host->mmc));
3649 goto get_config_err;
3650 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3652
3653 /* Establish connection between peripheral and memory endpoint */
3654 rc = sps_connect(sps_pipe_handle, sps_config);
3655 if (rc) {
3656 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3657 " rc=%d", mmc_hostname(host->mmc),
3658 (u32)sps_pipe_handle, rc);
3659 goto sps_connect_err;
3660 }
3661
3662 sps_event->mode = SPS_TRIGGER_CALLBACK;
3663 sps_event->options = SPS_O_EOT;
3664 sps_event->callback = msmsdcc_sps_complete_cb;
3665 sps_event->xfer_done = NULL;
3666 sps_event->user = (void *)host;
3667
3668 /* Register callback event for EOT (End of transfer) event. */
3669 rc = sps_register_event(sps_pipe_handle, sps_event);
3670 if (rc) {
3671 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3672 " rc=%d", mmc_hostname(host->mmc),
3673 (u32)sps_pipe_handle, rc);
3674 goto reg_event_err;
3675 }
3676 /* Now save the sps pipe handle */
3677 ep->pipe_handle = sps_pipe_handle;
3678 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3679 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3680 __func__, is_producer ? "READ" : "WRITE",
3681 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3682 goto out;
3683
3684reg_event_err:
3685 sps_disconnect(sps_pipe_handle);
3686sps_connect_err:
3687 dma_free_coherent(mmc_dev(host->mmc),
3688 sps_config->desc.size,
3689 sps_config->desc.base,
3690 sps_config->desc.phys_base);
3691get_config_err:
3692 sps_free_endpoint(sps_pipe_handle);
3693out:
3694 return rc;
3695}
3696
3697/**
3698 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3699 *
3700 * This function disconnect endpoint and deallocates
3701 * endpoint context.
3702 *
3703 * This function should only be called once typically
3704 * during driver remove.
3705 *
3706 * @host - Pointer to sdcc host structure
3707 * @ep - Pointer to sps endpoint data structure
3708 *
3709 */
3710static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3711 struct msmsdcc_sps_ep_conn_data *ep)
3712{
3713 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3714 struct sps_connect *sps_config = &ep->config;
3715 struct sps_register_event *sps_event = &ep->event;
3716
3717 sps_event->xfer_done = NULL;
3718 sps_event->callback = NULL;
3719 sps_register_event(sps_pipe_handle, sps_event);
3720 sps_disconnect(sps_pipe_handle);
3721 dma_free_coherent(mmc_dev(host->mmc),
3722 sps_config->desc.size,
3723 sps_config->desc.base,
3724 sps_config->desc.phys_base);
3725 sps_free_endpoint(sps_pipe_handle);
3726}
3727
3728/**
3729 * Reset SDCC peripheral's SPS endpoint
3730 *
3731 * This function disconnects an endpoint.
3732 *
3733 * This function should be called for reseting
3734 * SPS endpoint when data transfer error is
3735 * encountered during data transfer. This
3736 * can be considered as soft reset to endpoint.
3737 *
3738 * This function should only be called if
3739 * msmsdcc_sps_init() is already called.
3740 *
3741 * @host - Pointer to sdcc host structure
3742 * @ep - Pointer to sps endpoint data structure
3743 *
3744 * @return - 0 if successful else negative value.
3745 */
3746static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3747 struct msmsdcc_sps_ep_conn_data *ep)
3748{
3749 int rc = 0;
3750 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3751
3752 rc = sps_disconnect(sps_pipe_handle);
3753 if (rc) {
3754 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3755 " rc=%d", mmc_hostname(host->mmc), __func__,
3756 (u32)sps_pipe_handle, rc);
3757 goto out;
3758 }
3759 out:
3760 return rc;
3761}
3762
3763/**
3764 * Restore SDCC peripheral's SPS endpoint
3765 *
3766 * This function connects an endpoint.
3767 *
3768 * This function should be called for restoring
3769 * SPS endpoint after data transfer error is
3770 * encountered during data transfer. This
3771 * can be considered as soft reset to endpoint.
3772 *
3773 * This function should only be called if
3774 * msmsdcc_sps_reset_ep() is called before.
3775 *
3776 * @host - Pointer to sdcc host structure
3777 * @ep - Pointer to sps endpoint data structure
3778 *
3779 * @return - 0 if successful else negative value.
3780 */
3781static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3782 struct msmsdcc_sps_ep_conn_data *ep)
3783{
3784 int rc = 0;
3785 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3786 struct sps_connect *sps_config = &ep->config;
3787 struct sps_register_event *sps_event = &ep->event;
3788
3789 /* Establish connection between peripheral and memory endpoint */
3790 rc = sps_connect(sps_pipe_handle, sps_config);
3791 if (rc) {
3792 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3793 " rc=%d", mmc_hostname(host->mmc), __func__,
3794 (u32)sps_pipe_handle, rc);
3795 goto out;
3796 }
3797
3798 /* Register callback event for EOT (End of transfer) event. */
3799 rc = sps_register_event(sps_pipe_handle, sps_event);
3800 if (rc) {
3801 pr_err("%s: %s: sps_register_event() failed!!!"
3802 " pipe_handle=0x%x, rc=%d",
3803 mmc_hostname(host->mmc), __func__,
3804 (u32)sps_pipe_handle, rc);
3805 goto reg_event_err;
3806 }
3807 goto out;
3808
3809reg_event_err:
3810 sps_disconnect(sps_pipe_handle);
3811out:
3812 return rc;
3813}
3814
3815/**
3816 * Initialize SPS HW connected with SDCC core
3817 *
3818 * This function register BAM HW resources with
3819 * SPS driver and then initialize 2 SPS endpoints
3820 *
3821 * This function should only be called once typically
3822 * during driver probe.
3823 *
3824 * @host - Pointer to sdcc host structure
3825 *
3826 * @return - 0 if successful else negative value.
3827 *
3828 */
3829static int msmsdcc_sps_init(struct msmsdcc_host *host)
3830{
3831 int rc = 0;
3832 struct sps_bam_props bam = {0};
3833
3834 host->bam_base = ioremap(host->bam_memres->start,
3835 resource_size(host->bam_memres));
3836 if (!host->bam_base) {
3837 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3838 " size=0x%x", mmc_hostname(host->mmc),
3839 host->bam_memres->start,
3840 (host->bam_memres->end -
3841 host->bam_memres->start));
3842 rc = -ENOMEM;
3843 goto out;
3844 }
3845
3846 bam.phys_addr = host->bam_memres->start;
3847 bam.virt_addr = host->bam_base;
3848 /*
3849 * This event thresold value is only significant for BAM-to-BAM
3850 * transfer. It's ignored for BAM-to-System mode transfer.
3851 */
3852 bam.event_threshold = 0x10; /* Pipe event threshold */
3853 /*
3854 * This threshold controls when the BAM publish
3855 * the descriptor size on the sideband interface.
3856 * SPS HW will only be used when
3857 * data transfer size > MCI_FIFOSIZE (64 bytes).
3858 * PIO mode will be used when
3859 * data transfer size < MCI_FIFOSIZE (64 bytes).
3860 * So set this thresold value to 64 bytes.
3861 */
3862 bam.summing_threshold = 64;
3863 /* SPS driver wll handle the SDCC BAM IRQ */
3864 bam.irq = (u32)host->bam_irqres->start;
3865 bam.manage = SPS_BAM_MGR_LOCAL;
3866
3867 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3868 (u32)bam.phys_addr);
3869 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3870 (u32)bam.virt_addr);
3871
3872 /* Register SDCC Peripheral BAM device to SPS driver */
3873 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3874 if (rc) {
3875 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3876 mmc_hostname(host->mmc), rc);
3877 goto reg_bam_err;
3878 }
3879 pr_info("%s: BAM device registered. bam_handle=0x%x",
3880 mmc_hostname(host->mmc), host->sps.bam_handle);
3881
3882 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3883 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3884
3885 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3886 SPS_PROD_PERIPHERAL);
3887 if (rc)
3888 goto sps_reset_err;
3889 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3890 SPS_CONS_PERIPHERAL);
3891 if (rc)
3892 goto cons_conn_err;
3893
3894 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3895 mmc_hostname(host->mmc),
3896 (unsigned long long)host->bam_memres->start,
3897 (unsigned int)host->bam_irqres->start);
3898 goto out;
3899
3900cons_conn_err:
3901 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3902sps_reset_err:
3903 sps_deregister_bam_device(host->sps.bam_handle);
3904reg_bam_err:
3905 iounmap(host->bam_base);
3906out:
3907 return rc;
3908}
3909
3910/**
3911 * De-initialize SPS HW connected with SDCC core
3912 *
3913 * This function deinitialize SPS endpoints and then
3914 * deregisters BAM resources from SPS driver.
3915 *
3916 * This function should only be called once typically
3917 * during driver remove.
3918 *
3919 * @host - Pointer to sdcc host structure
3920 *
3921 */
3922static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3923{
3924 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3925 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3926 sps_deregister_bam_device(host->sps.bam_handle);
3927 iounmap(host->bam_base);
3928}
3929#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3930
3931static ssize_t
3932show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3933{
3934 struct mmc_host *mmc = dev_get_drvdata(dev);
3935 struct msmsdcc_host *host = mmc_priv(mmc);
3936 int poll;
3937 unsigned long flags;
3938
3939 spin_lock_irqsave(&host->lock, flags);
3940 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3941 spin_unlock_irqrestore(&host->lock, flags);
3942
3943 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3944}
3945
3946static ssize_t
3947set_polling(struct device *dev, struct device_attribute *attr,
3948 const char *buf, size_t count)
3949{
3950 struct mmc_host *mmc = dev_get_drvdata(dev);
3951 struct msmsdcc_host *host = mmc_priv(mmc);
3952 int value;
3953 unsigned long flags;
3954
3955 sscanf(buf, "%d", &value);
3956
3957 spin_lock_irqsave(&host->lock, flags);
3958 if (value) {
3959 mmc->caps |= MMC_CAP_NEEDS_POLL;
3960 mmc_detect_change(host->mmc, 0);
3961 } else {
3962 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3963 }
3964#ifdef CONFIG_HAS_EARLYSUSPEND
3965 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3966#endif
3967 spin_unlock_irqrestore(&host->lock, flags);
3968 return count;
3969}
3970
3971static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3972 show_polling, set_polling);
3973static struct attribute *dev_attrs[] = {
3974 &dev_attr_polling.attr,
3975 NULL,
3976};
3977static struct attribute_group dev_attr_grp = {
3978 .attrs = dev_attrs,
3979};
3980
3981#ifdef CONFIG_HAS_EARLYSUSPEND
3982static void msmsdcc_early_suspend(struct early_suspend *h)
3983{
3984 struct msmsdcc_host *host =
3985 container_of(h, struct msmsdcc_host, early_suspend);
3986 unsigned long flags;
3987
3988 spin_lock_irqsave(&host->lock, flags);
3989 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3990 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3991 spin_unlock_irqrestore(&host->lock, flags);
3992};
3993static void msmsdcc_late_resume(struct early_suspend *h)
3994{
3995 struct msmsdcc_host *host =
3996 container_of(h, struct msmsdcc_host, early_suspend);
3997 unsigned long flags;
3998
3999 if (host->polling_enabled) {
4000 spin_lock_irqsave(&host->lock, flags);
4001 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4002 mmc_detect_change(host->mmc, 0);
4003 spin_unlock_irqrestore(&host->lock, flags);
4004 }
4005};
4006#endif
4007
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304008void msmsdcc_print_regs(const char *name, void __iomem *base,
4009 unsigned int no_of_regs)
4010{
4011 unsigned int i;
4012
4013 if (!base)
4014 return;
4015 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
4016 name, (u32)base);
4017 for (i = 0; i < no_of_regs; i = i + 4) {
4018 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
4019 (u32)readl_relaxed(base + i*4),
4020 (u32)readl_relaxed(base + ((i+1)*4)),
4021 (u32)readl_relaxed(base + ((i+2)*4)),
4022 (u32)readl_relaxed(base + ((i+3)*4)));
4023 }
4024}
4025
4026static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4027{
4028 /* Dump current state of SDCC clocks, power and irq */
4029 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
4030 (host->pwr ? "ON" : "OFF"));
4031 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
4032 mmc_hostname(host->mmc),
4033 (host->clks_on ? "ON" : "OFF"),
4034 (u32)clk_get_rate(host->clk));
4035 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4036 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4037
4038 /* Now dump SDCC registers. Don't print FIFO registers */
4039 if (host->clks_on)
4040 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
4041
4042 if (host->curr.data) {
4043 if (msmsdcc_check_dma_op_req(host->curr.data))
4044 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4045 else if (host->is_dma_mode)
4046 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4047 mmc_hostname(host->mmc), host->dma.busy,
4048 host->dma.channel, host->dma.crci);
4049 else if (host->is_sps_mode)
4050 pr_info("%s: SPS mode: busy=%d\n",
4051 mmc_hostname(host->mmc), host->sps.busy);
4052
4053 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4054 mmc_hostname(host->mmc), host->curr.xfer_size,
4055 host->curr.data_xfered, host->curr.xfer_remain);
4056 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4057 " wait_for_auto_prog_done=%d,"
4058 " got_auto_prog_done=%d\n",
4059 mmc_hostname(host->mmc), host->curr.got_dataend,
4060 host->prog_enable, host->curr.wait_for_auto_prog_done,
4061 host->curr.got_auto_prog_done);
4062 }
4063
4064}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4066{
4067 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4068 struct mmc_request *mrq;
4069 unsigned long flags;
4070
4071 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004072 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 pr_info("%s: %s: dummy CMD52 timeout\n",
4074 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004075 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004076 }
4077
4078 mrq = host->curr.mrq;
4079
4080 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304081 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4082 mrq->cmd->opcode);
4083 msmsdcc_dump_sdcc_state(host);
4084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 if (!mrq->cmd->error)
4086 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304087 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004089 if (mrq->data && !mrq->data->error)
4090 mrq->data->error = -ETIMEDOUT;
4091 host->curr.data_xfered = 0;
4092 if (host->dma.sg && host->is_dma_mode) {
4093 msm_dmov_stop_cmd(host->dma.channel,
4094 &host->dma.hdr, 0);
4095 } else if (host->sps.sg && host->is_sps_mode) {
4096 /* Stop current SPS transfer */
4097 msmsdcc_sps_exit_curr_xfer(host);
4098 } else {
4099 msmsdcc_reset_and_restore(host);
4100 msmsdcc_stop_data(host);
4101 if (mrq->data && mrq->data->stop)
4102 msmsdcc_start_command(host,
4103 mrq->data->stop, 0);
4104 else
4105 msmsdcc_request_end(host, mrq);
4106 }
4107 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304108 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304109 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004110 msmsdcc_reset_and_restore(host);
4111 msmsdcc_request_end(host, mrq);
4112 }
4113 }
4114 spin_unlock_irqrestore(&host->lock, flags);
4115}
4116
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304117static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4118{
4119 int i, ret;
4120 struct mmc_platform_data *pdata;
4121 struct device_node *np = dev->of_node;
4122 u32 bus_width = 0;
4123 u32 *clk_table;
4124 int clk_table_len;
4125 u32 *sup_voltages;
4126 int sup_volt_len;
4127
4128 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4129 if (!pdata) {
4130 dev_err(dev, "could not allocate memory for platform data\n");
4131 goto err;
4132 }
4133
4134 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4135 if (bus_width == 8) {
4136 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4137 } else if (bus_width == 4) {
4138 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4139 } else {
4140 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4141 pdata->mmc_bus_width = 0;
4142 }
4143
4144 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4145 size_t sz;
4146 sz = sup_volt_len / sizeof(*sup_voltages);
4147 if (sz > 0) {
4148 sup_voltages = devm_kzalloc(dev,
4149 sz * sizeof(*sup_voltages), GFP_KERNEL);
4150 if (!sup_voltages) {
4151 dev_err(dev, "No memory for supported voltage\n");
4152 goto err;
4153 }
4154
4155 ret = of_property_read_u32_array(np,
4156 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4157 if (ret < 0) {
4158 dev_err(dev, "error while reading voltage"
4159 "ranges %d\n", ret);
4160 goto err;
4161 }
4162 } else {
4163 dev_err(dev, "No supported voltages\n");
4164 goto err;
4165 }
4166 for (i = 0; i < sz; i += 2) {
4167 u32 mask;
4168
4169 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4170 sup_voltages[i + 1]);
4171 if (!mask)
4172 dev_err(dev, "Invalide voltage range %d\n", i);
4173 pdata->ocr_mask |= mask;
4174 }
4175 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4176 } else {
4177 dev_err(dev, "Supported voltage range not specified\n");
4178 }
4179
4180 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4181 size_t sz;
4182 sz = clk_table_len / sizeof(*clk_table);
4183
4184 if (sz > 0) {
4185 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4186 GFP_KERNEL);
4187 if (!clk_table) {
4188 dev_err(dev, "No memory for clock table\n");
4189 goto err;
4190 }
4191
4192 ret = of_property_read_u32_array(np,
4193 "qcom,sdcc-clk-rates", clk_table, sz);
4194 if (ret < 0) {
4195 dev_err(dev, "error while reading clk"
4196 "table %d\n", ret);
4197 goto err;
4198 }
4199 } else {
4200 dev_err(dev, "clk_table not specified\n");
4201 goto err;
4202 }
4203 pdata->sup_clk_table = clk_table;
4204 pdata->sup_clk_cnt = sz;
4205 } else {
4206 dev_err(dev, "Supported clock rates not specified\n");
4207 }
4208
4209 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4210 pdata->nonremovable = true;
4211 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4212 pdata->disable_cmd23 = true;
4213
4214 return pdata;
4215err:
4216 return NULL;
4217}
4218
San Mehat9d2bd732009-09-22 16:44:22 -07004219static int
4220msmsdcc_probe(struct platform_device *pdev)
4221{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304222 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004223 struct msmsdcc_host *host;
4224 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225 unsigned long flags;
4226 struct resource *core_irqres = NULL;
4227 struct resource *bam_irqres = NULL;
4228 struct resource *core_memres = NULL;
4229 struct resource *dml_memres = NULL;
4230 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004231 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004232 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304233 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004235
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304236 if (pdev->dev.of_node) {
4237 plat = msmsdcc_populate_pdata(&pdev->dev);
4238 of_property_read_u32((&pdev->dev)->of_node,
4239 "cell-index", &pdev->id);
4240 } else {
4241 plat = pdev->dev.platform_data;
4242 }
4243
San Mehat9d2bd732009-09-22 16:44:22 -07004244 /* must have platform data */
4245 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004246 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004247 ret = -EINVAL;
4248 goto out;
4249 }
4250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004252 return -EINVAL;
4253
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304254 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4255 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4256 return -EINVAL;
4257 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004258
San Mehat9d2bd732009-09-22 16:44:22 -07004259 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004260 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004261 return -ENXIO;
4262 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304263 if (pdev->dev.of_node) {
4264 /*
4265 * Device tree iomem resources are only accessible by index.
4266 * index = 0 -> SDCC register interface
4267 * index = 1 -> DML register interface
4268 * index = 2 -> BAM register interface
4269 * IRQ resources:
4270 * index = 0 -> SDCC IRQ
4271 * index = 1 -> BAM IRQ
4272 */
4273 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4274 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4275 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4276 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4277 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4278 } else {
4279 for (i = 0; i < pdev->num_resources; i++) {
4280 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4281 if (!strncmp(pdev->resource[i].name,
4282 "sdcc_dml_addr",
4283 sizeof("sdcc_dml_addr")))
4284 dml_memres = &pdev->resource[i];
4285 else if (!strncmp(pdev->resource[i].name,
4286 "sdcc_bam_addr",
4287 sizeof("sdcc_bam_addr")))
4288 bam_memres = &pdev->resource[i];
4289 else
4290 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004291
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304292 }
4293 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4294 if (!strncmp(pdev->resource[i].name,
4295 "sdcc_bam_irq",
4296 sizeof("sdcc_bam_irq")))
4297 bam_irqres = &pdev->resource[i];
4298 else
4299 core_irqres = &pdev->resource[i];
4300 }
4301 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4302 if (!strncmp(pdev->resource[i].name,
4303 "sdcc_dma_chnl",
4304 sizeof("sdcc_dma_chnl")))
4305 dmares = &pdev->resource[i];
4306 else if (!strncmp(pdev->resource[i].name,
4307 "sdcc_dma_crci",
4308 sizeof("sdcc_dma_crci")))
4309 dma_crci_res = &pdev->resource[i];
4310 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004311 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004312 }
4313
4314 if (!core_irqres || !core_memres) {
4315 pr_err("%s: Invalid sdcc core resource\n", __func__);
4316 return -ENXIO;
4317 }
4318
4319 /*
4320 * Both BAM and DML memory resource should be preset.
4321 * BAM IRQ resource should also be present.
4322 */
4323 if ((bam_memres && !dml_memres) ||
4324 (!bam_memres && dml_memres) ||
4325 ((bam_memres && dml_memres) && !bam_irqres)) {
4326 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004327 return -ENXIO;
4328 }
4329
4330 /*
4331 * Setup our host structure
4332 */
San Mehat9d2bd732009-09-22 16:44:22 -07004333 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4334 if (!mmc) {
4335 ret = -ENOMEM;
4336 goto out;
4337 }
4338
4339 host = mmc_priv(mmc);
4340 host->pdev_id = pdev->id;
4341 host->plat = plat;
4342 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004343 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304344
4345 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004346 host->is_sps_mode = 1;
4347 else if (dmares)
4348 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004350 host->base = ioremap(core_memres->start,
4351 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004352 if (!host->base) {
4353 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004354 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004355 }
4356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357 host->core_irqres = core_irqres;
4358 host->bam_irqres = bam_irqres;
4359 host->core_memres = core_memres;
4360 host->dml_memres = dml_memres;
4361 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004362 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004363 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004364 spin_lock_init(&host->lock);
4365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366#ifdef CONFIG_MMC_EMBEDDED_SDIO
4367 if (plat->embedded_sdio)
4368 mmc_set_embedded_sdio_data(mmc,
4369 &plat->embedded_sdio->cis,
4370 &plat->embedded_sdio->cccr,
4371 plat->embedded_sdio->funcs,
4372 plat->embedded_sdio->num_funcs);
4373#endif
4374
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304375 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4376 (unsigned long)host);
4377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004378 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4379 (unsigned long)host);
4380 if (host->is_dma_mode) {
4381 /* Setup DMA */
4382 ret = msmsdcc_init_dma(host);
4383 if (ret)
4384 goto ioremap_free;
4385 } else {
4386 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004387 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004388 }
4389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004390 /*
4391 * Setup SDCC clock if derived from Dayatona
4392 * fabric core clock.
4393 */
4394 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004395 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004396 if (!IS_ERR(host->dfab_pclk)) {
4397 /* Set the clock rate to 64MHz for max. performance */
4398 ret = clk_set_rate(host->dfab_pclk, 64000000);
4399 if (ret)
4400 goto dfab_pclk_put;
4401 ret = clk_enable(host->dfab_pclk);
4402 if (ret)
4403 goto dfab_pclk_put;
4404 } else
4405 goto dma_free;
4406 }
4407
4408 /*
4409 * Setup main peripheral bus clock
4410 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004411 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004412 if (!IS_ERR(host->pclk)) {
4413 ret = clk_enable(host->pclk);
4414 if (ret)
4415 goto pclk_put;
4416
4417 host->pclk_rate = clk_get_rate(host->pclk);
4418 }
4419
4420 /*
4421 * Setup SDC MMC clock
4422 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004423 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004424 if (IS_ERR(host->clk)) {
4425 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004426 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004427 }
4428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004429 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4430 if (ret) {
4431 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4432 goto clk_put;
4433 }
4434
4435 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004436 if (ret)
4437 goto clk_put;
4438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004439 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304440 if (!host->clk_rate)
4441 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304442
4443 /*
4444 * Lookup the Controller Version, to identify the supported features
4445 * Version number read as 0 would indicate SDCC3 or earlier versions
4446 */
4447 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4448 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4449 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304450 /*
4451 * Set the register write delay according to min. clock frequency
4452 * supported and update later when the host->clk_rate changes.
4453 */
4454 host->reg_write_delay =
4455 (1 + ((3 * USEC_PER_SEC) /
4456 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004457
4458 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304459 /* Apply Hard reset to SDCC to put it in power on default state */
4460 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004461
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304462 /* pm qos request to prevent apps idle power collapse */
4463 if (host->plat->swfi_latency)
4464 pm_qos_add_request(&host->pm_qos_req_dma,
4465 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004467 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004468 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004469 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004470 goto clk_disable;
4471 }
4472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004473
4474 /* Clocks has to be running before accessing SPS/DML HW blocks */
4475 if (host->is_sps_mode) {
4476 /* Initialize SPS */
4477 ret = msmsdcc_sps_init(host);
4478 if (ret)
4479 goto vreg_deinit;
4480 /* Initialize DML */
4481 ret = msmsdcc_dml_init(host);
4482 if (ret)
4483 goto sps_exit;
4484 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304485 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004486
San Mehat9d2bd732009-09-22 16:44:22 -07004487 /*
4488 * Setup MMC host structure
4489 */
4490 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004491 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4492 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004493 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4495 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004496
San Mehat9d2bd732009-09-22 16:44:22 -07004497 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304498 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304499
4500 /*
4501 * If we send the CMD23 before multi block write/read command
4502 * then we need not to send CMD12 at the end of the transfer.
4503 * If we don't send the CMD12 then only way to detect the PROG_DONE
4504 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4505 * controller. So let's enable the CMD23 for SDCC4 only.
4506 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304507 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304508 mmc->caps |= MMC_CAP_CMD23;
4509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 mmc->caps |= plat->uhs_caps;
4511 /*
4512 * XPC controls the maximum current in the default speed mode of SDXC
4513 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4514 * XPC=1 means 150mA (max.) and speed class is supported.
4515 */
4516 if (plat->xpc_cap)
4517 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4518 MMC_CAP_SET_XPC_180);
4519
Subhash Jadavani0a0c6272012-03-24 23:13:18 +05304520 mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304521 if (pdev->dev.of_node) {
4522 if (of_get_property((&pdev->dev)->of_node,
4523 "qcom,sdcc-hs200", NULL))
4524 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4525 }
4526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004527 if (plat->nonremovable)
4528 mmc->caps |= MMC_CAP_NONREMOVABLE;
4529#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4530 mmc->caps |= MMC_CAP_SDIO_IRQ;
4531#endif
4532
4533 if (plat->is_sdio_al_client)
4534 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004535
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304536 mmc->max_segs = msmsdcc_get_nr_sg(host);
4537 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4538 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004539
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304540 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304541 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004543 writel_relaxed(0, host->base + MMCIMASK0);
4544 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304545 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004547 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4548 mb();
4549 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4552 DRIVER_NAME " (cmd)", host);
4553 if (ret)
4554 goto dml_exit;
4555
4556 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4557 DRIVER_NAME " (pio)", host);
4558 if (ret)
4559 goto irq_free;
4560
4561 /*
4562 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4563 * IRQ is un-necessarily being monitored by MPM (Modem power
4564 * management block) during idle-power collapse. The MPM will be
4565 * configured to monitor the DATA1 GPIO line with level-low trigger
4566 * and thus depending on the GPIO status, it prevents TCXO shutdown
4567 * during idle-power collapse.
4568 */
4569 disable_irq(core_irqres->start);
4570 host->sdcc_irq_disabled = 1;
4571
4572 if (plat->sdiowakeup_irq) {
4573 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4574 mmc_hostname(mmc));
4575 ret = request_irq(plat->sdiowakeup_irq,
4576 msmsdcc_platform_sdiowakeup_irq,
4577 IRQF_SHARED | IRQF_TRIGGER_LOW,
4578 DRIVER_NAME "sdiowakeup", host);
4579 if (ret) {
4580 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4581 plat->sdiowakeup_irq, ret);
4582 goto pio_irq_free;
4583 } else {
4584 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304585 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004586 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304587 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004588 }
4589 spin_unlock_irqrestore(&host->lock, flags);
4590 }
4591 }
4592
4593 if (plat->cfg_mpm_sdiowakeup) {
4594 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4595 mmc_hostname(mmc));
4596 }
4597
4598 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4599 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004600 /*
4601 * Setup card detect change
4602 */
4603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004605 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004606 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004607 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004608 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004609
Krishna Konda941604a2012-01-10 17:46:34 -08004610 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004611 }
San Mehat9d2bd732009-09-22 16:44:22 -07004612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 if (plat->status_irq) {
4614 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004615 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004617 DRIVER_NAME " (slot)",
4618 host);
4619 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004620 pr_err("Unable to get slot IRQ %d (%d)\n",
4621 plat->status_irq, ret);
4622 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004623 }
4624 } else if (plat->register_status_notify) {
4625 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4626 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004627 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004628 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004629
4630 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004631
4632 ret = pm_runtime_set_active(&(pdev)->dev);
4633 if (ret < 0)
4634 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4635 __func__, ret);
4636 /*
4637 * There is no notion of suspend/resume for SD/MMC/SDIO
4638 * cards. So host can be suspended/resumed with out
4639 * worrying about its children.
4640 */
4641 pm_suspend_ignore_children(&(pdev)->dev, true);
4642
4643 /*
4644 * MMC/SD/SDIO bus suspend/resume operations are defined
4645 * only for the slots that will be used for non-removable
4646 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4647 * defined. Otherwise, they simply become card removal and
4648 * insertion events during suspend and resume respectively.
4649 * Hence, enable run-time PM only for slots for which bus
4650 * suspend/resume operations are defined.
4651 */
4652#ifdef CONFIG_MMC_UNSAFE_RESUME
4653 /*
4654 * If this capability is set, MMC core will enable/disable host
4655 * for every claim/release operation on a host. We use this
4656 * notification to increment/decrement runtime pm usage count.
4657 */
4658 mmc->caps |= MMC_CAP_DISABLE;
4659 pm_runtime_enable(&(pdev)->dev);
4660#else
4661 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4662 mmc->caps |= MMC_CAP_DISABLE;
4663 pm_runtime_enable(&(pdev)->dev);
4664 }
4665#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304666#ifndef CONFIG_PM_RUNTIME
4667 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4668#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004669 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4670 (unsigned long)host);
4671
San Mehat9d2bd732009-09-22 16:44:22 -07004672 mmc_add_host(mmc);
4673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004674#ifdef CONFIG_HAS_EARLYSUSPEND
4675 host->early_suspend.suspend = msmsdcc_early_suspend;
4676 host->early_suspend.resume = msmsdcc_late_resume;
4677 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4678 register_early_suspend(&host->early_suspend);
4679#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004680
Krishna Konda25786ec2011-07-25 16:21:36 -07004681 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4682 " dmacrcri %d\n", mmc_hostname(mmc),
4683 (unsigned long long)core_memres->start,
4684 (unsigned int) core_irqres->start,
4685 (unsigned int) plat->status_irq, host->dma.channel,
4686 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687
4688 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4689 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4690 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4691 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4692 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4693 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4694 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4695 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4696 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4697 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4698 host->eject);
4699 pr_info("%s: Power save feature enable = %d\n",
4700 mmc_hostname(mmc), msmsdcc_pwrsave);
4701
Krishna Konda25786ec2011-07-25 16:21:36 -07004702 if (host->is_dma_mode && host->dma.channel != -1
4703 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004704 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004705 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004706 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004707 mmc_hostname(mmc), host->dma.cmd_busaddr,
4708 host->dma.cmdptr_busaddr);
4709 } else if (host->is_sps_mode) {
4710 pr_info("%s: SPS-BAM data transfer mode available\n",
4711 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004712 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004713 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004715#if defined(CONFIG_DEBUG_FS)
4716 msmsdcc_dbg_createhost(host);
4717#endif
4718 if (!plat->status_irq) {
4719 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4720 if (ret)
4721 goto platform_irq_free;
4722 }
San Mehat9d2bd732009-09-22 16:44:22 -07004723 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004724
4725 platform_irq_free:
4726 del_timer_sync(&host->req_tout_timer);
4727 pm_runtime_disable(&(pdev)->dev);
4728 pm_runtime_set_suspended(&(pdev)->dev);
4729
4730 if (plat->status_irq)
4731 free_irq(plat->status_irq, host);
4732 sdiowakeup_irq_free:
4733 wake_lock_destroy(&host->sdio_suspend_wlock);
4734 if (plat->sdiowakeup_irq)
4735 free_irq(plat->sdiowakeup_irq, host);
4736 pio_irq_free:
4737 if (plat->sdiowakeup_irq)
4738 wake_lock_destroy(&host->sdio_wlock);
4739 free_irq(core_irqres->start, host);
4740 irq_free:
4741 free_irq(core_irqres->start, host);
4742 dml_exit:
4743 if (host->is_sps_mode)
4744 msmsdcc_dml_exit(host);
4745 sps_exit:
4746 if (host->is_sps_mode)
4747 msmsdcc_sps_exit(host);
4748 vreg_deinit:
4749 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004750 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304752 if (host->plat->swfi_latency)
4753 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004754 clk_put:
4755 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004756 pclk_disable:
4757 if (!IS_ERR(host->pclk))
4758 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004759 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004760 if (!IS_ERR(host->pclk))
4761 clk_put(host->pclk);
4762 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4763 clk_disable(host->dfab_pclk);
4764 dfab_pclk_put:
4765 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4766 clk_put(host->dfab_pclk);
4767 dma_free:
4768 if (host->is_dma_mode) {
4769 if (host->dmares)
4770 dma_free_coherent(NULL,
4771 sizeof(struct msmsdcc_nc_dmadata),
4772 host->dma.nc, host->dma.nc_busaddr);
4773 }
4774 ioremap_free:
4775 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004776 host_free:
4777 mmc_free_host(mmc);
4778 out:
4779 return ret;
4780}
4781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004783{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004784 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4785 struct mmc_platform_data *plat;
4786 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788 if (!mmc)
4789 return -ENXIO;
4790
4791 if (pm_runtime_suspended(&(pdev)->dev))
4792 pm_runtime_resume(&(pdev)->dev);
4793
4794 host = mmc_priv(mmc);
4795
4796 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4797 plat = host->plat;
4798
4799 if (!plat->status_irq)
4800 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4801
4802 del_timer_sync(&host->req_tout_timer);
4803 tasklet_kill(&host->dma_tlet);
4804 tasklet_kill(&host->sps.tlet);
4805 mmc_remove_host(mmc);
4806
4807 if (plat->status_irq)
4808 free_irq(plat->status_irq, host);
4809
4810 wake_lock_destroy(&host->sdio_suspend_wlock);
4811 if (plat->sdiowakeup_irq) {
4812 wake_lock_destroy(&host->sdio_wlock);
4813 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4814 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004816
4817 free_irq(host->core_irqres->start, host);
4818 free_irq(host->core_irqres->start, host);
4819
4820 clk_put(host->clk);
4821 if (!IS_ERR(host->pclk))
4822 clk_put(host->pclk);
4823 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4824 clk_put(host->dfab_pclk);
4825
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304826 if (host->plat->swfi_latency)
4827 pm_qos_remove_request(&host->pm_qos_req_dma);
4828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004829 msmsdcc_vreg_init(host, false);
4830
4831 if (host->is_dma_mode) {
4832 if (host->dmares)
4833 dma_free_coherent(NULL,
4834 sizeof(struct msmsdcc_nc_dmadata),
4835 host->dma.nc, host->dma.nc_busaddr);
4836 }
4837
4838 if (host->is_sps_mode) {
4839 msmsdcc_dml_exit(host);
4840 msmsdcc_sps_exit(host);
4841 }
4842
4843 iounmap(host->base);
4844 mmc_free_host(mmc);
4845
4846#ifdef CONFIG_HAS_EARLYSUSPEND
4847 unregister_early_suspend(&host->early_suspend);
4848#endif
4849 pm_runtime_disable(&(pdev)->dev);
4850 pm_runtime_set_suspended(&(pdev)->dev);
4851
4852 return 0;
4853}
4854
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07004855static void msmsdcc_shutdown(struct platform_device *pdev)
4856{
4857 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4858
4859 mmc_remove_host(mmc);
4860 mmc_free_host(mmc);
4861}
4862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004863#ifdef CONFIG_MSM_SDIO_AL
4864int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4865{
4866 struct msmsdcc_host *host = mmc_priv(mmc);
4867 unsigned long flags;
4868
4869 spin_lock_irqsave(&host->lock, flags);
4870 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4871 enable ? "En" : "Dis");
4872
4873 if (enable) {
4874 if (!host->sdcc_irq_disabled) {
4875 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304876 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004877 host->sdcc_irq_disabled = 1;
4878 }
4879
4880 if (host->clks_on) {
4881 msmsdcc_setup_clocks(host, false);
4882 host->clks_on = 0;
4883 }
4884
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304885 if (host->plat->sdio_lpm_gpio_setup &&
4886 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004887 spin_unlock_irqrestore(&host->lock, flags);
4888 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4889 spin_lock_irqsave(&host->lock, flags);
4890 host->sdio_gpio_lpm = 1;
4891 }
4892
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304893 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004894 msmsdcc_enable_irq_wake(host);
4895 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304896 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004897 }
4898 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304899 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004900 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304901 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004902 msmsdcc_disable_irq_wake(host);
4903 }
4904
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304905 if (host->plat->sdio_lpm_gpio_setup &&
4906 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907 spin_unlock_irqrestore(&host->lock, flags);
4908 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4909 spin_lock_irqsave(&host->lock, flags);
4910 host->sdio_gpio_lpm = 0;
4911 }
4912
4913 if (!host->clks_on) {
4914 msmsdcc_setup_clocks(host, true);
4915 host->clks_on = 1;
4916 }
4917
4918 if (host->sdcc_irq_disabled) {
4919 writel_relaxed(host->mci_irqenable,
4920 host->base + MMCIMASK0);
4921 mb();
4922 enable_irq(host->core_irqres->start);
4923 host->sdcc_irq_disabled = 0;
4924 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004925 }
4926 spin_unlock_irqrestore(&host->lock, flags);
4927 return 0;
4928}
4929#else
4930int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4931{
4932 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004933}
4934#endif
4935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004937static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004938msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004939{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940 struct mmc_host *mmc = dev_get_drvdata(dev);
4941 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004942 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304943 unsigned long flags;
4944
San Mehat9d2bd732009-09-22 16:44:22 -07004945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004946 if (host->plat->is_sdio_al_client)
4947 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304948 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004949 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004950 host->sdcc_suspending = 1;
4951 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004953 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004954 * MMC core thinks that host is disabled by now since
4955 * runtime suspend is scheduled after msmsdcc_disable()
4956 * is called. Thus, MMC core will try to enable the host
4957 * while suspending it. This results in a synchronous
4958 * runtime resume request while in runtime suspending
4959 * context and hence inorder to complete this resume
4960 * requet, it will wait for suspend to be complete,
4961 * but runtime suspend also can not proceed further
4962 * until the host is resumed. Thus, it leads to a hang.
4963 * Hence, increase the pm usage count before suspending
4964 * the host so that any resume requests after this will
4965 * simple become pm usage counter increment operations.
4966 */
4967 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304968 /* If there is pending detect work abort runtime suspend */
4969 if (unlikely(work_busy(&mmc->detect.work)))
4970 rc = -EAGAIN;
4971 else
4972 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004973 pm_runtime_put_noidle(dev);
4974
4975 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304976 spin_lock_irqsave(&host->lock, flags);
4977 host->sdcc_suspended = true;
4978 spin_unlock_irqrestore(&host->lock, flags);
4979 if (mmc->card && mmc_card_sdio(mmc->card) &&
4980 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004981 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304982 * If SDIO function driver doesn't want
4983 * to power off the card, atleast turn off
4984 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004985 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304986 mmc_host_clk_hold(mmc);
4987 spin_lock_irqsave(&mmc->clk_lock, flags);
4988 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004989 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304990 mmc->clk_gated = true;
4991 spin_unlock_irqrestore(&mmc->clk_lock, flags);
4992 mmc_set_ios(mmc);
4993 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994 }
4995 }
4996 host->sdcc_suspending = 0;
4997 mmc->suspend_task = NULL;
4998 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4999 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005000 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305001 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005002 return rc;
5003}
5004
5005static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005007{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005008 struct mmc_host *mmc = dev_get_drvdata(dev);
5009 struct msmsdcc_host *host = mmc_priv(mmc);
5010 unsigned long flags;
5011
5012 if (host->plat->is_sdio_al_client)
5013 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005014
Sahitya Tummala7661a452011-07-18 13:28:35 +05305015 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005016 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305017 if (mmc->card && mmc_card_sdio(mmc->card) &&
5018 mmc_card_keep_power(mmc)) {
5019 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305020 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305021 mmc_set_ios(mmc);
5022 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305023 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005024
5025 mmc_resume_host(mmc);
5026
5027 /*
5028 * FIXME: Clearing of flags must be handled in clients
5029 * resume handler.
5030 */
5031 spin_lock_irqsave(&host->lock, flags);
5032 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305033 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 spin_unlock_irqrestore(&host->lock, flags);
5035
5036 /*
5037 * After resuming the host wait for sometime so that
5038 * the SDIO work will be processed.
5039 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305040 if (mmc->card && mmc_card_sdio(mmc->card)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005041 if ((host->plat->cfg_mpm_sdiowakeup ||
5042 host->plat->sdiowakeup_irq) &&
5043 wake_lock_active(&host->sdio_wlock))
5044 wake_lock_timeout(&host->sdio_wlock, 1);
5045 }
5046
5047 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005048 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305049 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005050 return 0;
5051}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005052
5053static int msmsdcc_runtime_idle(struct device *dev)
5054{
5055 struct mmc_host *mmc = dev_get_drvdata(dev);
5056 struct msmsdcc_host *host = mmc_priv(mmc);
5057
5058 if (host->plat->is_sdio_al_client)
5059 return 0;
5060
5061 /* Idle timeout is not configurable for now */
5062 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5063
5064 return -EAGAIN;
5065}
5066
5067static int msmsdcc_pm_suspend(struct device *dev)
5068{
5069 struct mmc_host *mmc = dev_get_drvdata(dev);
5070 struct msmsdcc_host *host = mmc_priv(mmc);
5071 int rc = 0;
5072
5073 if (host->plat->is_sdio_al_client)
5074 return 0;
5075
5076
5077 if (host->plat->status_irq)
5078 disable_irq(host->plat->status_irq);
5079
Subhash Jadavani18702212012-03-19 18:50:18 +05305080 if (!pm_runtime_suspended(dev)) {
5081 if (!(mmc->card && mmc_card_sdio(mmc->card))) {
5082 /*
5083 * decrement power.usage_counter if it's
5084 * not zero earlier
5085 */
5086 pm_runtime_put_noidle(dev);
5087 rc = pm_runtime_suspend(dev);
5088 }
5089
5090 /*
5091 * if device runtime PM status is still not suspended
5092 * then perform suspend here.
5093 */
5094 if (!pm_runtime_suspended(dev))
5095 rc = msmsdcc_runtime_suspend(dev);
5096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005097
5098 return rc;
5099}
5100
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305101static int msmsdcc_suspend_noirq(struct device *dev)
5102{
5103 struct mmc_host *mmc = dev_get_drvdata(dev);
5104 struct msmsdcc_host *host = mmc_priv(mmc);
5105 int rc = 0;
5106
5107 /*
5108 * After platform suspend there may be active request
5109 * which might have enabled clocks. For example, in SDIO
5110 * case, ksdioirq thread might have scheduled after sdcc
5111 * suspend but before system freeze. In that case abort
5112 * suspend and retry instead of keeping the clocks on
5113 * during suspend and not allowing TCXO.
5114 */
5115
5116 if (host->clks_on) {
5117 pr_warn("%s: clocks are on after suspend, aborting system "
5118 "suspend\n", mmc_hostname(mmc));
5119 rc = -EAGAIN;
5120 }
5121
5122 return rc;
5123}
5124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005125static int msmsdcc_pm_resume(struct device *dev)
5126{
5127 struct mmc_host *mmc = dev_get_drvdata(dev);
5128 struct msmsdcc_host *host = mmc_priv(mmc);
5129 int rc = 0;
5130
5131 if (host->plat->is_sdio_al_client)
5132 return 0;
5133
Sahitya Tummalafb486372011-09-02 19:01:49 +05305134 if (!pm_runtime_suspended(dev))
5135 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005136 if (host->plat->status_irq) {
5137 msmsdcc_check_status((unsigned long)host);
5138 enable_irq(host->plat->status_irq);
5139 }
5140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005141 return rc;
5142}
5143
Daniel Walker08ecfde2010-06-23 12:32:20 -07005144#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005145#define msmsdcc_runtime_suspend NULL
5146#define msmsdcc_runtime_resume NULL
5147#define msmsdcc_runtime_idle NULL
5148#define msmsdcc_pm_suspend NULL
5149#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305150#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005151#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005153static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5154 .runtime_suspend = msmsdcc_runtime_suspend,
5155 .runtime_resume = msmsdcc_runtime_resume,
5156 .runtime_idle = msmsdcc_runtime_idle,
5157 .suspend = msmsdcc_pm_suspend,
5158 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305159 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005160};
5161
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305162static const struct of_device_id msmsdcc_dt_match[] = {
5163 {.compatible = "qcom,msm-sdcc"},
5164
5165};
5166MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5167
San Mehat9d2bd732009-09-22 16:44:22 -07005168static struct platform_driver msmsdcc_driver = {
5169 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005170 .remove = msmsdcc_remove,
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07005171 .shutdown = msmsdcc_shutdown,
San Mehat9d2bd732009-09-22 16:44:22 -07005172 .driver = {
5173 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005174 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305175 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005176 },
5177};
5178
5179static int __init msmsdcc_init(void)
5180{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005181#if defined(CONFIG_DEBUG_FS)
5182 int ret = 0;
5183 ret = msmsdcc_dbg_init();
5184 if (ret) {
5185 pr_err("Failed to create debug fs dir \n");
5186 return ret;
5187 }
5188#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005189 return platform_driver_register(&msmsdcc_driver);
5190}
5191
5192static void __exit msmsdcc_exit(void)
5193{
5194 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005195
5196#if defined(CONFIG_DEBUG_FS)
5197 debugfs_remove(debugfs_file);
5198 debugfs_remove(debugfs_dir);
5199#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005200}
5201
5202module_init(msmsdcc_init);
5203module_exit(msmsdcc_exit);
5204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005206MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005207
5208#if defined(CONFIG_DEBUG_FS)
5209
5210static int
5211msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5212{
5213 file->private_data = inode->i_private;
5214 return 0;
5215}
5216
5217static ssize_t
5218msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5219 size_t count, loff_t *ppos)
5220{
5221 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005222 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005223 int max, i;
5224
5225 i = 0;
5226 max = sizeof(buf) - 1;
5227
5228 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5229 host->curr.cmd, host->curr.data);
5230 if (host->curr.cmd) {
5231 struct mmc_command *cmd = host->curr.cmd;
5232
5233 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5234 cmd->opcode, cmd->arg, cmd->flags);
5235 }
5236 if (host->curr.data) {
5237 struct mmc_data *data = host->curr.data;
5238 i += scnprintf(buf + i, max - i,
5239 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5240 data->timeout_ns, data->timeout_clks,
5241 data->blksz, data->blocks, data->error,
5242 data->flags);
5243 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5244 host->curr.xfer_size, host->curr.xfer_remain,
5245 host->curr.data_xfered, host->dma.sg);
5246 }
5247
5248 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5249}
5250
5251static const struct file_operations msmsdcc_dbg_state_ops = {
5252 .read = msmsdcc_dbg_state_read,
5253 .open = msmsdcc_dbg_state_open,
5254};
5255
5256static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5257{
5258 if (debugfs_dir) {
5259 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5260 0644, debugfs_dir, host,
5261 &msmsdcc_dbg_state_ops);
5262 }
5263}
5264
5265static int __init msmsdcc_dbg_init(void)
5266{
5267 int err;
5268
5269 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5270 if (IS_ERR(debugfs_dir)) {
5271 err = PTR_ERR(debugfs_dir);
5272 debugfs_dir = NULL;
5273 return err;
5274 }
5275
5276 return 0;
5277}
5278#endif