blob: e91cf3e3f5c72582a5436324ba6d5f62b6468a8a [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
1187 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1188 pr_err("%s: Data CRC error\n",
1189 mmc_hostname(host->mmc));
1190 pr_err("%s: opcode 0x%.8x\n", __func__,
1191 data->mrq->cmd->opcode);
1192 pr_err("%s: blksz %d, blocks %d\n", __func__,
1193 data->blksz, data->blocks);
1194 data->error = -EILSEQ;
1195 }
San Mehat9d2bd732009-09-22 16:44:22 -07001196 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 /* CRC is optional for the bus test commands, not all
1198 * cards respond back with CRC. However controller
1199 * waits for the CRC and times out. Hence ignore the
1200 * data timeouts during the Bustest.
1201 */
1202 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1203 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301204 pr_err("%s: CMD%d: Data timeout\n",
1205 mmc_hostname(host->mmc),
1206 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301208 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 }
San Mehat9d2bd732009-09-22 16:44:22 -07001210 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001211 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001212 data->error = -EIO;
1213 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001214 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001215 data->error = -EIO;
1216 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001217 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001219 data->error = -EIO;
1220 }
San Mehat9d2bd732009-09-22 16:44:22 -07001221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001223 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 host->dummy_52_needed = 0;
1225}
San Mehat9d2bd732009-09-22 16:44:22 -07001226
1227static int
1228msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1229{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001231 uint32_t *ptr = (uint32_t *) buffer;
1232 int count = 0;
1233
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301234 if (remain % 4)
1235 remain = ((remain >> 2) + 1) << 2;
1236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1238
1239 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001240 ptr++;
1241 count += sizeof(uint32_t);
1242
1243 remain -= sizeof(uint32_t);
1244 if (remain == 0)
1245 break;
1246 }
1247 return count;
1248}
1249
1250static int
1251msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001253{
1254 void __iomem *base = host->base;
1255 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 while (readl_relaxed(base + MMCISTATUS) &
1259 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1260 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001261
San Mehat9d2bd732009-09-22 16:44:22 -07001262 count = min(remain, maxcnt);
1263
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301264 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1265 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001266 ptr += count;
1267 remain -= count;
1268
1269 if (remain == 0)
1270 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 }
1272 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001273
1274 return ptr - buffer;
1275}
1276
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001277/*
1278 * Copy up to a word (4 bytes) between a scatterlist
1279 * and a temporary bounce buffer when the word lies across
1280 * two pages. The temporary buffer can then be read to/
1281 * written from the FIFO once.
1282 */
1283static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1284{
1285 struct msmsdcc_pio_data *pio = &host->pio;
1286 unsigned int bytes_avail;
1287
1288 if (host->curr.data->flags & MMC_DATA_READ)
1289 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1290 pio->bounce_buf_len);
1291 else
1292 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1293 pio->bounce_buf_len);
1294
1295 while (pio->bounce_buf_len != 4) {
1296 if (!sg_miter_next(&pio->sg_miter))
1297 break;
1298 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1299 4 - pio->bounce_buf_len);
1300 if (host->curr.data->flags & MMC_DATA_READ)
1301 memcpy(pio->sg_miter.addr,
1302 &pio->bounce_buf[pio->bounce_buf_len],
1303 bytes_avail);
1304 else
1305 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1306 pio->sg_miter.addr, bytes_avail);
1307
1308 pio->sg_miter.consumed = bytes_avail;
1309 pio->bounce_buf_len += bytes_avail;
1310 }
1311}
1312
1313/*
1314 * Use sg_miter_next to return as many 4-byte aligned
1315 * chunks as possible, using a temporary 4 byte buffer
1316 * for alignment if necessary
1317 */
1318static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1319{
1320 struct msmsdcc_pio_data *pio = &host->pio;
1321 unsigned int length, rlength;
1322 char *buffer;
1323
1324 if (!sg_miter_next(&pio->sg_miter))
1325 return 0;
1326
1327 buffer = pio->sg_miter.addr;
1328 length = pio->sg_miter.length;
1329
1330 if (length < host->curr.xfer_remain) {
1331 rlength = round_down(length, 4);
1332 if (rlength) {
1333 /*
1334 * We have a 4-byte aligned chunk.
1335 * The rounding will be reflected by
1336 * a call to msmsdcc_sg_consumed
1337 */
1338 length = rlength;
1339 goto sg_next_end;
1340 }
1341 /*
1342 * We have a length less than 4 bytes. Check to
1343 * see if more buffer is available, and combine
1344 * to make 4 bytes if possible.
1345 */
1346 pio->bounce_buf_len = length;
1347 memset(pio->bounce_buf, 0, 4);
1348
1349 /*
1350 * On a read, get 4 bytes from FIFO, and distribute
1351 * (4-bouce_buf_len) bytes into consecutive
1352 * sgl buffers when msmsdcc_sg_consumed is called
1353 */
1354 if (host->curr.data->flags & MMC_DATA_READ) {
1355 buffer = pio->bounce_buf;
1356 length = 4;
1357 goto sg_next_end;
1358 } else {
1359 _msmsdcc_sg_consume_word(host);
1360 buffer = pio->bounce_buf;
1361 length = pio->bounce_buf_len;
1362 }
1363 }
1364
1365sg_next_end:
1366 *buf = buffer;
1367 *len = length;
1368 return 1;
1369}
1370
1371/*
1372 * Update sg_miter.consumed based on how many bytes were
1373 * consumed. If the bounce buffer was used to read from FIFO,
1374 * redistribute into sgls.
1375 */
1376static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1377 unsigned int length)
1378{
1379 struct msmsdcc_pio_data *pio = &host->pio;
1380
1381 if (host->curr.data->flags & MMC_DATA_READ) {
1382 if (length > pio->sg_miter.consumed)
1383 /*
1384 * consumed 4 bytes, but sgl
1385 * describes < 4 bytes
1386 */
1387 _msmsdcc_sg_consume_word(host);
1388 else
1389 pio->sg_miter.consumed = length;
1390 } else
1391 if (length < pio->sg_miter.consumed)
1392 pio->sg_miter.consumed = length;
1393}
1394
1395static void msmsdcc_sg_start(struct msmsdcc_host *host)
1396{
1397 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1398
1399 host->pio.bounce_buf_len = 0;
1400
1401 if (host->curr.data->flags & MMC_DATA_READ)
1402 sg_miter_flags |= SG_MITER_TO_SG;
1403 else
1404 sg_miter_flags |= SG_MITER_FROM_SG;
1405
1406 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1407 host->curr.data->sg_len, sg_miter_flags);
1408}
1409
1410static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1411{
1412 sg_miter_stop(&host->pio.sg_miter);
1413}
1414
San Mehat1cd22962010-02-03 12:59:29 -08001415static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001416msmsdcc_pio_irq(int irq, void *dev_id)
1417{
1418 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001420 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001421 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001422 unsigned int remain;
1423 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001424
Murali Palnati36448a42011-09-02 15:06:18 +05301425 spin_lock(&host->lock);
1426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301430 (MCI_IRQ_PIO)) == 0) {
1431 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301433 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434#if IRQ_DEBUG
1435 msmsdcc_print_status(host, "irq1-r", status);
1436#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001437 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001439 do {
1440 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1443 | MCI_RXDATAAVLBL)))
1444 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001445
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001446 if (!msmsdcc_sg_next(host, &buffer, &remain))
1447 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448
San Mehat9d2bd732009-09-22 16:44:22 -07001449 len = 0;
1450 if (status & MCI_RXACTIVE)
1451 len = msmsdcc_pio_read(host, buffer, remain);
1452 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001454
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301455 /* len might have aligned to 32bits above */
1456 if (len > remain)
1457 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001458
San Mehat9d2bd732009-09-22 16:44:22 -07001459 host->curr.xfer_remain -= len;
1460 host->curr.data_xfered += len;
1461 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001462 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 if (remain) /* Done with this page? */
1465 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001468 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001469
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001470 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001471 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1474 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1475 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1476 host->base + MMCIMASK0);
1477 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301478 /*
1479 * back to back write to MASK0 register don't need
1480 * synchronization delay.
1481 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1483 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1484 }
1485 mb();
1486 } else if (!host->curr.xfer_remain) {
1487 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1488 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1489 mb();
1490 }
San Mehat9d2bd732009-09-22 16:44:22 -07001491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001493
1494 return IRQ_HANDLED;
1495}
1496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497static void
1498msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1499
1500static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1501 struct mmc_data *data)
1502{
1503 u32 loop_cnt = 0;
1504
1505 /*
1506 * For read commands with data less than fifo size, it is possible to
1507 * get DATAEND first and RXDATA_AVAIL might be set later because of
1508 * synchronization delay through the asynchronous RX FIFO. Thus, for
1509 * such cases, even after DATAEND interrupt is received software
1510 * should poll for RXDATA_AVAIL until the requested data is read out
1511 * of FIFO. This change is needed to get around this abnormal but
1512 * sometimes expected behavior of SDCC3 controller.
1513 *
1514 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1515 * after the data is loaded into RX FIFO. This would amount to less
1516 * than a microsecond and thus looping for 1000 times is good enough
1517 * for that delay.
1518 */
1519 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1520 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1521 spin_unlock(&host->lock);
1522 msmsdcc_pio_irq(1, host);
1523 spin_lock(&host->lock);
1524 }
1525 }
1526 if (loop_cnt == 1000) {
1527 pr_info("%s: Timed out while polling for Rx Data\n",
1528 mmc_hostname(host->mmc));
1529 data->error = -ETIMEDOUT;
1530 msmsdcc_reset_and_restore(host);
1531 }
1532}
1533
San Mehat9d2bd732009-09-22 16:44:22 -07001534static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1535{
1536 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001537
1538 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1540 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1541 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1542 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301545 pr_debug("%s: CMD%d: Command timeout\n",
1546 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001547 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301549 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301550 pr_err("%s: CMD%d: Command CRC error\n",
1551 mmc_hostname(host->mmc), cmd->opcode);
1552 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001553 cmd->error = -EILSEQ;
1554 }
1555
1556 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 if (host->curr.data && host->dma.sg &&
1558 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001559 msm_dmov_stop_cmd(host->dma.channel,
1560 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 else if (host->curr.data && host->sps.sg &&
1562 host->is_sps_mode){
1563 /* Stop current SPS transfer */
1564 msmsdcc_sps_exit_curr_xfer(host);
1565 }
San Mehat9d2bd732009-09-22 16:44:22 -07001566 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301567 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001568 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301569 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301570 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301571 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301572 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301574 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301576 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301577 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301578 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301579 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001580 if (host->dummy_52_needed)
1581 host->dummy_52_needed = 0;
1582 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301584 msmsdcc_request_end(host, cmd->mrq);
1585 }
1586 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301587 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1588 if (cmd->data->flags & MMC_DATA_READ)
1589 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1590 else
1591 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301592 } else if (cmd->data) {
1593 if (!(cmd->data->flags & MMC_DATA_READ))
1594 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001595 }
1596}
1597
San Mehat9d2bd732009-09-22 16:44:22 -07001598static irqreturn_t
1599msmsdcc_irq(int irq, void *dev_id)
1600{
1601 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001602 u32 status;
1603 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001605
1606 spin_lock(&host->lock);
1607
1608 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 struct mmc_command *cmd;
1610 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001612 if (timer) {
1613 timer = 0;
1614 msmsdcc_delay(host);
1615 }
San Mehat865c8062009-11-13 13:42:06 -08001616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 if (!host->clks_on) {
1618 pr_debug("%s: %s: SDIO async irq received\n",
1619 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301620
1621 /*
1622 * Only async interrupt can come when clocks are off,
1623 * disable further interrupts and enable them when
1624 * clocks are on.
1625 */
1626 if (!host->sdcc_irq_disabled) {
1627 disable_irq_nosync(irq);
1628 host->sdcc_irq_disabled = 1;
1629 }
1630
1631 /*
1632 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1633 * will take care of signaling sdio irq during
1634 * mmc_sdio_resume().
1635 */
1636 if (host->sdcc_suspended)
1637 /*
1638 * This is a wakeup interrupt so hold wakelock
1639 * until SDCC resume is handled.
1640 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301642 else
1643 mmc_signal_sdio_irq(host->mmc);
1644 ret = 1;
1645 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 }
1647
1648 status = readl_relaxed(host->base + MMCISTATUS);
1649
1650 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1651 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001652 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654#if IRQ_DEBUG
1655 msmsdcc_print_status(host, "irq0-r", status);
1656#endif
1657 status &= readl_relaxed(host->base + MMCIMASK0);
1658 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301659 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301660 if (host->clk_rate <=
1661 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301662 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663#if IRQ_DEBUG
1664 msmsdcc_print_status(host, "irq0-p", status);
1665#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1668 if (status & MCI_SDIOINTROPE) {
1669 if (host->sdcc_suspending)
1670 wake_lock(&host->sdio_suspend_wlock);
1671 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001672 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001674 data = host->curr.data;
1675
1676 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1678 MCI_CMDTIMEOUT)) {
1679 if (status & MCI_CMDTIMEOUT)
1680 pr_debug("%s: dummy CMD52 timeout\n",
1681 mmc_hostname(host->mmc));
1682 if (status & MCI_CMDCRCFAIL)
1683 pr_debug("%s: dummy CMD52 CRC failed\n",
1684 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001685 host->dummy_52_sent = 0;
1686 host->dummy_52_needed = 0;
1687 if (data) {
1688 msmsdcc_stop_data(host);
1689 msmsdcc_request_end(host, data->mrq);
1690 }
1691 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 spin_unlock(&host->lock);
1693 return IRQ_HANDLED;
1694 }
1695 break;
1696 }
1697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 /*
1699 * Check for proper command response
1700 */
1701 cmd = host->curr.cmd;
1702 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1703 MCI_CMDTIMEOUT | MCI_PROGDONE |
1704 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1705 msmsdcc_do_cmdirq(host, status);
1706 }
1707
Sathish Ambley081d7842011-11-29 11:19:41 -08001708 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 /* Check for data errors */
1710 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1711 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1712 msmsdcc_data_err(host, data, status);
1713 host->curr.data_xfered = 0;
1714 if (host->dma.sg && host->is_dma_mode)
1715 msm_dmov_stop_cmd(host->dma.channel,
1716 &host->dma.hdr, 0);
1717 else if (host->sps.sg && host->is_sps_mode) {
1718 /* Stop current SPS transfer */
1719 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301720 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721 msmsdcc_reset_and_restore(host);
1722 if (host->curr.data)
1723 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301724 if (!data->stop || (host->curr.mrq->sbc
1725 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726 timer |=
1727 msmsdcc_request_end(host,
1728 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301729 else if ((host->curr.mrq->sbc
1730 && data->error) ||
1731 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 msmsdcc_start_command(host,
1733 data->stop,
1734 0);
1735 timer = 1;
1736 }
1737 }
1738 }
1739
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301740 /* Check for prog done */
1741 if (host->curr.wait_for_auto_prog_done &&
1742 (status & MCI_PROGDONE))
1743 host->curr.got_auto_prog_done = 1;
1744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 /* Check for data done */
1746 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1747 host->curr.got_dataend = 1;
1748
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301749 if (host->curr.got_dataend &&
1750 (!host->curr.wait_for_auto_prog_done ||
1751 (host->curr.wait_for_auto_prog_done &&
1752 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 /*
1754 * If DMA is still in progress, we complete
1755 * via the completion handler
1756 */
1757 if (!host->dma.busy && !host->sps.busy) {
1758 /*
1759 * There appears to be an issue in the
1760 * controller where if you request a
1761 * small block transfer (< fifo size),
1762 * you may get your DATAEND/DATABLKEND
1763 * irq without the PIO data irq.
1764 *
1765 * Check to see if theres still data
1766 * to be read, and simulate a PIO irq.
1767 */
1768 if (data->flags & MMC_DATA_READ)
1769 msmsdcc_wait_for_rxdata(host,
1770 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001771 if (!data->error) {
1772 host->curr.data_xfered =
1773 host->curr.xfer_size;
1774 host->curr.xfer_remain -=
1775 host->curr.xfer_size;
1776 }
1777
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001778 if (!host->dummy_52_needed) {
1779 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301780 if (!data->stop ||
1781 (host->curr.mrq->sbc
1782 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001783 msmsdcc_request_end(
1784 host,
1785 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301786 else if ((host->curr.mrq->sbc
1787 && data->error) ||
1788 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001789 msmsdcc_start_command(
1790 host,
1791 data->stop, 0);
1792 timer = 1;
1793 }
1794 } else {
1795 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001797 &dummy52cmd,
1798 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 }
1800 }
1801 }
1802 }
1803
San Mehat9d2bd732009-09-22 16:44:22 -07001804 ret = 1;
1805 } while (status);
1806
1807 spin_unlock(&host->lock);
1808
San Mehat9d2bd732009-09-22 16:44:22 -07001809 return IRQ_RETVAL(ret);
1810}
1811
1812static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1814{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301815 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301817 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301818 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1819 else
1820 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 } else {
1822 msmsdcc_start_command(host, mrq->cmd, 0);
1823 }
1824}
1825
1826static void
San Mehat9d2bd732009-09-22 16:44:22 -07001827msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1828{
1829 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 /*
1833 * Get the SDIO AL client out of LPM.
1834 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001835 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 if (host->plat->is_sdio_al_client)
1837 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001838
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301839 /* check if sps pipe reset is pending? */
1840 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1841 msmsdcc_sps_pipes_reset_and_restore(host);
1842 host->sps.pipe_reset_pending = false;
1843 }
1844
San Mehat9d2bd732009-09-22 16:44:22 -07001845 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 WARN(host->curr.mrq, "Request in progress\n");
1847 WARN(!host->pwr, "SDCC power is turned off\n");
1848 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1849 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001850
1851 if (host->eject) {
1852 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1853 mrq->cmd->error = 0;
1854 mrq->data->bytes_xfered = mrq->data->blksz *
1855 mrq->data->blocks;
1856 } else
1857 mrq->cmd->error = -ENOMEDIUM;
1858
1859 spin_unlock_irqrestore(&host->lock, flags);
1860 mmc_request_done(mmc, mrq);
1861 return;
1862 }
1863
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301864 /*
1865 * Kick the software command timeout timer here.
1866 * Timer expires in 10 secs.
1867 */
1868 mod_timer(&host->req_tout_timer,
1869 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001870
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301871 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301872 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301873 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1874 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301875 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301877 else
1878 /*
1879 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1880 * write operations using CMD53 and CMD54.
1881 * Setting this bit with CMD53 would
1882 * automatically triggers PROG_DONE interrupt
1883 * without the need of sending dummy CMD52.
1884 */
1885 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301886 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1887 host->sdcc_version) {
1888 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 }
San Mehat9d2bd732009-09-22 16:44:22 -07001890 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301891
Pratibhasagar V00b94332011-10-18 14:57:27 +05301892 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301893 mrq->sbc->mrq = mrq;
1894 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301895 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301896 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301897 msmsdcc_start_command(host, mrq->sbc, 0);
1898 } else {
1899 msmsdcc_request_start(host, mrq);
1900 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301901 } else {
1902 msmsdcc_request_start(host, mrq);
1903 }
1904
San Mehat9d2bd732009-09-22 16:44:22 -07001905 spin_unlock_irqrestore(&host->lock, flags);
1906}
1907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1909 int min_uV, int max_uV)
1910{
1911 int rc = 0;
1912
1913 if (vreg->set_voltage_sup) {
1914 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1915 if (rc) {
1916 pr_err("%s: regulator_set_voltage(%s) failed."
1917 " min_uV=%d, max_uV=%d, rc=%d\n",
1918 __func__, vreg->name, min_uV, max_uV, rc);
1919 }
1920 }
1921
1922 return rc;
1923}
1924
1925static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1926 int uA_load)
1927{
1928 int rc = 0;
1929
Krishna Kondafea60182011-11-01 16:01:34 -07001930 /* regulators that do not support regulator_set_voltage also
1931 do not support regulator_set_optimum_mode */
1932 if (vreg->set_voltage_sup) {
1933 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1934 if (rc < 0)
1935 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1936 "uA_load=%d) failed. rc=%d\n", __func__,
1937 vreg->name, uA_load, rc);
1938 else
1939 /* regulator_set_optimum_mode() can return non zero
1940 * value even for success case.
1941 */
1942 rc = 0;
1943 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944
1945 return rc;
1946}
1947
1948static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1949 struct device *dev)
1950{
1951 int rc = 0;
1952
1953 /* check if regulator is already initialized? */
1954 if (vreg->reg)
1955 goto out;
1956
1957 /* Get the regulator handle */
1958 vreg->reg = regulator_get(dev, vreg->name);
1959 if (IS_ERR(vreg->reg)) {
1960 rc = PTR_ERR(vreg->reg);
1961 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1962 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001963 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001964 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001965
1966 if (regulator_count_voltages(vreg->reg) > 0)
1967 vreg->set_voltage_sup = 1;
1968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969out:
1970 return rc;
1971}
1972
1973static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1974{
1975 if (vreg->reg)
1976 regulator_put(vreg->reg);
1977}
1978
1979/* This init function should be called only once for each SDCC slot */
1980static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1981{
1982 int rc = 0;
1983 struct msm_mmc_slot_reg_data *curr_slot;
1984 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1985 struct device *dev = mmc_dev(host->mmc);
1986
1987 curr_slot = host->plat->vreg_data;
1988 if (!curr_slot)
1989 goto out;
1990
1991 curr_vdd_reg = curr_slot->vdd_data;
1992 curr_vccq_reg = curr_slot->vccq_data;
1993 curr_vddp_reg = curr_slot->vddp_data;
1994
1995 if (is_init) {
1996 /*
1997 * Get the regulator handle from voltage regulator framework
1998 * and then try to set the voltage level for the regulator
1999 */
2000 if (curr_vdd_reg) {
2001 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2002 if (rc)
2003 goto out;
2004 }
2005 if (curr_vccq_reg) {
2006 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2007 if (rc)
2008 goto vdd_reg_deinit;
2009 }
2010 if (curr_vddp_reg) {
2011 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2012 if (rc)
2013 goto vccq_reg_deinit;
2014 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002015 rc = msmsdcc_vreg_reset(host);
2016 if (rc)
2017 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2018 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 goto out;
2020 } else {
2021 /* Deregister all regulators from regulator framework */
2022 goto vddp_reg_deinit;
2023 }
2024vddp_reg_deinit:
2025 if (curr_vddp_reg)
2026 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2027vccq_reg_deinit:
2028 if (curr_vccq_reg)
2029 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2030vdd_reg_deinit:
2031 if (curr_vdd_reg)
2032 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2033out:
2034 return rc;
2035}
2036
2037static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2038{
2039 int rc = 0;
2040
Subhash Jadavanicc922692011-08-01 23:05:01 +05302041 /* Put regulator in HPM (high power mode) */
2042 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2043 if (rc < 0)
2044 goto out;
2045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 if (!vreg->is_enabled) {
2047 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302048 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2049 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002050 if (rc)
2051 goto out;
2052
2053 rc = regulator_enable(vreg->reg);
2054 if (rc) {
2055 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2056 __func__, vreg->name, rc);
2057 goto out;
2058 }
2059 vreg->is_enabled = true;
2060 }
2061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062out:
2063 return rc;
2064}
2065
2066static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2067{
2068 int rc = 0;
2069
2070 /* Never disable regulator marked as always_on */
2071 if (vreg->is_enabled && !vreg->always_on) {
2072 rc = regulator_disable(vreg->reg);
2073 if (rc) {
2074 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2075 __func__, vreg->name, rc);
2076 goto out;
2077 }
2078 vreg->is_enabled = false;
2079
2080 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2081 if (rc < 0)
2082 goto out;
2083
2084 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302085 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002086 if (rc)
2087 goto out;
2088 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2089 /* Put always_on regulator in LPM (low power mode) */
2090 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2091 if (rc < 0)
2092 goto out;
2093 }
2094out:
2095 return rc;
2096}
2097
2098static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2099{
2100 int rc = 0, i;
2101 struct msm_mmc_slot_reg_data *curr_slot;
2102 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2103 struct msm_mmc_reg_data *vreg_table[3];
2104
2105 curr_slot = host->plat->vreg_data;
2106 if (!curr_slot)
2107 goto out;
2108
2109 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2110 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2111 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2112
2113 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2114 if (vreg_table[i]) {
2115 if (enable)
2116 rc = msmsdcc_vreg_enable(vreg_table[i]);
2117 else
2118 rc = msmsdcc_vreg_disable(vreg_table[i]);
2119 if (rc)
2120 goto out;
2121 }
2122 }
2123out:
2124 return rc;
2125}
2126
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002127/*
2128 * Reset vreg by ensuring it is off during probe. A call
2129 * to enable vreg is needed to balance disable vreg
2130 */
2131static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2132{
2133 int rc;
2134
2135 rc = msmsdcc_setup_vreg(host, 1);
2136 if (rc)
2137 return rc;
2138 rc = msmsdcc_setup_vreg(host, 0);
2139 return rc;
2140}
2141
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302142static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143{
2144 int rc = 0;
2145
2146 if (host->plat->vreg_data) {
2147 struct msm_mmc_reg_data *vddp_reg =
2148 host->plat->vreg_data->vddp_data;
2149
2150 if (vddp_reg && vddp_reg->is_enabled)
2151 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2152 }
2153
2154 return rc;
2155}
2156
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302157static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2158{
2159 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2160 int rc = 0;
2161
2162 if (curr_slot && curr_slot->vddp_data) {
2163 rc = msmsdcc_set_vddp_level(host,
2164 curr_slot->vddp_data->low_vol_level);
2165
2166 if (rc)
2167 pr_err("%s: %s: failed to change vddp level to %d",
2168 mmc_hostname(host->mmc), __func__,
2169 curr_slot->vddp_data->low_vol_level);
2170 }
2171
2172 return rc;
2173}
2174
2175static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2176{
2177 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2178 int rc = 0;
2179
2180 if (curr_slot && curr_slot->vddp_data) {
2181 rc = msmsdcc_set_vddp_level(host,
2182 curr_slot->vddp_data->high_vol_level);
2183
2184 if (rc)
2185 pr_err("%s: %s: failed to change vddp level to %d",
2186 mmc_hostname(host->mmc), __func__,
2187 curr_slot->vddp_data->high_vol_level);
2188 }
2189
2190 return rc;
2191}
2192
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302193static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2194{
2195 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2196 int rc = 0;
2197
2198 if (curr_slot && curr_slot->vccq_data) {
2199 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2200 level, level);
2201 if (rc)
2202 pr_err("%s: %s: failed to change vccq level to %d",
2203 mmc_hostname(host->mmc), __func__, level);
2204 }
2205
2206 return rc;
2207}
2208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002209static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2210{
2211 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2212 return 1;
2213 return 0;
2214}
2215
2216static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2217{
2218 if (enable) {
2219 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2220 clk_enable(host->dfab_pclk);
2221 if (!IS_ERR(host->pclk))
2222 clk_enable(host->pclk);
2223 clk_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302224 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302225 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302227 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302228 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229 clk_disable(host->clk);
2230 if (!IS_ERR(host->pclk))
2231 clk_disable(host->pclk);
2232 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2233 clk_disable(host->dfab_pclk);
2234 }
2235}
2236
2237static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2238 unsigned int req_clk)
2239{
2240 unsigned int sel_clk = -1;
2241
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302242 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2243 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2244 goto out;
2245 }
2246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2248 unsigned char cnt;
2249
2250 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2251 if (host->plat->sup_clk_table[cnt] > req_clk)
2252 break;
2253 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2254 sel_clk = host->plat->sup_clk_table[cnt];
2255 break;
2256 } else
2257 sel_clk = host->plat->sup_clk_table[cnt];
2258 }
2259 } else {
2260 if ((req_clk < host->plat->msmsdcc_fmax) &&
2261 (req_clk > host->plat->msmsdcc_fmid))
2262 sel_clk = host->plat->msmsdcc_fmid;
2263 else
2264 sel_clk = req_clk;
2265 }
2266
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302267out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 return sel_clk;
2269}
2270
2271static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2272 struct msmsdcc_host *host)
2273{
2274 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2275 return host->plat->sup_clk_table[0];
2276 else
2277 return host->plat->msmsdcc_fmin;
2278}
2279
2280static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2281 struct msmsdcc_host *host)
2282{
2283 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2284 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2285 else
2286 return host->plat->msmsdcc_fmax;
2287}
2288
2289static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302290{
2291 struct msm_mmc_gpio_data *curr;
2292 int i, rc = 0;
2293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302295 for (i = 0; i < curr->size; i++) {
2296 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 if (curr->gpio[i].is_always_on &&
2298 curr->gpio[i].is_enabled)
2299 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302300 rc = gpio_request(curr->gpio[i].no,
2301 curr->gpio[i].name);
2302 if (rc) {
2303 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2304 mmc_hostname(host->mmc),
2305 curr->gpio[i].no,
2306 curr->gpio[i].name, rc);
2307 goto free_gpios;
2308 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302310 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 if (curr->gpio[i].is_always_on)
2312 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302313 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302315 }
2316 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302318
2319free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302321 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 curr->gpio[i].is_enabled = false;
2323 }
2324out:
2325 return rc;
2326}
2327
2328static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2329{
2330 struct msm_mmc_pad_data *curr;
2331 int i;
2332
2333 curr = host->plat->pin_data->pad_data;
2334 for (i = 0; i < curr->drv->size; i++) {
2335 if (enable)
2336 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2337 curr->drv->on[i].val);
2338 else
2339 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2340 curr->drv->off[i].val);
2341 }
2342
2343 for (i = 0; i < curr->pull->size; i++) {
2344 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002345 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 curr->pull->on[i].val);
2347 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002348 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 curr->pull->off[i].val);
2350 }
2351
2352 return 0;
2353}
2354
2355static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2356{
2357 int rc = 0;
2358
2359 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2360 return 0;
2361
2362 if (host->plat->pin_data->is_gpio)
2363 rc = msmsdcc_setup_gpio(host, enable);
2364 else
2365 rc = msmsdcc_setup_pad(host, enable);
2366
2367 if (!rc)
2368 host->plat->pin_data->cfg_sts = enable;
2369
2370 return rc;
2371}
2372
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302373static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2374{
2375 u32 pwr = 0;
2376 int ret = 0;
2377 struct mmc_host *mmc = host->mmc;
2378
2379 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2380 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2381 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2382 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2383
2384 if (ret) {
2385 pr_err("%s: Failed to setup voltage regulators\n",
2386 mmc_hostname(host->mmc));
2387 goto out;
2388 }
2389
2390 switch (ios->power_mode) {
2391 case MMC_POWER_OFF:
2392 pwr = MCI_PWR_OFF;
2393 if (host->plat->cfg_mpm_sdiowakeup)
2394 host->plat->cfg_mpm_sdiowakeup(
2395 mmc_dev(mmc), SDC_DAT1_DISABLE);
2396 /*
2397 * As VDD pad rail is always on, set low voltage for VDD
2398 * pad rail when slot is unused (when card is not present
2399 * or during system suspend).
2400 */
2401 msmsdcc_set_vddp_low_vol(host);
2402 msmsdcc_setup_pins(host, false);
2403 break;
2404 case MMC_POWER_UP:
2405 /* writing PWR_UP bit is redundant */
2406 pwr = MCI_PWR_UP;
2407 if (host->plat->cfg_mpm_sdiowakeup)
2408 host->plat->cfg_mpm_sdiowakeup(
2409 mmc_dev(mmc), SDC_DAT1_ENABLE);
2410
2411 msmsdcc_set_vddp_high_vol(host);
2412 msmsdcc_setup_pins(host, true);
2413 break;
2414 case MMC_POWER_ON:
2415 pwr = MCI_PWR_ON;
2416 break;
2417 }
2418
2419out:
2420 return pwr;
2421}
2422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2424{
2425 unsigned int wakeup_irq;
2426
2427 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2428 host->plat->sdiowakeup_irq :
2429 host->core_irqres->start;
2430
2431 if (!host->irq_wake_enabled) {
2432 enable_irq_wake(wakeup_irq);
2433 host->irq_wake_enabled = true;
2434 }
2435}
2436
2437static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2438{
2439 unsigned int wakeup_irq;
2440
2441 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2442 host->plat->sdiowakeup_irq :
2443 host->core_irqres->start;
2444
2445 if (host->irq_wake_enabled) {
2446 disable_irq_wake(wakeup_irq);
2447 host->irq_wake_enabled = false;
2448 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302449}
2450
San Mehat9d2bd732009-09-22 16:44:22 -07002451static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302452msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2453{
2454 struct mmc_host *mmc = host->mmc;
2455
2456 /*
2457 * SDIO_AL clients has different mechanism of handling LPM through
2458 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2459 * part of that. Here, we are interested only in clients like WLAN.
2460 */
2461 if (!(mmc->card && mmc_card_sdio(mmc->card))
2462 || host->plat->is_sdio_al_client)
2463 goto out;
2464
2465 if (!host->sdcc_suspended) {
2466 /*
2467 * When MSM is not in power collapse and we
2468 * are disabling clocks, enable bit 22 in MASK0
2469 * to handle asynchronous SDIO interrupts.
2470 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302471 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302472 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302473 mb();
2474 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302475 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302476 msmsdcc_sync_reg_wr(host);
2477 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302478 goto out;
2479 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2480 /*
2481 * Wakeup MSM only if SDIO function drivers set
2482 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2483 */
2484 goto out;
2485 }
2486
2487 if (enable_wakeup_irq) {
2488 if (!host->plat->sdiowakeup_irq) {
2489 /*
2490 * When there is no gpio line that can be configured
2491 * as wakeup interrupt handle it by configuring
2492 * asynchronous sdio interrupts and DAT1 line.
2493 */
2494 writel_relaxed(MCI_SDIOINTMASK,
2495 host->base + MMCIMASK0);
2496 mb();
2497 if (host->plat->cfg_mpm_sdiowakeup)
2498 host->plat->cfg_mpm_sdiowakeup(
2499 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2500 /* configure sdcc core interrupt as wakeup interrupt */
2501 msmsdcc_enable_irq_wake(host);
2502 } else {
2503 /* Let gpio line handle wakeup interrupt */
2504 writel_relaxed(0, host->base + MMCIMASK0);
2505 mb();
2506 if (host->sdio_wakeupirq_disabled) {
2507 host->sdio_wakeupirq_disabled = 0;
2508 /* configure gpio line as wakeup interrupt */
2509 msmsdcc_enable_irq_wake(host);
2510 enable_irq(host->plat->sdiowakeup_irq);
2511 }
2512 }
2513 } else {
2514 if (!host->plat->sdiowakeup_irq) {
2515 /*
2516 * We may not have cleared bit 22 in the interrupt
2517 * handler as the clocks might be off at that time.
2518 */
2519 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302520 msmsdcc_sync_reg_wr(host);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302521 if (host->plat->cfg_mpm_sdiowakeup)
2522 host->plat->cfg_mpm_sdiowakeup(
2523 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2524 msmsdcc_disable_irq_wake(host);
2525 } else if (!host->sdio_wakeupirq_disabled) {
2526 disable_irq_nosync(host->plat->sdiowakeup_irq);
2527 msmsdcc_disable_irq_wake(host);
2528 host->sdio_wakeupirq_disabled = 1;
2529 }
2530 }
2531out:
2532 return;
2533}
2534
2535static void
San Mehat9d2bd732009-09-22 16:44:22 -07002536msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2537{
2538 struct msmsdcc_host *host = mmc_priv(mmc);
2539 u32 clk = 0, pwr = 0;
2540 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002541 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302545
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302546 /*
2547 * Disable SDCC core interrupt until set_ios is completed.
2548 * This avoids any race conditions with interrupt raised
2549 * when turning on/off the clocks. One possible
2550 * scenario is SDIO operational interrupt while the clock
2551 * is turned off.
2552 */
2553
2554 spin_lock_irqsave(&host->lock, flags);
2555 if (!host->sdcc_irq_disabled) {
2556 spin_unlock_irqrestore(&host->lock, flags);
2557 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302559 host->sdcc_irq_disabled = 1;
2560 }
2561 spin_unlock_irqrestore(&host->lock, flags);
2562
2563 pwr = msmsdcc_setup_pwr(host, ios);
2564
2565 spin_lock_irqsave(&host->lock, flags);
2566 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 if (!host->clks_on) {
2568 msmsdcc_setup_clocks(host, true);
2569 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302570 writel_relaxed(host->mci_irqenable,
2571 host->base + MMCIMASK0);
2572 mb();
2573 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002574 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575
2576 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2577 /*
2578 * For DDR50 mode, controller needs clock rate to be
2579 * double than what is required on the SD card CLK pin.
2580 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302581 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582 /*
2583 * Make sure that we don't double the clock if
2584 * doubled clock rate is already set
2585 */
2586 if (!host->ddr_doubled_clk_rate ||
2587 (host->ddr_doubled_clk_rate &&
2588 (host->ddr_doubled_clk_rate != ios->clock))) {
2589 host->ddr_doubled_clk_rate =
2590 msmsdcc_get_sup_clk_rate(
2591 host, (ios->clock * 2));
2592 clock = host->ddr_doubled_clk_rate;
2593 }
2594 } else {
2595 host->ddr_doubled_clk_rate = 0;
2596 }
2597
2598 if (clock != host->clk_rate) {
2599 rc = clk_set_rate(host->clk, clock);
2600 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302601 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002602 mmc_hostname(mmc), clock);
2603 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302604 host->reg_write_delay =
2605 (1 + ((3 * USEC_PER_SEC) /
2606 (host->clk_rate ? host->clk_rate :
2607 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608 }
2609 /*
2610 * give atleast 2 MCLK cycles delay for clocks
2611 * and SDCC core to stabilize
2612 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302613 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002615 clk |= MCI_CLK_ENABLE;
2616 }
2617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 if (ios->bus_width == MMC_BUS_WIDTH_8)
2619 clk |= MCI_CLK_WIDEBUS_8;
2620 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2621 clk |= MCI_CLK_WIDEBUS_4;
2622 else
2623 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 if (msmsdcc_is_pwrsave(host))
2626 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 host->tuning_needed = 0;
2631 /*
2632 * Select the controller timing mode according
2633 * to current bus speed mode
2634 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302635 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2636 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637 clk |= (4 << 14);
2638 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302639 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640 clk |= (3 << 14);
2641 } else {
2642 clk |= (2 << 14); /* feedback clock */
2643 }
2644
2645 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2646 clk |= (2 << 23);
2647
Subhash Jadavani00083572012-02-15 16:18:01 +05302648 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2649 if (!ios->vdd)
2650 host->io_pad_pwr_switch = 0;
2651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 if (host->io_pad_pwr_switch)
2653 clk |= IO_PAD_PWR_SWITCH;
2654
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302655 /* Don't write into registers if clocks are disabled */
2656 if (host->clks_on) {
2657 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2658 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302659 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302661 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2662 host->pwr = pwr;
2663 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302664 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002666 }
2667
2668 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302669 msmsdcc_cfg_sdio_wakeup(host, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 msmsdcc_setup_clocks(host, false);
2671 host->clks_on = 0;
2672 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302673
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302674 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302675 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302676 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302677
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302678 /* Let interrupts be disabled if the host is powered off */
2679 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2680 enable_irq(host->core_irqres->start);
2681 host->sdcc_irq_disabled = 0;
2682 }
2683
San Mehat4adbbcc2009-11-08 13:00:37 -08002684 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002685}
2686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2688{
2689 struct msmsdcc_host *host = mmc_priv(mmc);
2690 u32 clk;
2691
2692 clk = readl_relaxed(host->base + MMCICLOCK);
2693 pr_debug("Changing to pwr_save=%d", pwrsave);
2694 if (pwrsave && msmsdcc_is_pwrsave(host))
2695 clk |= MCI_CLK_PWRSAVE;
2696 else
2697 clk &= ~MCI_CLK_PWRSAVE;
2698 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302699 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700
2701 return 0;
2702}
2703
2704static int msmsdcc_get_ro(struct mmc_host *mmc)
2705{
2706 int status = -ENOSYS;
2707 struct msmsdcc_host *host = mmc_priv(mmc);
2708
2709 if (host->plat->wpswitch) {
2710 status = host->plat->wpswitch(mmc_dev(mmc));
2711 } else if (host->plat->wpswitch_gpio) {
2712 status = gpio_request(host->plat->wpswitch_gpio,
2713 "SD_WP_Switch");
2714 if (status) {
2715 pr_err("%s: %s: Failed to request GPIO %d\n",
2716 mmc_hostname(mmc), __func__,
2717 host->plat->wpswitch_gpio);
2718 } else {
2719 status = gpio_direction_input(
2720 host->plat->wpswitch_gpio);
2721 if (!status) {
2722 /*
2723 * Wait for atleast 300ms as debounce
2724 * time for GPIO input to stabilize.
2725 */
2726 msleep(300);
2727 status = gpio_get_value_cansleep(
2728 host->plat->wpswitch_gpio);
2729 status ^= !host->plat->wpswitch_polarity;
2730 }
2731 gpio_free(host->plat->wpswitch_gpio);
2732 }
2733 }
2734
2735 if (status < 0)
2736 status = -ENOSYS;
2737 pr_debug("%s: Card read-only status %d\n", __func__, status);
2738
2739 return status;
2740}
2741
2742#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002743static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2744{
2745 struct msmsdcc_host *host = mmc_priv(mmc);
2746 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302748 /*
2749 * We may come here with clocks turned off in that case don't
2750 * attempt to write into MASK0 register. While turning on the
2751 * clocks mci_irqenable will be written to MASK0 register.
2752 */
2753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002754 if (enable) {
2755 spin_lock_irqsave(&host->lock, flags);
2756 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302757 if (host->clks_on) {
2758 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302760 mb();
2761 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002762 spin_unlock_irqrestore(&host->lock, flags);
2763 } else {
2764 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302765 if (host->clks_on) {
2766 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302768 mb();
2769 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771}
2772#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2773
2774#ifdef CONFIG_PM_RUNTIME
2775static int msmsdcc_enable(struct mmc_host *mmc)
2776{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302777 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302779 struct msmsdcc_host *host = mmc_priv(mmc);
2780
2781 msmsdcc_pm_qos_update_latency(host, 1);
2782
2783 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2784 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302786 if (dev->power.runtime_status == RPM_SUSPENDING) {
2787 if (mmc->suspend_task == current) {
2788 pm_runtime_get_noresume(dev);
2789 goto out;
2790 }
2791 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302793 rc = pm_runtime_get_sync(dev);
2794
2795 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2797 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302798 return rc;
2799 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302800
2801 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302802out:
2803 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002804}
2805
2806static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2807{
2808 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302809 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002810
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302811 msmsdcc_pm_qos_update_latency(host, 0);
2812
2813 if (mmc->card && mmc_card_sdio(mmc->card))
2814 return 0;
2815
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302816 if (host->plat->disable_runtime_pm)
2817 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818
2819 rc = pm_runtime_put_sync(mmc->parent);
2820
2821 if (rc < 0)
2822 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2823 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302824 else
2825 host->is_resumed = false;
2826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002827 return rc;
2828}
2829#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302830static int msmsdcc_enable(struct mmc_host *mmc)
2831{
2832 struct msmsdcc_host *host = mmc_priv(mmc);
2833 unsigned long flags;
2834
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302835 msmsdcc_pm_qos_update_latency(host, 1);
2836
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302837 spin_lock_irqsave(&host->lock, flags);
2838 if (!host->clks_on) {
2839 msmsdcc_setup_clocks(host, true);
2840 host->clks_on = 1;
2841 }
2842 spin_unlock_irqrestore(&host->lock, flags);
2843
2844 return 0;
2845}
2846
2847static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2848{
2849 struct msmsdcc_host *host = mmc_priv(mmc);
2850 unsigned long flags;
2851
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302852 msmsdcc_pm_qos_update_latency(host, 0);
2853
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302854 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302855 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302856
2857 spin_lock_irqsave(&host->lock, flags);
2858 if (host->clks_on) {
2859 msmsdcc_setup_clocks(host, false);
2860 host->clks_on = 0;
2861 }
2862 spin_unlock_irqrestore(&host->lock, flags);
2863
2864 return 0;
2865}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002866#endif
2867
2868static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2869 struct mmc_ios *ios)
2870{
2871 struct msmsdcc_host *host = mmc_priv(mmc);
2872 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302873 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002874
Subhash Jadavani00083572012-02-15 16:18:01 +05302875 spin_lock_irqsave(&host->lock, flags);
2876 host->io_pad_pwr_switch = 0;
2877 spin_unlock_irqrestore(&host->lock, flags);
2878
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302879 /*
2880 * For eMMC cards, VccQ voltage range must be changed
2881 * only if it operates in HS200 SDR 1.2V mode or in
2882 * DDR 1.2V mode.
2883 */
2884 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
2885 rc = msmsdcc_set_vccq_vol(host, 1200000);
2886 goto out;
2887 }
2888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2890 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302891 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 goto out;
2893 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2894 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302895 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002896 goto out;
2897 }
San Mehat9d2bd732009-09-22 16:44:22 -07002898
2899 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002900 /*
2901 * If we are here means voltage switch from high voltage to
2902 * low voltage is required
2903 */
2904
2905 /*
2906 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2907 * register until they become all zeros.
2908 */
2909 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302910 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2912 mmc_hostname(mmc), __func__);
2913 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002914 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915
2916 /* Stop SD CLK output. */
2917 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2918 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302919 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002920 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002921
2922 /*
2923 * Switch VDDPX from high voltage to low voltage
2924 * to change the VDD of the SD IO pads.
2925 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302926 rc = msmsdcc_set_vddp_low_vol(host);
2927 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929
2930 spin_lock_irqsave(&host->lock, flags);
2931 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2932 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302933 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 host->io_pad_pwr_switch = 1;
2935 spin_unlock_irqrestore(&host->lock, flags);
2936
2937 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2938 usleep_range(5000, 5500);
2939
2940 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302941 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2943 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302944 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945 spin_unlock_irqrestore(&host->lock, flags);
2946
2947 /*
2948 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2949 * don't become all ones within 1 ms then a Voltage Switch
2950 * sequence has failed and a power cycle to the card is required.
2951 * Otherwise Voltage Switch sequence is completed successfully.
2952 */
2953 usleep_range(1000, 1500);
2954
2955 spin_lock_irqsave(&host->lock, flags);
2956 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2957 != (0xF << 1)) {
2958 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2959 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302960 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 goto out_unlock;
2962 }
2963
2964out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302965 /* Enable PWRSAVE */
2966 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2967 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302968 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002969 spin_unlock_irqrestore(&host->lock, flags);
2970out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302971 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002972}
2973
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302974static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977
2978 /* Program the MCLK value to MCLK_FREQ bit field */
2979 if (host->clk_rate <= 112000000)
2980 mclk_freq = 0;
2981 else if (host->clk_rate <= 125000000)
2982 mclk_freq = 1;
2983 else if (host->clk_rate <= 137000000)
2984 mclk_freq = 2;
2985 else if (host->clk_rate <= 150000000)
2986 mclk_freq = 3;
2987 else if (host->clk_rate <= 162000000)
2988 mclk_freq = 4;
2989 else if (host->clk_rate <= 175000000)
2990 mclk_freq = 5;
2991 else if (host->clk_rate <= 187000000)
2992 mclk_freq = 6;
2993 else if (host->clk_rate <= 200000000)
2994 mclk_freq = 7;
2995
2996 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2997 & ~(7 << 24)) | (mclk_freq << 24)),
2998 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999}
3000
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303001/* Initialize the DLL (Programmable Delay Line ) */
3002static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303005 unsigned long flags;
3006 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303008 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003009 /*
3010 * Make sure that clock is always enabled when DLL
3011 * tuning is in progress. Keeping PWRSAVE ON may
3012 * turn off the clock. So let's disable the PWRSAVE
3013 * here and re-enable it once tuning is completed.
3014 */
3015 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3016 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303017 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303018
3019 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3020 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3021 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3022
3023 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3024 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3025 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3026
3027 msmsdcc_cm_sdc4_dll_set_freq(host);
3028
3029 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3030 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3031 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3032
3033 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3034 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3035 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3036
3037 /* Set DLL_EN bit to 1. */
3038 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3039 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3040
3041 /* Set CK_OUT_EN bit to 1. */
3042 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3043 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3044
3045 wait_cnt = 50;
3046 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3047 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3048 /* max. wait for 50us sec for LOCK bit to be set */
3049 if (--wait_cnt == 0) {
3050 pr_err("%s: %s: DLL failed to LOCK\n",
3051 mmc_hostname(host->mmc), __func__);
3052 rc = -ETIMEDOUT;
3053 goto out;
3054 }
3055 /* wait for 1us before polling again */
3056 udelay(1);
3057 }
3058
3059out:
3060 /* re-enable PWRSAVE */
3061 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3062 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303063 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303064 spin_unlock_irqrestore(&host->lock, flags);
3065
3066 return rc;
3067}
3068
3069static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3070 u8 poll)
3071{
3072 int rc = 0;
3073 u32 wait_cnt = 50;
3074 u8 ck_out_en = 0;
3075
3076 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3077 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3078 MCI_CK_OUT_EN);
3079
3080 while (ck_out_en != poll) {
3081 if (--wait_cnt == 0) {
3082 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3083 mmc_hostname(host->mmc), __func__, poll);
3084 rc = -ETIMEDOUT;
3085 goto out;
3086 }
3087 udelay(1);
3088
3089 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3090 MCI_CK_OUT_EN);
3091 }
3092out:
3093 return rc;
3094}
3095
3096/*
3097 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3098 * calibration sequence. This function should be called before
3099 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3100 * commands (CMD17/CMD18).
3101 *
3102 * This function gets called when host spinlock acquired.
3103 */
3104static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3105{
3106 int rc = 0;
3107 u32 config;
3108
3109 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3110 config |= MCI_CDR_EN;
3111 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3112 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3113
3114 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3115 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3116 if (rc)
3117 goto err_out;
3118
3119 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3120 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3121 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3122
3123 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3124 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3125 if (rc)
3126 goto err_out;
3127
3128 goto out;
3129
3130err_out:
3131 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3132out:
3133 return rc;
3134}
3135
3136static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3137 u8 phase)
3138{
3139 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303140 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3141 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3142 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303143 unsigned long flags;
3144 u32 config;
3145
3146 spin_lock_irqsave(&host->lock, flags);
3147
3148 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3149 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3150 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3151 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3152
3153 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3154 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3155 if (rc)
3156 goto err_out;
3157
3158 /*
3159 * Write the selected DLL clock output phase (0 ... 15)
3160 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3161 */
3162 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3163 & ~(0xF << 20))
3164 | (grey_coded_phase_table[phase] << 20)),
3165 host->base + MCI_DLL_CONFIG);
3166
3167 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3168 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3169 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3170
3171 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3172 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3173 if (rc)
3174 goto err_out;
3175
3176 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3177 config |= MCI_CDR_EN;
3178 config &= ~MCI_CDR_EXT_EN;
3179 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3180 goto out;
3181
3182err_out:
3183 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3184 mmc_hostname(host->mmc), __func__, phase);
3185out:
3186 spin_unlock_irqrestore(&host->lock, flags);
3187 return rc;
3188}
3189
3190/*
3191 * Find out the greatest range of consecuitive selected
3192 * DLL clock output phases that can be used as sampling
3193 * setting for SD3.0 UHS-I card read operation (in SDR104
3194 * timing mode) or for eMMC4.5 card read operation (in HS200
3195 * timing mode).
3196 * Select the 3/4 of the range and configure the DLL with the
3197 * selected DLL clock output phase.
3198*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303199static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303200 u8 *phase_table, u8 total_phases)
3201{
Subhash Jadavani34187042012-03-02 10:59:49 +05303202 int ret;
3203 u8 ranges[16][16] = { {0}, {0} };
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303204 u8 phases_per_row[16] = {0};
3205 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303206 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3207 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303208
Subhash Jadavani34187042012-03-02 10:59:49 +05303209 if (total_phases > 16) {
3210 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3211 mmc_hostname(host->mmc), __func__, total_phases);
3212 return -EINVAL;
3213 }
3214
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303215 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303216 ranges[row_index][col_index] = phase_table[cnt];
3217 phases_per_row[row_index] += 1;
3218 col_index++;
3219
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303220 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303221 continue;
3222 /* check if next phase in phase_table is consecutive or not */
3223 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3224 row_index++;
3225 col_index = 0;
3226 }
3227 }
3228
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303229 /* Check if phase-0 is present in first valid window? */
3230 if (!ranges[0][0]) {
3231 phase_0_found = true;
3232 phase_0_raw_index = 0;
3233 /* Check if cycle exist between 2 valid windows */
3234 for (cnt = 1; cnt <= row_index; cnt++) {
3235 if (phases_per_row[cnt]) {
3236 for (i = 0; i <= phases_per_row[cnt]; i++) {
3237 if (ranges[cnt][i] == 15) {
3238 phase_15_found = true;
3239 phase_15_raw_index = cnt;
3240 break;
3241 }
3242 }
3243 }
3244 }
3245 }
3246
3247 /* If 2 valid windows form cycle then merge them as single window */
3248 if (phase_0_found && phase_15_found) {
3249 /* number of phases in raw where phase 0 is present */
3250 u8 phases_0 = phases_per_row[phase_0_raw_index];
3251 /* number of phases in raw where phase 15 is present */
3252 u8 phases_15 = phases_per_row[phase_15_raw_index];
3253
3254 cnt = 0;
3255 for (i = phases_15; i < (phases_15 + phases_0); i++) {
3256 ranges[phase_15_raw_index][i] =
3257 ranges[phase_0_raw_index][cnt];
3258 cnt++;
3259 }
3260 phases_per_row[phase_0_raw_index] = 0;
3261 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3262 }
3263
3264 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303265 if (phases_per_row[cnt] > curr_max) {
3266 curr_max = phases_per_row[cnt];
3267 selected_row_index = cnt;
3268 }
3269 }
3270
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303271 i = ((curr_max * 3) / 4) - 1;
Subhash Jadavani34187042012-03-02 10:59:49 +05303272 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303273
3274 return ret;
3275}
3276
Girish K Sa3f41692012-02-29 12:00:09 +05303277static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303278{
3279 int rc = 0;
3280 struct msmsdcc_host *host = mmc_priv(mmc);
3281 unsigned long flags;
3282 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303283 const u32 *tuning_block_pattern = tuning_block_64;
3284 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303285
3286 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3287
3288 /* Tuning is only required for SDR104 modes */
3289 if (!host->tuning_needed) {
3290 rc = 0;
3291 goto exit;
3292 }
3293
3294 spin_lock_irqsave(&host->lock, flags);
3295 WARN(!host->pwr, "SDCC power is turned off\n");
3296 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3297 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3298
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303299 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303300 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3301 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3302 tuning_block_pattern = tuning_block_128;
3303 size = sizeof(tuning_block_128);
3304 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303305 spin_unlock_irqrestore(&host->lock, flags);
3306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307 /* first of all reset the tuning block */
3308 rc = msmsdcc_init_cm_sdc4_dll(host);
3309 if (rc)
3310 goto out;
3311
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303312 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003313 if (!data_buf) {
3314 rc = -ENOMEM;
3315 goto out;
3316 }
3317
3318 phase = 0;
3319 do {
3320 struct mmc_command cmd = {0};
3321 struct mmc_data data = {0};
3322 struct mmc_request mrq = {
3323 .cmd = &cmd,
3324 .data = &data
3325 };
3326 struct scatterlist sg;
3327
3328 /* set the phase in delay line hw block */
3329 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3330 if (rc)
3331 goto kfree;
3332
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303333 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3335
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303336 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003337 data.blocks = 1;
3338 data.flags = MMC_DATA_READ;
3339 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3340
3341 data.sg = &sg;
3342 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303343 sg_init_one(&sg, data_buf, size);
3344 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345 mmc_wait_for_req(mmc, &mrq);
3346
3347 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303348 !memcmp(data_buf, tuning_block_pattern, size)) {
3349 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003350 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303351 pr_debug("%s: %s: found good phase = %d\n",
3352 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 }
3354 } while (++phase < 16);
3355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003356 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303357 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303358 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303359 if (rc < 0)
3360 goto kfree;
3361 else
3362 phase = (u8)rc;
3363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364 /*
3365 * Finally set the selected phase in delay
3366 * line hw block.
3367 */
3368 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3369 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303370 goto kfree;
3371 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3372 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003373 } else {
3374 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303375 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303377 msmsdcc_dump_sdcc_state(host);
3378 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003379 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003380
3381kfree:
3382 kfree(data_buf);
3383out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303384 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303385 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303386 spin_unlock_irqrestore(&host->lock, flags);
3387exit:
3388 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003389 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003390}
3391
3392static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 .enable = msmsdcc_enable,
3394 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003395 .request = msmsdcc_request,
3396 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 .get_ro = msmsdcc_get_ro,
3398#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003399 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400#endif
3401 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3402 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003403};
3404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405static unsigned int
3406msmsdcc_slot_status(struct msmsdcc_host *host)
3407{
3408 int status;
3409 unsigned int gpio_no = host->plat->status_gpio;
3410
3411 status = gpio_request(gpio_no, "SD_HW_Detect");
3412 if (status) {
3413 pr_err("%s: %s: Failed to request GPIO %d\n",
3414 mmc_hostname(host->mmc), __func__, gpio_no);
3415 } else {
3416 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003417 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003418 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003419 if (host->plat->is_status_gpio_active_low)
3420 status = !status;
3421 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422 gpio_free(gpio_no);
3423 }
3424 return status;
3425}
3426
San Mehat9d2bd732009-09-22 16:44:22 -07003427static void
3428msmsdcc_check_status(unsigned long data)
3429{
3430 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3431 unsigned int status;
3432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003434 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003436 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003437 status = msmsdcc_slot_status(host);
3438
Krishna Konda941604a2012-01-10 17:46:34 -08003439 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003442 if (host->plat->status)
3443 pr_info("%s: Slot status change detected "
3444 "(%d -> %d)\n",
3445 mmc_hostname(host->mmc),
3446 host->oldstat, status);
3447 else if (host->plat->is_status_gpio_active_low)
3448 pr_info("%s: Slot status change detected "
3449 "(%d -> %d) and the card detect GPIO"
3450 " is ACTIVE_LOW\n",
3451 mmc_hostname(host->mmc),
3452 host->oldstat, status);
3453 else
3454 pr_info("%s: Slot status change detected "
3455 "(%d -> %d) and the card detect GPIO"
3456 " is ACTIVE_HIGH\n",
3457 mmc_hostname(host->mmc),
3458 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003459 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003460 }
3461 host->oldstat = status;
3462 } else {
3463 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003464 }
San Mehat9d2bd732009-09-22 16:44:22 -07003465}
3466
3467static irqreturn_t
3468msmsdcc_platform_status_irq(int irq, void *dev_id)
3469{
3470 struct msmsdcc_host *host = dev_id;
3471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003473 msmsdcc_check_status((unsigned long) host);
3474 return IRQ_HANDLED;
3475}
3476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477static irqreturn_t
3478msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3479{
3480 struct msmsdcc_host *host = dev_id;
3481
3482 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3483 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303484 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303486 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 wake_lock(&host->sdio_wlock);
3488 msmsdcc_disable_irq_wake(host);
3489 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303490 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003491 }
3492 if (host->plat->is_sdio_al_client) {
3493 if (!host->clks_on) {
3494 msmsdcc_setup_clocks(host, true);
3495 host->clks_on = 1;
3496 }
3497 if (host->sdcc_irq_disabled) {
3498 writel_relaxed(host->mci_irqenable,
3499 host->base + MMCIMASK0);
3500 mb();
3501 enable_irq(host->core_irqres->start);
3502 host->sdcc_irq_disabled = 0;
3503 }
3504 wake_lock(&host->sdio_wlock);
3505 }
3506 spin_unlock(&host->lock);
3507
3508 return IRQ_HANDLED;
3509}
3510
San Mehat9d2bd732009-09-22 16:44:22 -07003511static void
3512msmsdcc_status_notify_cb(int card_present, void *dev_id)
3513{
3514 struct msmsdcc_host *host = dev_id;
3515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003517 card_present);
3518 msmsdcc_check_status((unsigned long) host);
3519}
3520
San Mehat9d2bd732009-09-22 16:44:22 -07003521static int
3522msmsdcc_init_dma(struct msmsdcc_host *host)
3523{
3524 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3525 host->dma.host = host;
3526 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003527 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003528
3529 if (!host->dmares)
3530 return -ENODEV;
3531
3532 host->dma.nc = dma_alloc_coherent(NULL,
3533 sizeof(struct msmsdcc_nc_dmadata),
3534 &host->dma.nc_busaddr,
3535 GFP_KERNEL);
3536 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003537 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003538 return -ENOMEM;
3539 }
3540 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3541 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3542 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3543 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3544 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003545 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003546
3547 return 0;
3548}
3549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003550#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3551/**
3552 * Allocate and Connect a SDCC peripheral's SPS endpoint
3553 *
3554 * This function allocates endpoint context and
3555 * connect it with memory endpoint by calling
3556 * appropriate SPS driver APIs.
3557 *
3558 * Also registers a SPS callback function with
3559 * SPS driver
3560 *
3561 * This function should only be called once typically
3562 * during driver probe.
3563 *
3564 * @host - Pointer to sdcc host structure
3565 * @ep - Pointer to sps endpoint data structure
3566 * @is_produce - 1 means Producer endpoint
3567 * 0 means Consumer endpoint
3568 *
3569 * @return - 0 if successful else negative value.
3570 *
3571 */
3572static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3573 struct msmsdcc_sps_ep_conn_data *ep,
3574 bool is_producer)
3575{
3576 int rc = 0;
3577 struct sps_pipe *sps_pipe_handle;
3578 struct sps_connect *sps_config = &ep->config;
3579 struct sps_register_event *sps_event = &ep->event;
3580
3581 /* Allocate endpoint context */
3582 sps_pipe_handle = sps_alloc_endpoint();
3583 if (!sps_pipe_handle) {
3584 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3585 mmc_hostname(host->mmc), is_producer);
3586 rc = -ENOMEM;
3587 goto out;
3588 }
3589
3590 /* Get default connection configuration for an endpoint */
3591 rc = sps_get_config(sps_pipe_handle, sps_config);
3592 if (rc) {
3593 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3594 " rc=%d", mmc_hostname(host->mmc),
3595 (u32)sps_pipe_handle, rc);
3596 goto get_config_err;
3597 }
3598
3599 /* Modify the default connection configuration */
3600 if (is_producer) {
3601 /*
3602 * For SDCC producer transfer, source should be
3603 * SDCC peripheral where as destination should
3604 * be system memory.
3605 */
3606 sps_config->source = host->sps.bam_handle;
3607 sps_config->destination = SPS_DEV_HANDLE_MEM;
3608 /* Producer pipe will handle this connection */
3609 sps_config->mode = SPS_MODE_SRC;
3610 sps_config->options =
3611 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3612 } else {
3613 /*
3614 * For SDCC consumer transfer, source should be
3615 * system memory where as destination should
3616 * SDCC peripheral
3617 */
3618 sps_config->source = SPS_DEV_HANDLE_MEM;
3619 sps_config->destination = host->sps.bam_handle;
3620 sps_config->mode = SPS_MODE_DEST;
3621 sps_config->options =
3622 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3623 }
3624
3625 /* Producer pipe index */
3626 sps_config->src_pipe_index = host->sps.src_pipe_index;
3627 /* Consumer pipe index */
3628 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3629 /*
3630 * This event thresold value is only significant for BAM-to-BAM
3631 * transfer. It's ignored for BAM-to-System mode transfer.
3632 */
3633 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303634
3635 /* Allocate maximum descriptor fifo size */
3636 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3637 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003638 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3639 sps_config->desc.size,
3640 &sps_config->desc.phys_base,
3641 GFP_KERNEL);
3642
Pratibhasagar V00b94332011-10-18 14:57:27 +05303643 if (!sps_config->desc.base) {
3644 rc = -ENOMEM;
3645 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3646 , mmc_hostname(host->mmc));
3647 goto get_config_err;
3648 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003649 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3650
3651 /* Establish connection between peripheral and memory endpoint */
3652 rc = sps_connect(sps_pipe_handle, sps_config);
3653 if (rc) {
3654 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3655 " rc=%d", mmc_hostname(host->mmc),
3656 (u32)sps_pipe_handle, rc);
3657 goto sps_connect_err;
3658 }
3659
3660 sps_event->mode = SPS_TRIGGER_CALLBACK;
3661 sps_event->options = SPS_O_EOT;
3662 sps_event->callback = msmsdcc_sps_complete_cb;
3663 sps_event->xfer_done = NULL;
3664 sps_event->user = (void *)host;
3665
3666 /* Register callback event for EOT (End of transfer) event. */
3667 rc = sps_register_event(sps_pipe_handle, sps_event);
3668 if (rc) {
3669 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3670 " rc=%d", mmc_hostname(host->mmc),
3671 (u32)sps_pipe_handle, rc);
3672 goto reg_event_err;
3673 }
3674 /* Now save the sps pipe handle */
3675 ep->pipe_handle = sps_pipe_handle;
3676 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3677 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3678 __func__, is_producer ? "READ" : "WRITE",
3679 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3680 goto out;
3681
3682reg_event_err:
3683 sps_disconnect(sps_pipe_handle);
3684sps_connect_err:
3685 dma_free_coherent(mmc_dev(host->mmc),
3686 sps_config->desc.size,
3687 sps_config->desc.base,
3688 sps_config->desc.phys_base);
3689get_config_err:
3690 sps_free_endpoint(sps_pipe_handle);
3691out:
3692 return rc;
3693}
3694
3695/**
3696 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3697 *
3698 * This function disconnect endpoint and deallocates
3699 * endpoint context.
3700 *
3701 * This function should only be called once typically
3702 * during driver remove.
3703 *
3704 * @host - Pointer to sdcc host structure
3705 * @ep - Pointer to sps endpoint data structure
3706 *
3707 */
3708static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3709 struct msmsdcc_sps_ep_conn_data *ep)
3710{
3711 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3712 struct sps_connect *sps_config = &ep->config;
3713 struct sps_register_event *sps_event = &ep->event;
3714
3715 sps_event->xfer_done = NULL;
3716 sps_event->callback = NULL;
3717 sps_register_event(sps_pipe_handle, sps_event);
3718 sps_disconnect(sps_pipe_handle);
3719 dma_free_coherent(mmc_dev(host->mmc),
3720 sps_config->desc.size,
3721 sps_config->desc.base,
3722 sps_config->desc.phys_base);
3723 sps_free_endpoint(sps_pipe_handle);
3724}
3725
3726/**
3727 * Reset SDCC peripheral's SPS endpoint
3728 *
3729 * This function disconnects an endpoint.
3730 *
3731 * This function should be called for reseting
3732 * SPS endpoint when data transfer error is
3733 * encountered during data transfer. This
3734 * can be considered as soft reset to endpoint.
3735 *
3736 * This function should only be called if
3737 * msmsdcc_sps_init() is already called.
3738 *
3739 * @host - Pointer to sdcc host structure
3740 * @ep - Pointer to sps endpoint data structure
3741 *
3742 * @return - 0 if successful else negative value.
3743 */
3744static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3745 struct msmsdcc_sps_ep_conn_data *ep)
3746{
3747 int rc = 0;
3748 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3749
3750 rc = sps_disconnect(sps_pipe_handle);
3751 if (rc) {
3752 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3753 " rc=%d", mmc_hostname(host->mmc), __func__,
3754 (u32)sps_pipe_handle, rc);
3755 goto out;
3756 }
3757 out:
3758 return rc;
3759}
3760
3761/**
3762 * Restore SDCC peripheral's SPS endpoint
3763 *
3764 * This function connects an endpoint.
3765 *
3766 * This function should be called for restoring
3767 * SPS endpoint after data transfer error is
3768 * encountered during data transfer. This
3769 * can be considered as soft reset to endpoint.
3770 *
3771 * This function should only be called if
3772 * msmsdcc_sps_reset_ep() is called before.
3773 *
3774 * @host - Pointer to sdcc host structure
3775 * @ep - Pointer to sps endpoint data structure
3776 *
3777 * @return - 0 if successful else negative value.
3778 */
3779static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3780 struct msmsdcc_sps_ep_conn_data *ep)
3781{
3782 int rc = 0;
3783 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3784 struct sps_connect *sps_config = &ep->config;
3785 struct sps_register_event *sps_event = &ep->event;
3786
3787 /* Establish connection between peripheral and memory endpoint */
3788 rc = sps_connect(sps_pipe_handle, sps_config);
3789 if (rc) {
3790 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3791 " rc=%d", mmc_hostname(host->mmc), __func__,
3792 (u32)sps_pipe_handle, rc);
3793 goto out;
3794 }
3795
3796 /* Register callback event for EOT (End of transfer) event. */
3797 rc = sps_register_event(sps_pipe_handle, sps_event);
3798 if (rc) {
3799 pr_err("%s: %s: sps_register_event() failed!!!"
3800 " pipe_handle=0x%x, rc=%d",
3801 mmc_hostname(host->mmc), __func__,
3802 (u32)sps_pipe_handle, rc);
3803 goto reg_event_err;
3804 }
3805 goto out;
3806
3807reg_event_err:
3808 sps_disconnect(sps_pipe_handle);
3809out:
3810 return rc;
3811}
3812
3813/**
3814 * Initialize SPS HW connected with SDCC core
3815 *
3816 * This function register BAM HW resources with
3817 * SPS driver and then initialize 2 SPS endpoints
3818 *
3819 * This function should only be called once typically
3820 * during driver probe.
3821 *
3822 * @host - Pointer to sdcc host structure
3823 *
3824 * @return - 0 if successful else negative value.
3825 *
3826 */
3827static int msmsdcc_sps_init(struct msmsdcc_host *host)
3828{
3829 int rc = 0;
3830 struct sps_bam_props bam = {0};
3831
3832 host->bam_base = ioremap(host->bam_memres->start,
3833 resource_size(host->bam_memres));
3834 if (!host->bam_base) {
3835 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3836 " size=0x%x", mmc_hostname(host->mmc),
3837 host->bam_memres->start,
3838 (host->bam_memres->end -
3839 host->bam_memres->start));
3840 rc = -ENOMEM;
3841 goto out;
3842 }
3843
3844 bam.phys_addr = host->bam_memres->start;
3845 bam.virt_addr = host->bam_base;
3846 /*
3847 * This event thresold value is only significant for BAM-to-BAM
3848 * transfer. It's ignored for BAM-to-System mode transfer.
3849 */
3850 bam.event_threshold = 0x10; /* Pipe event threshold */
3851 /*
3852 * This threshold controls when the BAM publish
3853 * the descriptor size on the sideband interface.
3854 * SPS HW will only be used when
3855 * data transfer size > MCI_FIFOSIZE (64 bytes).
3856 * PIO mode will be used when
3857 * data transfer size < MCI_FIFOSIZE (64 bytes).
3858 * So set this thresold value to 64 bytes.
3859 */
3860 bam.summing_threshold = 64;
3861 /* SPS driver wll handle the SDCC BAM IRQ */
3862 bam.irq = (u32)host->bam_irqres->start;
3863 bam.manage = SPS_BAM_MGR_LOCAL;
3864
3865 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3866 (u32)bam.phys_addr);
3867 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3868 (u32)bam.virt_addr);
3869
3870 /* Register SDCC Peripheral BAM device to SPS driver */
3871 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3872 if (rc) {
3873 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3874 mmc_hostname(host->mmc), rc);
3875 goto reg_bam_err;
3876 }
3877 pr_info("%s: BAM device registered. bam_handle=0x%x",
3878 mmc_hostname(host->mmc), host->sps.bam_handle);
3879
3880 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3881 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3882
3883 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3884 SPS_PROD_PERIPHERAL);
3885 if (rc)
3886 goto sps_reset_err;
3887 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3888 SPS_CONS_PERIPHERAL);
3889 if (rc)
3890 goto cons_conn_err;
3891
3892 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3893 mmc_hostname(host->mmc),
3894 (unsigned long long)host->bam_memres->start,
3895 (unsigned int)host->bam_irqres->start);
3896 goto out;
3897
3898cons_conn_err:
3899 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3900sps_reset_err:
3901 sps_deregister_bam_device(host->sps.bam_handle);
3902reg_bam_err:
3903 iounmap(host->bam_base);
3904out:
3905 return rc;
3906}
3907
3908/**
3909 * De-initialize SPS HW connected with SDCC core
3910 *
3911 * This function deinitialize SPS endpoints and then
3912 * deregisters BAM resources from SPS driver.
3913 *
3914 * This function should only be called once typically
3915 * during driver remove.
3916 *
3917 * @host - Pointer to sdcc host structure
3918 *
3919 */
3920static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3921{
3922 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3923 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3924 sps_deregister_bam_device(host->sps.bam_handle);
3925 iounmap(host->bam_base);
3926}
3927#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3928
3929static ssize_t
3930show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3931{
3932 struct mmc_host *mmc = dev_get_drvdata(dev);
3933 struct msmsdcc_host *host = mmc_priv(mmc);
3934 int poll;
3935 unsigned long flags;
3936
3937 spin_lock_irqsave(&host->lock, flags);
3938 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3939 spin_unlock_irqrestore(&host->lock, flags);
3940
3941 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3942}
3943
3944static ssize_t
3945set_polling(struct device *dev, struct device_attribute *attr,
3946 const char *buf, size_t count)
3947{
3948 struct mmc_host *mmc = dev_get_drvdata(dev);
3949 struct msmsdcc_host *host = mmc_priv(mmc);
3950 int value;
3951 unsigned long flags;
3952
3953 sscanf(buf, "%d", &value);
3954
3955 spin_lock_irqsave(&host->lock, flags);
3956 if (value) {
3957 mmc->caps |= MMC_CAP_NEEDS_POLL;
3958 mmc_detect_change(host->mmc, 0);
3959 } else {
3960 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3961 }
3962#ifdef CONFIG_HAS_EARLYSUSPEND
3963 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3964#endif
3965 spin_unlock_irqrestore(&host->lock, flags);
3966 return count;
3967}
3968
3969static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3970 show_polling, set_polling);
3971static struct attribute *dev_attrs[] = {
3972 &dev_attr_polling.attr,
3973 NULL,
3974};
3975static struct attribute_group dev_attr_grp = {
3976 .attrs = dev_attrs,
3977};
3978
3979#ifdef CONFIG_HAS_EARLYSUSPEND
3980static void msmsdcc_early_suspend(struct early_suspend *h)
3981{
3982 struct msmsdcc_host *host =
3983 container_of(h, struct msmsdcc_host, early_suspend);
3984 unsigned long flags;
3985
3986 spin_lock_irqsave(&host->lock, flags);
3987 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3988 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3989 spin_unlock_irqrestore(&host->lock, flags);
3990};
3991static void msmsdcc_late_resume(struct early_suspend *h)
3992{
3993 struct msmsdcc_host *host =
3994 container_of(h, struct msmsdcc_host, early_suspend);
3995 unsigned long flags;
3996
3997 if (host->polling_enabled) {
3998 spin_lock_irqsave(&host->lock, flags);
3999 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4000 mmc_detect_change(host->mmc, 0);
4001 spin_unlock_irqrestore(&host->lock, flags);
4002 }
4003};
4004#endif
4005
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304006void msmsdcc_print_regs(const char *name, void __iomem *base,
4007 unsigned int no_of_regs)
4008{
4009 unsigned int i;
4010
4011 if (!base)
4012 return;
4013 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
4014 name, (u32)base);
4015 for (i = 0; i < no_of_regs; i = i + 4) {
4016 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
4017 (u32)readl_relaxed(base + i*4),
4018 (u32)readl_relaxed(base + ((i+1)*4)),
4019 (u32)readl_relaxed(base + ((i+2)*4)),
4020 (u32)readl_relaxed(base + ((i+3)*4)));
4021 }
4022}
4023
4024static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4025{
4026 /* Dump current state of SDCC clocks, power and irq */
4027 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
4028 (host->pwr ? "ON" : "OFF"));
4029 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
4030 mmc_hostname(host->mmc),
4031 (host->clks_on ? "ON" : "OFF"),
4032 (u32)clk_get_rate(host->clk));
4033 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4034 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4035
4036 /* Now dump SDCC registers. Don't print FIFO registers */
4037 if (host->clks_on)
4038 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
4039
4040 if (host->curr.data) {
4041 if (msmsdcc_check_dma_op_req(host->curr.data))
4042 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4043 else if (host->is_dma_mode)
4044 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4045 mmc_hostname(host->mmc), host->dma.busy,
4046 host->dma.channel, host->dma.crci);
4047 else if (host->is_sps_mode)
4048 pr_info("%s: SPS mode: busy=%d\n",
4049 mmc_hostname(host->mmc), host->sps.busy);
4050
4051 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4052 mmc_hostname(host->mmc), host->curr.xfer_size,
4053 host->curr.data_xfered, host->curr.xfer_remain);
4054 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4055 " wait_for_auto_prog_done=%d,"
4056 " got_auto_prog_done=%d\n",
4057 mmc_hostname(host->mmc), host->curr.got_dataend,
4058 host->prog_enable, host->curr.wait_for_auto_prog_done,
4059 host->curr.got_auto_prog_done);
4060 }
4061
4062}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4064{
4065 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4066 struct mmc_request *mrq;
4067 unsigned long flags;
4068
4069 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004070 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071 pr_info("%s: %s: dummy CMD52 timeout\n",
4072 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004073 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004074 }
4075
4076 mrq = host->curr.mrq;
4077
4078 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304079 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4080 mrq->cmd->opcode);
4081 msmsdcc_dump_sdcc_state(host);
4082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004083 if (!mrq->cmd->error)
4084 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304085 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 if (mrq->data && !mrq->data->error)
4088 mrq->data->error = -ETIMEDOUT;
4089 host->curr.data_xfered = 0;
4090 if (host->dma.sg && host->is_dma_mode) {
4091 msm_dmov_stop_cmd(host->dma.channel,
4092 &host->dma.hdr, 0);
4093 } else if (host->sps.sg && host->is_sps_mode) {
4094 /* Stop current SPS transfer */
4095 msmsdcc_sps_exit_curr_xfer(host);
4096 } else {
4097 msmsdcc_reset_and_restore(host);
4098 msmsdcc_stop_data(host);
4099 if (mrq->data && mrq->data->stop)
4100 msmsdcc_start_command(host,
4101 mrq->data->stop, 0);
4102 else
4103 msmsdcc_request_end(host, mrq);
4104 }
4105 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304106 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304107 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 msmsdcc_reset_and_restore(host);
4109 msmsdcc_request_end(host, mrq);
4110 }
4111 }
4112 spin_unlock_irqrestore(&host->lock, flags);
4113}
4114
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304115static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4116{
4117 int i, ret;
4118 struct mmc_platform_data *pdata;
4119 struct device_node *np = dev->of_node;
4120 u32 bus_width = 0;
4121 u32 *clk_table;
4122 int clk_table_len;
4123 u32 *sup_voltages;
4124 int sup_volt_len;
4125
4126 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4127 if (!pdata) {
4128 dev_err(dev, "could not allocate memory for platform data\n");
4129 goto err;
4130 }
4131
4132 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4133 if (bus_width == 8) {
4134 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4135 } else if (bus_width == 4) {
4136 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4137 } else {
4138 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4139 pdata->mmc_bus_width = 0;
4140 }
4141
4142 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4143 size_t sz;
4144 sz = sup_volt_len / sizeof(*sup_voltages);
4145 if (sz > 0) {
4146 sup_voltages = devm_kzalloc(dev,
4147 sz * sizeof(*sup_voltages), GFP_KERNEL);
4148 if (!sup_voltages) {
4149 dev_err(dev, "No memory for supported voltage\n");
4150 goto err;
4151 }
4152
4153 ret = of_property_read_u32_array(np,
4154 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4155 if (ret < 0) {
4156 dev_err(dev, "error while reading voltage"
4157 "ranges %d\n", ret);
4158 goto err;
4159 }
4160 } else {
4161 dev_err(dev, "No supported voltages\n");
4162 goto err;
4163 }
4164 for (i = 0; i < sz; i += 2) {
4165 u32 mask;
4166
4167 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4168 sup_voltages[i + 1]);
4169 if (!mask)
4170 dev_err(dev, "Invalide voltage range %d\n", i);
4171 pdata->ocr_mask |= mask;
4172 }
4173 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4174 } else {
4175 dev_err(dev, "Supported voltage range not specified\n");
4176 }
4177
4178 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4179 size_t sz;
4180 sz = clk_table_len / sizeof(*clk_table);
4181
4182 if (sz > 0) {
4183 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4184 GFP_KERNEL);
4185 if (!clk_table) {
4186 dev_err(dev, "No memory for clock table\n");
4187 goto err;
4188 }
4189
4190 ret = of_property_read_u32_array(np,
4191 "qcom,sdcc-clk-rates", clk_table, sz);
4192 if (ret < 0) {
4193 dev_err(dev, "error while reading clk"
4194 "table %d\n", ret);
4195 goto err;
4196 }
4197 } else {
4198 dev_err(dev, "clk_table not specified\n");
4199 goto err;
4200 }
4201 pdata->sup_clk_table = clk_table;
4202 pdata->sup_clk_cnt = sz;
4203 } else {
4204 dev_err(dev, "Supported clock rates not specified\n");
4205 }
4206
4207 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4208 pdata->nonremovable = true;
4209 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4210 pdata->disable_cmd23 = true;
4211
4212 return pdata;
4213err:
4214 return NULL;
4215}
4216
San Mehat9d2bd732009-09-22 16:44:22 -07004217static int
4218msmsdcc_probe(struct platform_device *pdev)
4219{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304220 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004221 struct msmsdcc_host *host;
4222 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 unsigned long flags;
4224 struct resource *core_irqres = NULL;
4225 struct resource *bam_irqres = NULL;
4226 struct resource *core_memres = NULL;
4227 struct resource *dml_memres = NULL;
4228 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004229 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004230 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304231 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004232 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004233
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304234 if (pdev->dev.of_node) {
4235 plat = msmsdcc_populate_pdata(&pdev->dev);
4236 of_property_read_u32((&pdev->dev)->of_node,
4237 "cell-index", &pdev->id);
4238 } else {
4239 plat = pdev->dev.platform_data;
4240 }
4241
San Mehat9d2bd732009-09-22 16:44:22 -07004242 /* must have platform data */
4243 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004244 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004245 ret = -EINVAL;
4246 goto out;
4247 }
4248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004250 return -EINVAL;
4251
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304252 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4253 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4254 return -EINVAL;
4255 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004256
San Mehat9d2bd732009-09-22 16:44:22 -07004257 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004258 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004259 return -ENXIO;
4260 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304261 if (pdev->dev.of_node) {
4262 /*
4263 * Device tree iomem resources are only accessible by index.
4264 * index = 0 -> SDCC register interface
4265 * index = 1 -> DML register interface
4266 * index = 2 -> BAM register interface
4267 * IRQ resources:
4268 * index = 0 -> SDCC IRQ
4269 * index = 1 -> BAM IRQ
4270 */
4271 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4272 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4273 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4274 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4275 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4276 } else {
4277 for (i = 0; i < pdev->num_resources; i++) {
4278 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4279 if (!strncmp(pdev->resource[i].name,
4280 "sdcc_dml_addr",
4281 sizeof("sdcc_dml_addr")))
4282 dml_memres = &pdev->resource[i];
4283 else if (!strncmp(pdev->resource[i].name,
4284 "sdcc_bam_addr",
4285 sizeof("sdcc_bam_addr")))
4286 bam_memres = &pdev->resource[i];
4287 else
4288 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004289
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304290 }
4291 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4292 if (!strncmp(pdev->resource[i].name,
4293 "sdcc_bam_irq",
4294 sizeof("sdcc_bam_irq")))
4295 bam_irqres = &pdev->resource[i];
4296 else
4297 core_irqres = &pdev->resource[i];
4298 }
4299 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4300 if (!strncmp(pdev->resource[i].name,
4301 "sdcc_dma_chnl",
4302 sizeof("sdcc_dma_chnl")))
4303 dmares = &pdev->resource[i];
4304 else if (!strncmp(pdev->resource[i].name,
4305 "sdcc_dma_crci",
4306 sizeof("sdcc_dma_crci")))
4307 dma_crci_res = &pdev->resource[i];
4308 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004309 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004310 }
4311
4312 if (!core_irqres || !core_memres) {
4313 pr_err("%s: Invalid sdcc core resource\n", __func__);
4314 return -ENXIO;
4315 }
4316
4317 /*
4318 * Both BAM and DML memory resource should be preset.
4319 * BAM IRQ resource should also be present.
4320 */
4321 if ((bam_memres && !dml_memres) ||
4322 (!bam_memres && dml_memres) ||
4323 ((bam_memres && dml_memres) && !bam_irqres)) {
4324 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004325 return -ENXIO;
4326 }
4327
4328 /*
4329 * Setup our host structure
4330 */
San Mehat9d2bd732009-09-22 16:44:22 -07004331 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4332 if (!mmc) {
4333 ret = -ENOMEM;
4334 goto out;
4335 }
4336
4337 host = mmc_priv(mmc);
4338 host->pdev_id = pdev->id;
4339 host->plat = plat;
4340 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004341 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304342
4343 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004344 host->is_sps_mode = 1;
4345 else if (dmares)
4346 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004348 host->base = ioremap(core_memres->start,
4349 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004350 if (!host->base) {
4351 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004352 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004353 }
4354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004355 host->core_irqres = core_irqres;
4356 host->bam_irqres = bam_irqres;
4357 host->core_memres = core_memres;
4358 host->dml_memres = dml_memres;
4359 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004360 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004361 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004362 spin_lock_init(&host->lock);
4363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004364#ifdef CONFIG_MMC_EMBEDDED_SDIO
4365 if (plat->embedded_sdio)
4366 mmc_set_embedded_sdio_data(mmc,
4367 &plat->embedded_sdio->cis,
4368 &plat->embedded_sdio->cccr,
4369 plat->embedded_sdio->funcs,
4370 plat->embedded_sdio->num_funcs);
4371#endif
4372
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304373 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4374 (unsigned long)host);
4375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004376 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4377 (unsigned long)host);
4378 if (host->is_dma_mode) {
4379 /* Setup DMA */
4380 ret = msmsdcc_init_dma(host);
4381 if (ret)
4382 goto ioremap_free;
4383 } else {
4384 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004385 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004386 }
4387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004388 /*
4389 * Setup SDCC clock if derived from Dayatona
4390 * fabric core clock.
4391 */
4392 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004393 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004394 if (!IS_ERR(host->dfab_pclk)) {
4395 /* Set the clock rate to 64MHz for max. performance */
4396 ret = clk_set_rate(host->dfab_pclk, 64000000);
4397 if (ret)
4398 goto dfab_pclk_put;
4399 ret = clk_enable(host->dfab_pclk);
4400 if (ret)
4401 goto dfab_pclk_put;
4402 } else
4403 goto dma_free;
4404 }
4405
4406 /*
4407 * Setup main peripheral bus clock
4408 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004409 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004410 if (!IS_ERR(host->pclk)) {
4411 ret = clk_enable(host->pclk);
4412 if (ret)
4413 goto pclk_put;
4414
4415 host->pclk_rate = clk_get_rate(host->pclk);
4416 }
4417
4418 /*
4419 * Setup SDC MMC clock
4420 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004421 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004422 if (IS_ERR(host->clk)) {
4423 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004424 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004425 }
4426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004427 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4428 if (ret) {
4429 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4430 goto clk_put;
4431 }
4432
4433 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004434 if (ret)
4435 goto clk_put;
4436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004437 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304438 if (!host->clk_rate)
4439 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304440
4441 /*
4442 * Lookup the Controller Version, to identify the supported features
4443 * Version number read as 0 would indicate SDCC3 or earlier versions
4444 */
4445 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4446 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4447 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304448 /*
4449 * Set the register write delay according to min. clock frequency
4450 * supported and update later when the host->clk_rate changes.
4451 */
4452 host->reg_write_delay =
4453 (1 + ((3 * USEC_PER_SEC) /
4454 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004455
4456 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304457 /* Apply Hard reset to SDCC to put it in power on default state */
4458 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004459
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304460 /* pm qos request to prevent apps idle power collapse */
4461 if (host->plat->swfi_latency)
4462 pm_qos_add_request(&host->pm_qos_req_dma,
4463 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004465 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004466 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004467 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004468 goto clk_disable;
4469 }
4470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004471
4472 /* Clocks has to be running before accessing SPS/DML HW blocks */
4473 if (host->is_sps_mode) {
4474 /* Initialize SPS */
4475 ret = msmsdcc_sps_init(host);
4476 if (ret)
4477 goto vreg_deinit;
4478 /* Initialize DML */
4479 ret = msmsdcc_dml_init(host);
4480 if (ret)
4481 goto sps_exit;
4482 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304483 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004484
San Mehat9d2bd732009-09-22 16:44:22 -07004485 /*
4486 * Setup MMC host structure
4487 */
4488 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004489 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4490 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004491 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4493 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004494
San Mehat9d2bd732009-09-22 16:44:22 -07004495 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304496 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304497
4498 /*
4499 * If we send the CMD23 before multi block write/read command
4500 * then we need not to send CMD12 at the end of the transfer.
4501 * If we don't send the CMD12 then only way to detect the PROG_DONE
4502 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4503 * controller. So let's enable the CMD23 for SDCC4 only.
4504 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304505 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304506 mmc->caps |= MMC_CAP_CMD23;
4507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508 mmc->caps |= plat->uhs_caps;
4509 /*
4510 * XPC controls the maximum current in the default speed mode of SDXC
4511 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4512 * XPC=1 means 150mA (max.) and speed class is supported.
4513 */
4514 if (plat->xpc_cap)
4515 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4516 MMC_CAP_SET_XPC_180);
4517
Subhash Jadavani0a0c6272012-03-24 23:13:18 +05304518 mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304519 if (pdev->dev.of_node) {
4520 if (of_get_property((&pdev->dev)->of_node,
4521 "qcom,sdcc-hs200", NULL))
4522 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4523 }
4524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004525 if (plat->nonremovable)
4526 mmc->caps |= MMC_CAP_NONREMOVABLE;
4527#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4528 mmc->caps |= MMC_CAP_SDIO_IRQ;
4529#endif
4530
4531 if (plat->is_sdio_al_client)
4532 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004533
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304534 mmc->max_segs = msmsdcc_get_nr_sg(host);
4535 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4536 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004537
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304538 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304539 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541 writel_relaxed(0, host->base + MMCIMASK0);
4542 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304543 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4546 mb();
4547 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004549 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4550 DRIVER_NAME " (cmd)", host);
4551 if (ret)
4552 goto dml_exit;
4553
4554 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4555 DRIVER_NAME " (pio)", host);
4556 if (ret)
4557 goto irq_free;
4558
4559 /*
4560 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4561 * IRQ is un-necessarily being monitored by MPM (Modem power
4562 * management block) during idle-power collapse. The MPM will be
4563 * configured to monitor the DATA1 GPIO line with level-low trigger
4564 * and thus depending on the GPIO status, it prevents TCXO shutdown
4565 * during idle-power collapse.
4566 */
4567 disable_irq(core_irqres->start);
4568 host->sdcc_irq_disabled = 1;
4569
4570 if (plat->sdiowakeup_irq) {
4571 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4572 mmc_hostname(mmc));
4573 ret = request_irq(plat->sdiowakeup_irq,
4574 msmsdcc_platform_sdiowakeup_irq,
4575 IRQF_SHARED | IRQF_TRIGGER_LOW,
4576 DRIVER_NAME "sdiowakeup", host);
4577 if (ret) {
4578 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4579 plat->sdiowakeup_irq, ret);
4580 goto pio_irq_free;
4581 } else {
4582 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304583 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304585 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004586 }
4587 spin_unlock_irqrestore(&host->lock, flags);
4588 }
4589 }
4590
4591 if (plat->cfg_mpm_sdiowakeup) {
4592 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4593 mmc_hostname(mmc));
4594 }
4595
4596 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4597 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004598 /*
4599 * Setup card detect change
4600 */
4601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004602 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004603 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004605 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004606 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004607
Krishna Konda941604a2012-01-10 17:46:34 -08004608 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004609 }
San Mehat9d2bd732009-09-22 16:44:22 -07004610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004611 if (plat->status_irq) {
4612 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004613 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004615 DRIVER_NAME " (slot)",
4616 host);
4617 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004618 pr_err("Unable to get slot IRQ %d (%d)\n",
4619 plat->status_irq, ret);
4620 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004621 }
4622 } else if (plat->register_status_notify) {
4623 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4624 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004625 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004626 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004627
4628 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004629
4630 ret = pm_runtime_set_active(&(pdev)->dev);
4631 if (ret < 0)
4632 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4633 __func__, ret);
4634 /*
4635 * There is no notion of suspend/resume for SD/MMC/SDIO
4636 * cards. So host can be suspended/resumed with out
4637 * worrying about its children.
4638 */
4639 pm_suspend_ignore_children(&(pdev)->dev, true);
4640
4641 /*
4642 * MMC/SD/SDIO bus suspend/resume operations are defined
4643 * only for the slots that will be used for non-removable
4644 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4645 * defined. Otherwise, they simply become card removal and
4646 * insertion events during suspend and resume respectively.
4647 * Hence, enable run-time PM only for slots for which bus
4648 * suspend/resume operations are defined.
4649 */
4650#ifdef CONFIG_MMC_UNSAFE_RESUME
4651 /*
4652 * If this capability is set, MMC core will enable/disable host
4653 * for every claim/release operation on a host. We use this
4654 * notification to increment/decrement runtime pm usage count.
4655 */
4656 mmc->caps |= MMC_CAP_DISABLE;
4657 pm_runtime_enable(&(pdev)->dev);
4658#else
4659 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4660 mmc->caps |= MMC_CAP_DISABLE;
4661 pm_runtime_enable(&(pdev)->dev);
4662 }
4663#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304664#ifndef CONFIG_PM_RUNTIME
4665 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4666#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004667 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4668 (unsigned long)host);
4669
San Mehat9d2bd732009-09-22 16:44:22 -07004670 mmc_add_host(mmc);
4671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004672#ifdef CONFIG_HAS_EARLYSUSPEND
4673 host->early_suspend.suspend = msmsdcc_early_suspend;
4674 host->early_suspend.resume = msmsdcc_late_resume;
4675 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4676 register_early_suspend(&host->early_suspend);
4677#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004678
Krishna Konda25786ec2011-07-25 16:21:36 -07004679 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4680 " dmacrcri %d\n", mmc_hostname(mmc),
4681 (unsigned long long)core_memres->start,
4682 (unsigned int) core_irqres->start,
4683 (unsigned int) plat->status_irq, host->dma.channel,
4684 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004685
4686 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4687 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4688 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4689 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4690 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4691 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4692 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4693 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4694 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4695 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4696 host->eject);
4697 pr_info("%s: Power save feature enable = %d\n",
4698 mmc_hostname(mmc), msmsdcc_pwrsave);
4699
Krishna Konda25786ec2011-07-25 16:21:36 -07004700 if (host->is_dma_mode && host->dma.channel != -1
4701 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004702 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004704 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004705 mmc_hostname(mmc), host->dma.cmd_busaddr,
4706 host->dma.cmdptr_busaddr);
4707 } else if (host->is_sps_mode) {
4708 pr_info("%s: SPS-BAM data transfer mode available\n",
4709 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004710 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004711 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713#if defined(CONFIG_DEBUG_FS)
4714 msmsdcc_dbg_createhost(host);
4715#endif
4716 if (!plat->status_irq) {
4717 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4718 if (ret)
4719 goto platform_irq_free;
4720 }
San Mehat9d2bd732009-09-22 16:44:22 -07004721 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004722
4723 platform_irq_free:
4724 del_timer_sync(&host->req_tout_timer);
4725 pm_runtime_disable(&(pdev)->dev);
4726 pm_runtime_set_suspended(&(pdev)->dev);
4727
4728 if (plat->status_irq)
4729 free_irq(plat->status_irq, host);
4730 sdiowakeup_irq_free:
4731 wake_lock_destroy(&host->sdio_suspend_wlock);
4732 if (plat->sdiowakeup_irq)
4733 free_irq(plat->sdiowakeup_irq, host);
4734 pio_irq_free:
4735 if (plat->sdiowakeup_irq)
4736 wake_lock_destroy(&host->sdio_wlock);
4737 free_irq(core_irqres->start, host);
4738 irq_free:
4739 free_irq(core_irqres->start, host);
4740 dml_exit:
4741 if (host->is_sps_mode)
4742 msmsdcc_dml_exit(host);
4743 sps_exit:
4744 if (host->is_sps_mode)
4745 msmsdcc_sps_exit(host);
4746 vreg_deinit:
4747 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004748 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004749 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304750 if (host->plat->swfi_latency)
4751 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004752 clk_put:
4753 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754 pclk_disable:
4755 if (!IS_ERR(host->pclk))
4756 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004757 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 if (!IS_ERR(host->pclk))
4759 clk_put(host->pclk);
4760 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4761 clk_disable(host->dfab_pclk);
4762 dfab_pclk_put:
4763 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4764 clk_put(host->dfab_pclk);
4765 dma_free:
4766 if (host->is_dma_mode) {
4767 if (host->dmares)
4768 dma_free_coherent(NULL,
4769 sizeof(struct msmsdcc_nc_dmadata),
4770 host->dma.nc, host->dma.nc_busaddr);
4771 }
4772 ioremap_free:
4773 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004774 host_free:
4775 mmc_free_host(mmc);
4776 out:
4777 return ret;
4778}
4779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004780static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004781{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4783 struct mmc_platform_data *plat;
4784 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004786 if (!mmc)
4787 return -ENXIO;
4788
4789 if (pm_runtime_suspended(&(pdev)->dev))
4790 pm_runtime_resume(&(pdev)->dev);
4791
4792 host = mmc_priv(mmc);
4793
4794 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4795 plat = host->plat;
4796
4797 if (!plat->status_irq)
4798 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4799
4800 del_timer_sync(&host->req_tout_timer);
4801 tasklet_kill(&host->dma_tlet);
4802 tasklet_kill(&host->sps.tlet);
4803 mmc_remove_host(mmc);
4804
4805 if (plat->status_irq)
4806 free_irq(plat->status_irq, host);
4807
4808 wake_lock_destroy(&host->sdio_suspend_wlock);
4809 if (plat->sdiowakeup_irq) {
4810 wake_lock_destroy(&host->sdio_wlock);
4811 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4812 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004813 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004814
4815 free_irq(host->core_irqres->start, host);
4816 free_irq(host->core_irqres->start, host);
4817
4818 clk_put(host->clk);
4819 if (!IS_ERR(host->pclk))
4820 clk_put(host->pclk);
4821 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4822 clk_put(host->dfab_pclk);
4823
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304824 if (host->plat->swfi_latency)
4825 pm_qos_remove_request(&host->pm_qos_req_dma);
4826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004827 msmsdcc_vreg_init(host, false);
4828
4829 if (host->is_dma_mode) {
4830 if (host->dmares)
4831 dma_free_coherent(NULL,
4832 sizeof(struct msmsdcc_nc_dmadata),
4833 host->dma.nc, host->dma.nc_busaddr);
4834 }
4835
4836 if (host->is_sps_mode) {
4837 msmsdcc_dml_exit(host);
4838 msmsdcc_sps_exit(host);
4839 }
4840
4841 iounmap(host->base);
4842 mmc_free_host(mmc);
4843
4844#ifdef CONFIG_HAS_EARLYSUSPEND
4845 unregister_early_suspend(&host->early_suspend);
4846#endif
4847 pm_runtime_disable(&(pdev)->dev);
4848 pm_runtime_set_suspended(&(pdev)->dev);
4849
4850 return 0;
4851}
4852
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07004853static void msmsdcc_shutdown(struct platform_device *pdev)
4854{
4855 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4856
4857 mmc_remove_host(mmc);
4858 mmc_free_host(mmc);
4859}
4860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004861#ifdef CONFIG_MSM_SDIO_AL
4862int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4863{
4864 struct msmsdcc_host *host = mmc_priv(mmc);
4865 unsigned long flags;
4866
4867 spin_lock_irqsave(&host->lock, flags);
4868 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4869 enable ? "En" : "Dis");
4870
4871 if (enable) {
4872 if (!host->sdcc_irq_disabled) {
4873 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304874 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004875 host->sdcc_irq_disabled = 1;
4876 }
4877
4878 if (host->clks_on) {
4879 msmsdcc_setup_clocks(host, false);
4880 host->clks_on = 0;
4881 }
4882
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304883 if (host->plat->sdio_lpm_gpio_setup &&
4884 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004885 spin_unlock_irqrestore(&host->lock, flags);
4886 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4887 spin_lock_irqsave(&host->lock, flags);
4888 host->sdio_gpio_lpm = 1;
4889 }
4890
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304891 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004892 msmsdcc_enable_irq_wake(host);
4893 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304894 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004895 }
4896 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304897 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004898 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304899 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004900 msmsdcc_disable_irq_wake(host);
4901 }
4902
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304903 if (host->plat->sdio_lpm_gpio_setup &&
4904 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004905 spin_unlock_irqrestore(&host->lock, flags);
4906 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4907 spin_lock_irqsave(&host->lock, flags);
4908 host->sdio_gpio_lpm = 0;
4909 }
4910
4911 if (!host->clks_on) {
4912 msmsdcc_setup_clocks(host, true);
4913 host->clks_on = 1;
4914 }
4915
4916 if (host->sdcc_irq_disabled) {
4917 writel_relaxed(host->mci_irqenable,
4918 host->base + MMCIMASK0);
4919 mb();
4920 enable_irq(host->core_irqres->start);
4921 host->sdcc_irq_disabled = 0;
4922 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004923 }
4924 spin_unlock_irqrestore(&host->lock, flags);
4925 return 0;
4926}
4927#else
4928int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4929{
4930 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004931}
4932#endif
4933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004934#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004935static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004937{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004938 struct mmc_host *mmc = dev_get_drvdata(dev);
4939 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004940 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304941 unsigned long flags;
4942
San Mehat9d2bd732009-09-22 16:44:22 -07004943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004944 if (host->plat->is_sdio_al_client)
4945 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304946 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004947 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004948 host->sdcc_suspending = 1;
4949 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004952 * MMC core thinks that host is disabled by now since
4953 * runtime suspend is scheduled after msmsdcc_disable()
4954 * is called. Thus, MMC core will try to enable the host
4955 * while suspending it. This results in a synchronous
4956 * runtime resume request while in runtime suspending
4957 * context and hence inorder to complete this resume
4958 * requet, it will wait for suspend to be complete,
4959 * but runtime suspend also can not proceed further
4960 * until the host is resumed. Thus, it leads to a hang.
4961 * Hence, increase the pm usage count before suspending
4962 * the host so that any resume requests after this will
4963 * simple become pm usage counter increment operations.
4964 */
4965 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304966 /* If there is pending detect work abort runtime suspend */
4967 if (unlikely(work_busy(&mmc->detect.work)))
4968 rc = -EAGAIN;
4969 else
4970 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004971 pm_runtime_put_noidle(dev);
4972
4973 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304974 spin_lock_irqsave(&host->lock, flags);
4975 host->sdcc_suspended = true;
4976 spin_unlock_irqrestore(&host->lock, flags);
4977 if (mmc->card && mmc_card_sdio(mmc->card) &&
4978 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004979 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304980 * If SDIO function driver doesn't want
4981 * to power off the card, atleast turn off
4982 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004983 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304984 mmc_host_clk_hold(mmc);
4985 spin_lock_irqsave(&mmc->clk_lock, flags);
4986 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004987 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304988 mmc->clk_gated = true;
4989 spin_unlock_irqrestore(&mmc->clk_lock, flags);
4990 mmc_set_ios(mmc);
4991 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992 }
4993 }
4994 host->sdcc_suspending = 0;
4995 mmc->suspend_task = NULL;
4996 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4997 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004998 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304999 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005000 return rc;
5001}
5002
5003static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005005{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005006 struct mmc_host *mmc = dev_get_drvdata(dev);
5007 struct msmsdcc_host *host = mmc_priv(mmc);
5008 unsigned long flags;
5009
5010 if (host->plat->is_sdio_al_client)
5011 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005012
Sahitya Tummala7661a452011-07-18 13:28:35 +05305013 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005014 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305015 if (mmc->card && mmc_card_sdio(mmc->card) &&
5016 mmc_card_keep_power(mmc)) {
5017 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305018 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305019 mmc_set_ios(mmc);
5020 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305021 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005022
5023 mmc_resume_host(mmc);
5024
5025 /*
5026 * FIXME: Clearing of flags must be handled in clients
5027 * resume handler.
5028 */
5029 spin_lock_irqsave(&host->lock, flags);
5030 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305031 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005032 spin_unlock_irqrestore(&host->lock, flags);
5033
5034 /*
5035 * After resuming the host wait for sometime so that
5036 * the SDIO work will be processed.
5037 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305038 if (mmc->card && mmc_card_sdio(mmc->card)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005039 if ((host->plat->cfg_mpm_sdiowakeup ||
5040 host->plat->sdiowakeup_irq) &&
5041 wake_lock_active(&host->sdio_wlock))
5042 wake_lock_timeout(&host->sdio_wlock, 1);
5043 }
5044
5045 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005046 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305047 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005048 return 0;
5049}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005050
5051static int msmsdcc_runtime_idle(struct device *dev)
5052{
5053 struct mmc_host *mmc = dev_get_drvdata(dev);
5054 struct msmsdcc_host *host = mmc_priv(mmc);
5055
5056 if (host->plat->is_sdio_al_client)
5057 return 0;
5058
5059 /* Idle timeout is not configurable for now */
5060 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5061
5062 return -EAGAIN;
5063}
5064
5065static int msmsdcc_pm_suspend(struct device *dev)
5066{
5067 struct mmc_host *mmc = dev_get_drvdata(dev);
5068 struct msmsdcc_host *host = mmc_priv(mmc);
5069 int rc = 0;
5070
5071 if (host->plat->is_sdio_al_client)
5072 return 0;
5073
5074
5075 if (host->plat->status_irq)
5076 disable_irq(host->plat->status_irq);
5077
Subhash Jadavani18702212012-03-19 18:50:18 +05305078 if (!pm_runtime_suspended(dev)) {
5079 if (!(mmc->card && mmc_card_sdio(mmc->card))) {
5080 /*
5081 * decrement power.usage_counter if it's
5082 * not zero earlier
5083 */
5084 pm_runtime_put_noidle(dev);
5085 rc = pm_runtime_suspend(dev);
5086 }
5087
5088 /*
5089 * if device runtime PM status is still not suspended
5090 * then perform suspend here.
5091 */
5092 if (!pm_runtime_suspended(dev))
5093 rc = msmsdcc_runtime_suspend(dev);
5094 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005095
5096 return rc;
5097}
5098
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305099static int msmsdcc_suspend_noirq(struct device *dev)
5100{
5101 struct mmc_host *mmc = dev_get_drvdata(dev);
5102 struct msmsdcc_host *host = mmc_priv(mmc);
5103 int rc = 0;
5104
5105 /*
5106 * After platform suspend there may be active request
5107 * which might have enabled clocks. For example, in SDIO
5108 * case, ksdioirq thread might have scheduled after sdcc
5109 * suspend but before system freeze. In that case abort
5110 * suspend and retry instead of keeping the clocks on
5111 * during suspend and not allowing TCXO.
5112 */
5113
5114 if (host->clks_on) {
5115 pr_warn("%s: clocks are on after suspend, aborting system "
5116 "suspend\n", mmc_hostname(mmc));
5117 rc = -EAGAIN;
5118 }
5119
5120 return rc;
5121}
5122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005123static int msmsdcc_pm_resume(struct device *dev)
5124{
5125 struct mmc_host *mmc = dev_get_drvdata(dev);
5126 struct msmsdcc_host *host = mmc_priv(mmc);
5127 int rc = 0;
5128
5129 if (host->plat->is_sdio_al_client)
5130 return 0;
5131
Sahitya Tummalafb486372011-09-02 19:01:49 +05305132 if (!pm_runtime_suspended(dev))
5133 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005134 if (host->plat->status_irq) {
5135 msmsdcc_check_status((unsigned long)host);
5136 enable_irq(host->plat->status_irq);
5137 }
5138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005139 return rc;
5140}
5141
Daniel Walker08ecfde2010-06-23 12:32:20 -07005142#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005143#define msmsdcc_runtime_suspend NULL
5144#define msmsdcc_runtime_resume NULL
5145#define msmsdcc_runtime_idle NULL
5146#define msmsdcc_pm_suspend NULL
5147#define msmsdcc_pm_resume NULL
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305148#define msmsdcc_suspend_noirq NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07005149#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005151static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5152 .runtime_suspend = msmsdcc_runtime_suspend,
5153 .runtime_resume = msmsdcc_runtime_resume,
5154 .runtime_idle = msmsdcc_runtime_idle,
5155 .suspend = msmsdcc_pm_suspend,
5156 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305157 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005158};
5159
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305160static const struct of_device_id msmsdcc_dt_match[] = {
5161 {.compatible = "qcom,msm-sdcc"},
5162
5163};
5164MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5165
San Mehat9d2bd732009-09-22 16:44:22 -07005166static struct platform_driver msmsdcc_driver = {
5167 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005168 .remove = msmsdcc_remove,
Oluwafemi Adeyemif68d3e62012-03-13 11:46:49 -07005169 .shutdown = msmsdcc_shutdown,
San Mehat9d2bd732009-09-22 16:44:22 -07005170 .driver = {
5171 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005172 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305173 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005174 },
5175};
5176
5177static int __init msmsdcc_init(void)
5178{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005179#if defined(CONFIG_DEBUG_FS)
5180 int ret = 0;
5181 ret = msmsdcc_dbg_init();
5182 if (ret) {
5183 pr_err("Failed to create debug fs dir \n");
5184 return ret;
5185 }
5186#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005187 return platform_driver_register(&msmsdcc_driver);
5188}
5189
5190static void __exit msmsdcc_exit(void)
5191{
5192 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005193
5194#if defined(CONFIG_DEBUG_FS)
5195 debugfs_remove(debugfs_file);
5196 debugfs_remove(debugfs_dir);
5197#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005198}
5199
5200module_init(msmsdcc_init);
5201module_exit(msmsdcc_exit);
5202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005203MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005204MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205
5206#if defined(CONFIG_DEBUG_FS)
5207
5208static int
5209msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5210{
5211 file->private_data = inode->i_private;
5212 return 0;
5213}
5214
5215static ssize_t
5216msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5217 size_t count, loff_t *ppos)
5218{
5219 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005220 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005221 int max, i;
5222
5223 i = 0;
5224 max = sizeof(buf) - 1;
5225
5226 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5227 host->curr.cmd, host->curr.data);
5228 if (host->curr.cmd) {
5229 struct mmc_command *cmd = host->curr.cmd;
5230
5231 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5232 cmd->opcode, cmd->arg, cmd->flags);
5233 }
5234 if (host->curr.data) {
5235 struct mmc_data *data = host->curr.data;
5236 i += scnprintf(buf + i, max - i,
5237 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5238 data->timeout_ns, data->timeout_clks,
5239 data->blksz, data->blocks, data->error,
5240 data->flags);
5241 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5242 host->curr.xfer_size, host->curr.xfer_remain,
5243 host->curr.data_xfered, host->dma.sg);
5244 }
5245
5246 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5247}
5248
5249static const struct file_operations msmsdcc_dbg_state_ops = {
5250 .read = msmsdcc_dbg_state_read,
5251 .open = msmsdcc_dbg_state_open,
5252};
5253
5254static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5255{
5256 if (debugfs_dir) {
5257 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5258 0644, debugfs_dir, host,
5259 &msmsdcc_dbg_state_ops);
5260 }
5261}
5262
5263static int __init msmsdcc_dbg_init(void)
5264{
5265 int err;
5266
5267 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5268 if (IS_ERR(debugfs_dir)) {
5269 err = PTR_ERR(debugfs_dir);
5270 debugfs_dir = NULL;
5271 return err;
5272 }
5273
5274 return 0;
5275}
5276#endif