blob: 73a3171630d73e69c09ab4f7c76edafdf4ab2cb3 [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>
Subhash Jadavanic9b85752012-04-13 11:16:49 +053057#include <mach/mpm.h>
San Mehat9d2bd732009-09-22 16:44:22 -070058
San Mehat9d2bd732009-09-22 16:44:22 -070059#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070061
62#define DRIVER_NAME "msm-sdcc"
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#define DBG(host, fmt, args...) \
65 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
66
67#define IRQ_DEBUG 0
68#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
69#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
70#define SPS_CONS_PERIPHERAL 0
71#define SPS_PROD_PERIPHERAL 1
Subhash Jadavanie6e1b822012-03-12 18:17:58 +053072/* Use SPS only if transfer size is more than this macro */
73#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
75#if defined(CONFIG_DEBUG_FS)
76static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
77static struct dentry *debugfs_dir;
78static struct dentry *debugfs_file;
79static int msmsdcc_dbg_init(void);
80#endif
81
Asutosh Dasaccacd42012-03-08 14:33:17 +053082static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
83 *data);
84
Subhash Jadavani8766e352011-11-30 11:30:32 +053085static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070086static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088static struct mmc_command dummy52cmd;
89static struct mmc_request dummy52mrq = {
90 .cmd = &dummy52cmd,
91 .data = NULL,
92 .stop = NULL,
93};
94static struct mmc_command dummy52cmd = {
95 .opcode = SD_IO_RW_DIRECT,
96 .flags = MMC_RSP_PRESENT,
97 .data = NULL,
98 .mrq = &dummy52mrq,
99};
100/*
101 * An array holding the Tuning pattern to compare with when
102 * executing a tuning cycle.
103 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530104static const u32 tuning_block_64[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
106 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
107 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
108 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
109};
San Mehat865c8062009-11-13 13:42:06 -0800110
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +0530111static const u32 tuning_block_128[] = {
112 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
113 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
114 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
115 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
116 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
117 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
118 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
119 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
120};
121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122#if IRQ_DEBUG == 1
123static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
124 "dattimeout", "txunderrun", "rxoverrun",
125 "cmdrespend", "cmdsent", "dataend", NULL,
126 "datablkend", "cmdactive", "txactive",
127 "rxactive", "txhalfempty", "rxhalffull",
128 "txfifofull", "rxfifofull", "txfifoempty",
129 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
130 "sdiointr", "progdone", "atacmdcompl",
131 "sdiointrope", "ccstimeout", NULL, NULL,
132 NULL, NULL, NULL };
133
134static void
135msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800136{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
140 for (i = 0; i < 32; i++) {
141 if (status & (1 << i))
142 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800143 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800145}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146#endif
San Mehat865c8062009-11-13 13:42:06 -0800147
San Mehat9d2bd732009-09-22 16:44:22 -0700148static void
149msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
150 u32 c);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530151static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530152static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530153static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -0800154static void msmsdcc_sg_start(struct msmsdcc_host *host);
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -0800155static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -0700156static int msmsdcc_runtime_resume(struct device *dev);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530157
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530158static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
159{
160 unsigned short ret = NR_SG;
161
162 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530163 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530164 } else { /* DMA or PIO mode */
165 if (NR_SG > MAX_NR_SG_DMA_PIO)
166 ret = MAX_NR_SG_DMA_PIO;
167 }
168
169 return ret;
170}
171
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530172/* Prevent idle power collapse(pc) while operating in peripheral mode */
173static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
174{
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700175 if (!host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530176 return;
177
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530178 if (vote)
179 pm_qos_update_request(&host->pm_qos_req_dma,
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -0700180 host->cpu_dma_latency);
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530181 else
182 pm_qos_update_request(&host->pm_qos_req_dma,
183 PM_QOS_DEFAULT_VALUE);
184}
185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
187static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
188 struct msmsdcc_sps_ep_conn_data *ep);
189static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
190 struct msmsdcc_sps_ep_conn_data *ep);
191#else
192static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
193 struct msmsdcc_sps_ep_conn_data *ep,
194 bool is_producer) { return 0; }
195static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
196 struct msmsdcc_sps_ep_conn_data *ep) { }
197static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
198 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530199{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 return 0;
201}
202static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
203 struct msmsdcc_sps_ep_conn_data *ep)
204{
205 return 0;
206}
207static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
208static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
209#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530212 * Apply soft reset to all SDCC BAM pipes
213 *
214 * This function applies soft reset to SDCC BAM pipe.
215 *
216 * This function should be called to recover from error
217 * conditions encountered during CMD/DATA tranfsers with card.
218 *
219 * @host - Pointer to driver's host structure
220 *
221 */
222static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
223{
224 int rc;
225
226 /* Reset all SDCC BAM pipes */
227 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
228 if (rc)
229 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
230 mmc_hostname(host->mmc), rc);
231 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
232 if (rc)
233 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
234 mmc_hostname(host->mmc), rc);
235
236 /* Restore all BAM pipes connections */
237 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
238 if (rc)
239 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
240 mmc_hostname(host->mmc), rc);
241 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
242 if (rc)
243 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
244 mmc_hostname(host->mmc), rc);
245}
246
247/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 * Apply soft reset
249 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530250 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 *
252 * This function should be called to recover from error
253 * conditions encountered with CMD/DATA tranfsers with card.
254 *
255 * Soft reset should only be used with SDCC controller v4.
256 *
257 * @host - Pointer to driver's host structure
258 *
259 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530260static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 /*
263 * Reset SDCC controller's DPSM (data path state machine
264 * and CPSM (command path state machine).
265 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530267 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530269 msmsdcc_sync_reg_wr(host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530270}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530271
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530272static void msmsdcc_hard_reset(struct msmsdcc_host *host)
273{
274 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530275
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530276 /* Reset the controller */
277 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
278 if (ret)
279 pr_err("%s: Clock assert failed at %u Hz"
280 " with err %d\n", mmc_hostname(host->mmc),
281 host->clk_rate, ret);
282
283 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
284 if (ret)
285 pr_err("%s: Clock deassert failed at %u Hz"
286 " with err %d\n", mmc_hostname(host->mmc),
287 host->clk_rate, ret);
288
Subhash Jadavanidd432952012-03-28 11:25:56 +0530289 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530290 /* Give some delay for clock reset to propogate to controller */
291 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530292}
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
295{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530296 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530297 if (host->is_sps_mode) {
298 /* Reset DML first */
299 msmsdcc_dml_reset(host);
300 /*
301 * delay the SPS pipe reset in thread context as
302 * sps_connect/sps_disconnect APIs can be called
303 * only from non-atomic context.
304 */
305 host->sps.pipe_reset_pending = true;
306 }
307 mb();
308 msmsdcc_soft_reset(host);
309
310 pr_debug("%s: Applied soft reset to Controller\n",
311 mmc_hostname(host->mmc));
312
313 if (host->is_sps_mode)
314 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 } else {
316 /* Give Clock reset (hard reset) to controller */
317 u32 mci_clk = 0;
318 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319
320 /* Save the controller state */
321 mci_clk = readl_relaxed(host->base + MMCICLOCK);
322 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +0530323 host->pwr = readl_relaxed(host->base + MMCIPOWER);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530326 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 pr_debug("%s: Controller has been reinitialized\n",
328 mmc_hostname(host->mmc));
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 /* Restore the contoller state */
331 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530332 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530334 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530336 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530338
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700339 if (host->dummy_52_needed)
340 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341}
342
343static int
San Mehat9d2bd732009-09-22 16:44:22 -0700344msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
345{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 int retval = 0;
347
San Mehat9d2bd732009-09-22 16:44:22 -0700348 BUG_ON(host->curr.data);
349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 del_timer(&host->req_tout_timer);
351
San Mehat9d2bd732009-09-22 16:44:22 -0700352 if (mrq->data)
353 mrq->data->bytes_xfered = host->curr.data_xfered;
354 if (mrq->cmd->error == -ETIMEDOUT)
355 mdelay(5);
356
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530357 /* Clear current request information as current request has ended */
358 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
359
San Mehat9d2bd732009-09-22 16:44:22 -0700360 /*
361 * Need to drop the host lock here; mmc_request_done may call
362 * back into the driver...
363 */
364 spin_unlock(&host->lock);
365 mmc_request_done(host->mmc, mrq);
366 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367
368 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700369}
370
371static void
372msmsdcc_stop_data(struct msmsdcc_host *host)
373{
San Mehat9d2bd732009-09-22 16:44:22 -0700374 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530375 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530376 host->curr.wait_for_auto_prog_done = 0;
377 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700378 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
379 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530380 msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700381}
382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700384{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 return host->core_memres->start + MMCIFIFO;
386}
387
388static inline unsigned int msmsdcc_get_min_sup_clk_rate(
389 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530390
Subhash Jadavanidd432952012-03-28 11:25:56 +0530391static inline void msmsdcc_sync_reg_wr(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392{
393 mb();
Subhash Jadavanidd432952012-03-28 11:25:56 +0530394 if (!host->sdcc_version)
395 udelay(host->reg_write_delay);
396 else if (readl_relaxed(host->base + MCI_STATUS2) &
397 MCI_MCLK_REG_WR_ACTIVE) {
398 ktime_t start, diff;
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530399
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530400 start = ktime_get();
401 while (readl_relaxed(host->base + MCI_STATUS2) &
402 MCI_MCLK_REG_WR_ACTIVE) {
403 diff = ktime_sub(ktime_get(), start);
404 /* poll for max. 1 ms */
405 if (ktime_to_us(diff) > 1000) {
406 pr_warning("%s: previous reg. write is"
407 " still active\n",
408 mmc_hostname(host->mmc));
409 break;
410 }
411 }
412 }
San Mehat9d2bd732009-09-22 16:44:22 -0700413}
414
Subhash Jadavanidd432952012-03-28 11:25:56 +0530415static inline void msmsdcc_delay(struct msmsdcc_host *host)
416{
417 udelay(host->reg_write_delay);
418
419}
420
San Mehat56a8b5b2009-11-21 12:29:46 -0800421static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
423{
424 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530426 /*
427 * As after sending the command, we don't write any of the
428 * controller registers and just wait for the
429 * CMD_RESPOND_END/CMD_SENT/Command failure notication
430 * from Controller.
431 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800433}
434
435static void
436msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
437{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
441 writel_relaxed((unsigned int)host->curr.xfer_size,
442 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
Subhash Jadavanidd432952012-03-28 11:25:56 +0530444 msmsdcc_sync_reg_wr(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800445
San Mehat6ac9ea62009-12-02 17:24:58 -0800446 if (host->cmd_cmd) {
447 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800449 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800450}
451
San Mehat9d2bd732009-09-22 16:44:22 -0700452static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530453msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700454{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530455 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700456 unsigned long flags;
457 struct mmc_request *mrq;
458
459 spin_lock_irqsave(&host->lock, flags);
460 mrq = host->curr.mrq;
461 BUG_ON(!mrq);
462
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530463 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700464 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700465 goto out;
466 }
467
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530468 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700471 } else {
472 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530473 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700474 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530475 mmc_hostname(host->mmc), host->dma.result);
476 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700477 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530478 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530479 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 host->dma.err.flush[0], host->dma.err.flush[1],
481 host->dma.err.flush[2], host->dma.err.flush[3],
482 host->dma.err.flush[4],
483 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530484 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700485 if (!mrq->data->error)
486 mrq->data->error = -EIO;
487 }
Asutosh Dasaccacd42012-03-08 14:33:17 +0530488 if (!mrq->data->host_cookie)
489 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
490 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 if (host->curr.user_pages) {
493 struct scatterlist *sg = host->dma.sg;
494 int i;
495
496 for (i = 0; i < host->dma.num_ents; i++, sg++)
497 flush_dcache_page(sg_page(sg));
498 }
499
San Mehat9d2bd732009-09-22 16:44:22 -0700500 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800501 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700502
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530503 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
504 (host->curr.wait_for_auto_prog_done &&
505 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700506 /*
507 * If we've already gotten our DATAEND / DATABLKEND
508 * for this request, then complete it through here.
509 */
San Mehat9d2bd732009-09-22 16:44:22 -0700510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700512 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 host->curr.xfer_remain -= host->curr.xfer_size;
514 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700515 if (host->dummy_52_needed) {
516 mrq->data->bytes_xfered = host->curr.data_xfered;
517 host->dummy_52_sent = 1;
518 msmsdcc_start_command(host, &dummy52cmd,
519 MCI_CPSM_PROGENA);
520 goto out;
521 }
522 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530523 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530524 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700525 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530527 /*
528 * Clear current request information as current
529 * request has ended
530 */
531 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
San Mehat9d2bd732009-09-22 16:44:22 -0700532 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533
San Mehat9d2bd732009-09-22 16:44:22 -0700534 mmc_request_done(host->mmc, mrq);
535 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530536 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
537 || !mrq->sbc)) {
538 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530539 }
San Mehat9d2bd732009-09-22 16:44:22 -0700540 }
541
542out:
543 spin_unlock_irqrestore(&host->lock, flags);
544 return;
545}
546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
548/**
549 * Callback notification from SPS driver
550 *
551 * This callback function gets triggered called from
552 * SPS driver when requested SPS data transfer is
553 * completed.
554 *
555 * SPS driver invokes this callback in BAM irq context so
556 * SDCC driver schedule a tasklet for further processing
557 * this callback notification at later point of time in
558 * tasklet context and immediately returns control back
559 * to SPS driver.
560 *
561 * @nofity - Pointer to sps event notify sturcture
562 *
563 */
564static void
565msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
566{
567 struct msmsdcc_host *host =
568 (struct msmsdcc_host *)
569 ((struct sps_event_notify *)notify)->user;
570
571 host->sps.notify = *notify;
572 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
573 mmc_hostname(host->mmc), __func__, notify->event_id,
574 notify->data.transfer.iovec.addr,
575 notify->data.transfer.iovec.size,
576 notify->data.transfer.iovec.flags);
577 /* Schedule a tasklet for completing data transfer */
578 tasklet_schedule(&host->sps.tlet);
579}
580
581/**
582 * Tasklet handler for processing SPS callback event
583 *
584 * This function processing SPS event notification and
585 * checks if the SPS transfer is completed or not and
586 * then accordingly notifies status to MMC core layer.
587 *
588 * This function is called in tasklet context.
589 *
590 * @data - Pointer to sdcc driver data
591 *
592 */
593static void msmsdcc_sps_complete_tlet(unsigned long data)
594{
595 unsigned long flags;
596 int i, rc;
597 u32 data_xfered = 0;
598 struct mmc_request *mrq;
599 struct sps_iovec iovec;
600 struct sps_pipe *sps_pipe_handle;
601 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
602 struct sps_event_notify *notify = &host->sps.notify;
603
604 spin_lock_irqsave(&host->lock, flags);
605 if (host->sps.dir == DMA_FROM_DEVICE)
606 sps_pipe_handle = host->sps.prod.pipe_handle;
607 else
608 sps_pipe_handle = host->sps.cons.pipe_handle;
609 mrq = host->curr.mrq;
610
611 if (!mrq) {
612 spin_unlock_irqrestore(&host->lock, flags);
613 return;
614 }
615
616 pr_debug("%s: %s: sps event_id=%d\n",
617 mmc_hostname(host->mmc), __func__,
618 notify->event_id);
619
620 if (msmsdcc_is_dml_busy(host)) {
621 /* oops !!! this should never happen. */
622 pr_err("%s: %s: Received SPS EOT event"
623 " but DML HW is still busy !!!\n",
624 mmc_hostname(host->mmc), __func__);
625 }
626 /*
627 * Got End of transfer event!!! Check if all of the data
628 * has been transferred?
629 */
630 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
631 rc = sps_get_iovec(sps_pipe_handle, &iovec);
632 if (rc) {
633 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
634 mmc_hostname(host->mmc), __func__, rc, i);
635 break;
636 }
637 data_xfered += iovec.size;
638 }
639
640 if (data_xfered == host->curr.xfer_size) {
641 host->curr.data_xfered = host->curr.xfer_size;
642 host->curr.xfer_remain -= host->curr.xfer_size;
643 pr_debug("%s: Data xfer success. data_xfered=0x%x",
644 mmc_hostname(host->mmc),
645 host->curr.xfer_size);
646 } else {
647 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
648 " xfer_size=%d", mmc_hostname(host->mmc),
649 data_xfered, host->curr.xfer_size);
650 msmsdcc_reset_and_restore(host);
651 if (!mrq->data->error)
652 mrq->data->error = -EIO;
653 }
654
655 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530656 if (!mrq->data->host_cookie)
657 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
658 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 host->sps.sg = NULL;
660 host->sps.busy = 0;
661
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530662 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
663 (host->curr.wait_for_auto_prog_done &&
664 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 /*
666 * If we've already gotten our DATAEND / DATABLKEND
667 * for this request, then complete it through here.
668 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669
670 if (!mrq->data->error) {
671 host->curr.data_xfered = host->curr.xfer_size;
672 host->curr.xfer_remain -= host->curr.xfer_size;
673 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700674 if (host->dummy_52_needed) {
675 mrq->data->bytes_xfered = host->curr.data_xfered;
676 host->dummy_52_sent = 1;
677 msmsdcc_start_command(host, &dummy52cmd,
678 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700679 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700680 return;
681 }
682 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530683 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530684 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 mrq->data->bytes_xfered = host->curr.data_xfered;
686 del_timer(&host->req_tout_timer);
Subhash Jadavanied6b0e42012-03-07 16:36:27 +0530687 /*
688 * Clear current request information as current
689 * request has ended
690 */
691 memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 spin_unlock_irqrestore(&host->lock, flags);
693
694 mmc_request_done(host->mmc, mrq);
695 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530696 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
697 || !mrq->sbc)) {
698 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 }
700 }
701 spin_unlock_irqrestore(&host->lock, flags);
702}
703
704/**
705 * Exit from current SPS data transfer
706 *
707 * This function exits from current SPS data transfer.
708 *
709 * This function should be called when error condition
710 * is encountered during data transfer.
711 *
712 * @host - Pointer to sdcc host structure
713 *
714 */
715static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
716{
717 struct mmc_request *mrq;
718
719 mrq = host->curr.mrq;
720 BUG_ON(!mrq);
721
722 msmsdcc_reset_and_restore(host);
723 if (!mrq->data->error)
724 mrq->data->error = -EIO;
725
726 /* Unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +0530727 if (!mrq->data->host_cookie)
728 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
729 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730
731 host->sps.sg = NULL;
732 host->sps.busy = 0;
733 if (host->curr.data)
734 msmsdcc_stop_data(host);
735
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530736 if (!mrq->data->stop || mrq->cmd->error ||
737 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530739 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
740 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 msmsdcc_start_command(host, mrq->data->stop, 0);
742
743}
744#else
745static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
746static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
747static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
748#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
749
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530750static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530752static void
753msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
754 unsigned int result,
755 struct msm_dmov_errdata *err)
756{
757 struct msmsdcc_dma_data *dma_data =
758 container_of(cmd, struct msmsdcc_dma_data, hdr);
759 struct msmsdcc_host *host = dma_data->host;
760
761 dma_data->result = result;
762 if (err)
763 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
764
765 tasklet_schedule(&host->dma_tlet);
766}
767
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530768static bool msmsdcc_is_dma_possible(struct msmsdcc_host *host,
769 struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700770{
Subhash Jadavanie6e1b822012-03-12 18:17:58 +0530771 bool ret = true;
772 u32 xfer_size = data->blksz * data->blocks;
773
774 if (host->is_sps_mode) {
775 /*
776 * BAM Mode: Fall back on PIO if size is less
777 * than or equal to SPS_MIN_XFER_SIZE bytes.
778 */
779 if (xfer_size <= SPS_MIN_XFER_SIZE)
780 ret = false;
781 } else if (host->is_dma_mode) {
782 /*
783 * ADM Mode: Fall back on PIO if size is less than FIFO size
784 * or not integer multiple of FIFO size
785 */
786 if (xfer_size % MCI_FIFOSIZE)
787 ret = false;
788 } else {
789 /* PIO Mode */
790 ret = false;
791 }
792
793 return ret;
San Mehat9d2bd732009-09-22 16:44:22 -0700794}
795
796static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
797{
798 struct msmsdcc_nc_dmadata *nc;
799 dmov_box *box;
800 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700801 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530802 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700803 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530804 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700805
Krishna Konda25786ec2011-07-25 16:21:36 -0700806 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700808
Krishna Konda25786ec2011-07-25 16:21:36 -0700809 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
810
San Mehat9d2bd732009-09-22 16:44:22 -0700811 host->dma.sg = data->sg;
812 host->dma.num_ents = data->sg_len;
813
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530814 /* Prevent memory corruption */
815 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800816
San Mehat9d2bd732009-09-22 16:44:22 -0700817 nc = host->dma.nc;
818
San Mehat9d2bd732009-09-22 16:44:22 -0700819 if (data->flags & MMC_DATA_READ)
820 host->dma.dir = DMA_FROM_DEVICE;
821 else
822 host->dma.dir = DMA_TO_DEVICE;
823
Asutosh Dasaccacd42012-03-08 14:33:17 +0530824 if (!data->host_cookie) {
825 n = msmsdcc_prep_xfer(host, data);
826 if (unlikely(n < 0)) {
827 host->dma.sg = NULL;
828 host->dma.num_ents = 0;
829 return -ENOMEM;
830 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800831 }
San Mehat9d2bd732009-09-22 16:44:22 -0700832
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530833 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
834 host->curr.user_pages = 0;
835 box = &nc->cmd[0];
836 for (i = 0; i < host->dma.num_ents; i++) {
837 len = sg_dma_len(sg);
838 offset = 0;
839
840 do {
841 /* Check if we can do DMA */
842 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
843 err = -ENOTSUPP;
844 goto unmap;
845 }
846
847 box->cmd = CMD_MODE_BOX;
848
849 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
850 len = MMC_MAX_DMA_BOX_LENGTH;
851 len -= len % data->blksz;
852 }
853 rows = (len % MCI_FIFOSIZE) ?
854 (len / MCI_FIFOSIZE) + 1 :
855 (len / MCI_FIFOSIZE);
856
857 if (data->flags & MMC_DATA_READ) {
858 box->src_row_addr = msmsdcc_fifo_addr(host);
859 box->dst_row_addr = sg_dma_address(sg) + offset;
860 box->src_dst_len = (MCI_FIFOSIZE << 16) |
861 (MCI_FIFOSIZE);
862 box->row_offset = MCI_FIFOSIZE;
863 box->num_rows = rows * ((1 << 16) + 1);
864 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
865 } else {
866 box->src_row_addr = sg_dma_address(sg) + offset;
867 box->dst_row_addr = msmsdcc_fifo_addr(host);
868 box->src_dst_len = (MCI_FIFOSIZE << 16) |
869 (MCI_FIFOSIZE);
870 box->row_offset = (MCI_FIFOSIZE << 16);
871 box->num_rows = rows * ((1 << 16) + 1);
872 box->cmd |= CMD_DST_CRCI(host->dma.crci);
873 }
874
875 offset += len;
876 len = sg_dma_len(sg) - offset;
877 box++;
878 box_cmd_cnt++;
879 } while (len);
880 sg++;
881 }
882 /* Mark last command */
883 box--;
884 box->cmd |= CMD_LC;
885
886 /* location of command block must be 64 bit aligned */
887 BUG_ON(host->dma.cmd_busaddr & 0x07);
888
889 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
890 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
891 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
892 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
893
894 /* Flush all data to memory before starting dma */
895 mb();
896
897unmap:
898 if (err) {
Asutosh Dasaccacd42012-03-08 14:33:17 +0530899 if (!data->host_cookie)
900 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
901 host->dma.num_ents, host->dma.dir);
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530902 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
903 mmc_hostname(host->mmc), err);
904 }
905
906 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700907}
908
Asutosh Dasaccacd42012-03-08 14:33:17 +0530909static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
910 struct mmc_data *data)
911{
912 int rc = 0;
913 unsigned int dir;
914
915 /* Prevent memory corruption */
916 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
917
918 if (data->flags & MMC_DATA_READ)
919 dir = DMA_FROM_DEVICE;
920 else
921 dir = DMA_TO_DEVICE;
922
923 /* Make sg buffers DMA ready */
924 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
925 dir);
926
927 if (unlikely(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 rc = -ENOMEM;
931 goto dma_map_err;
932 }
933
934 pr_debug("%s: %s: %s: sg_len=%d\n",
935 mmc_hostname(host->mmc), __func__,
936 dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
937 data->sg_len);
938
939 goto out;
940
941dma_map_err:
942 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
943 data->flags);
944out:
945 return rc;
946}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
948/**
949 * Submits data transfer request to SPS driver
950 *
951 * This function make sg (scatter gather) data buffers
952 * DMA ready and then submits them to SPS driver for
953 * transfer.
954 *
955 * @host - Pointer to sdcc host structure
956 * @data - Pointer to mmc_data structure
957 *
958 * @return 0 if success else negative value
959 */
960static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
Asutosh Dasaccacd42012-03-08 14:33:17 +0530961 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800962{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 int rc = 0;
964 u32 flags;
965 int i;
966 u32 addr, len, data_cnt;
967 struct scatterlist *sg = data->sg;
968 struct sps_pipe *sps_pipe_handle;
969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 host->sps.sg = data->sg;
971 host->sps.num_ents = data->sg_len;
972 host->sps.xfer_req_cnt = 0;
973 if (data->flags & MMC_DATA_READ) {
974 host->sps.dir = DMA_FROM_DEVICE;
975 sps_pipe_handle = host->sps.prod.pipe_handle;
976 } else {
977 host->sps.dir = DMA_TO_DEVICE;
978 sps_pipe_handle = host->sps.cons.pipe_handle;
979 }
980
Asutosh Dasaccacd42012-03-08 14:33:17 +0530981 if (!data->host_cookie) {
982 rc = msmsdcc_prep_xfer(host, data);
983 if (unlikely(rc < 0)) {
984 host->dma.sg = NULL;
985 host->dma.num_ents = 0;
986 goto out;
987 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 }
989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 for (i = 0; i < data->sg_len; i++) {
991 /*
992 * Check if this is the last buffer to transfer?
993 * If yes then set the INT and EOT flags.
994 */
995 len = sg_dma_len(sg);
996 addr = sg_dma_address(sg);
997 flags = 0;
998 while (len > 0) {
999 if (len > SPS_MAX_DESC_SIZE) {
1000 data_cnt = SPS_MAX_DESC_SIZE;
1001 } else {
1002 data_cnt = len;
1003 if (i == data->sg_len - 1)
1004 flags = SPS_IOVEC_FLAG_INT |
1005 SPS_IOVEC_FLAG_EOT;
1006 }
1007 rc = sps_transfer_one(sps_pipe_handle, addr,
1008 data_cnt, host, flags);
1009 if (rc) {
1010 pr_err("%s: sps_transfer_one() error! rc=%d,"
1011 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
1012 mmc_hostname(host->mmc), rc,
1013 (u32)sps_pipe_handle, (u32)sg, i);
1014 goto dma_map_err;
1015 }
1016 addr += data_cnt;
1017 len -= data_cnt;
1018 host->sps.xfer_req_cnt++;
1019 }
1020 sg++;
1021 }
1022 goto out;
1023
1024dma_map_err:
1025 /* unmap sg buffers */
Asutosh Dasaccacd42012-03-08 14:33:17 +05301026 if (!data->host_cookie)
1027 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
1028 host->sps.num_ents, host->sps.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029out:
1030 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07001031}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032#else
1033static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
1034 struct mmc_data *data) { return 0; }
1035#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -07001036
1037static void
San Mehat56a8b5b2009-11-21 12:29:46 -08001038msmsdcc_start_command_deferred(struct msmsdcc_host *host,
1039 struct mmc_command *cmd, u32 *c)
1040{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301041 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 cmd->opcode, cmd->arg, cmd->flags);
1043
San Mehat56a8b5b2009-11-21 12:29:46 -08001044 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
1045
1046 if (cmd->flags & MMC_RSP_PRESENT) {
1047 if (cmd->flags & MMC_RSP_136)
1048 *c |= MCI_CPSM_LONGRSP;
1049 *c |= MCI_CPSM_RESPONSE;
1050 }
1051
1052 if (/*interrupt*/0)
1053 *c |= MCI_CPSM_INTERRUPT;
1054
Asutosh Das05049132012-05-09 12:38:15 +05301055 /* DAT_CMD bit should be set for all ADTC */
1056 if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
San Mehat56a8b5b2009-11-21 12:29:46 -08001057 *c |= MCI_CSPM_DATCMD;
1058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301060 if (host->tuning_needed &&
1061 !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
1062
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301063 /*
1064 * For open ended block read operation (without CMD23),
1065 * AUTO_CMD19 bit should be set while sending the READ command.
1066 * For close ended block read operation (with CMD23),
1067 * AUTO_CMD19 bit should be set while sending CMD23.
1068 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301069 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
1070 host->curr.mrq->cmd->opcode ==
1071 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301072 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301073 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1074 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301075 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1076 *c |= MCI_CSPM_AUTO_CMD19;
1077 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 }
1079
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05301080 /* Clear CDR_EN bit for write operations */
1081 if (host->tuning_needed && cmd->mrq->data &&
1082 (cmd->mrq->data->flags & MMC_DATA_WRITE))
1083 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) &
1084 ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
1085
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301086 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301087 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301089 }
1090
San Mehat56a8b5b2009-11-21 12:29:46 -08001091 if (cmd == cmd->mrq->stop)
1092 *c |= MCI_CSPM_MCIABORT;
1093
San Mehat56a8b5b2009-11-21 12:29:46 -08001094 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 pr_err("%s: Overlapping command requests\n",
1096 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001097 }
1098 host->curr.cmd = cmd;
1099}
1100
1101static void
1102msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1103 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001104{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301105 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001106 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001108 unsigned int pio_irqmask = 0;
1109
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301110 BUG_ON(!data->sg);
1111 BUG_ON(!data->sg_len);
1112
San Mehat9d2bd732009-09-22 16:44:22 -07001113 host->curr.data = data;
1114 host->curr.xfer_size = data->blksz * data->blocks;
1115 host->curr.xfer_remain = host->curr.xfer_size;
1116 host->curr.data_xfered = 0;
1117 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301118 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001119
San Mehat9d2bd732009-09-22 16:44:22 -07001120 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1121
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301122 if (host->curr.wait_for_auto_prog_done)
1123 datactrl |= MCI_AUTO_PROG_DONE;
1124
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05301125 if (msmsdcc_is_dma_possible(host, data)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1127 datactrl |= MCI_DPSM_DMAENABLE;
1128 } else if (host->is_sps_mode) {
1129 if (!msmsdcc_is_dml_busy(host)) {
1130 if (!msmsdcc_sps_start_xfer(host, data)) {
1131 /* Now kick start DML transfer */
1132 mb();
1133 msmsdcc_dml_start_xfer(host, data);
1134 datactrl |= MCI_DPSM_DMAENABLE;
1135 host->sps.busy = 1;
1136 }
1137 } else {
1138 /*
1139 * Can't proceed with new transfer as
1140 * previous trasnfer is already in progress.
1141 * There is no point of going into PIO mode
1142 * as well. Is this a time to do kernel panic?
1143 */
1144 pr_err("%s: %s: DML HW is busy!!!"
1145 " Can't perform new SPS transfers"
1146 " now\n", mmc_hostname(host->mmc),
1147 __func__);
1148 }
1149 }
1150 }
1151
1152 /* Is data transfer in PIO mode required? */
1153 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001154 if (data->flags & MMC_DATA_READ) {
1155 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1156 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1157 pio_irqmask |= MCI_RXDATAAVLBLMASK;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001158 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1160 MCI_TXFIFOEMPTYMASK;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001161
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001162 msmsdcc_sg_start(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001163 }
1164
1165 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301166 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001167
San Mehat56a8b5b2009-11-21 12:29:46 -08001168 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001170 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1173 /* Use ADM (Application Data Mover) HW for Data transfer */
1174 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001175 host->cmd_timeout = timeout;
1176 host->cmd_pio_irqmask = pio_irqmask;
1177 host->cmd_datactrl = datactrl;
1178 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1181 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001182 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001183
1184 if (cmd) {
1185 msmsdcc_start_command_deferred(host, cmd, &c);
1186 host->cmd_c = c;
1187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1189 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1190 host->base + MMCIMASK0);
1191 mb();
1192 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001193 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1200 (~(MCI_IRQ_PIO))) | pio_irqmask,
1201 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 writel_relaxed(datactrl, base + MMCIDATACTRL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001203
1204 if (cmd) {
Subhash Jadavanidd432952012-03-28 11:25:56 +05301205 /* Delay between data/command */
1206 msmsdcc_sync_reg_wr(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001207 /* Daisy-chain the command if requested */
1208 msmsdcc_start_command(host, cmd, c);
Subhash Jadavanidd432952012-03-28 11:25:56 +05301209 } else {
1210 /*
1211 * We don't need delay after writing to DATA_CTRL
1212 * register if we are not writing to CMD register
1213 * immediately after this. As we already have delay
1214 * before sending the command, we just need mb() here.
1215 */
1216 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001217 }
San Mehat9d2bd732009-09-22 16:44:22 -07001218 }
1219}
1220
1221static void
1222msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1223{
San Mehat56a8b5b2009-11-21 12:29:46 -08001224 msmsdcc_start_command_deferred(host, cmd, &c);
1225 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001226}
1227
1228static void
1229msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1230 unsigned int status)
1231{
1232 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
Subhash Jadavanib30c9822012-03-27 18:03:16 +05301234 || data->mrq->cmd->opcode == MMC_BUS_TEST_R
1235 || data->mrq->cmd->opcode ==
1236 MMC_SEND_TUNING_BLOCK_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 pr_err("%s: Data CRC error\n",
1238 mmc_hostname(host->mmc));
1239 pr_err("%s: opcode 0x%.8x\n", __func__,
1240 data->mrq->cmd->opcode);
1241 pr_err("%s: blksz %d, blocks %d\n", __func__,
1242 data->blksz, data->blocks);
1243 data->error = -EILSEQ;
1244 }
San Mehat9d2bd732009-09-22 16:44:22 -07001245 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 /* CRC is optional for the bus test commands, not all
1247 * cards respond back with CRC. However controller
1248 * waits for the CRC and times out. Hence ignore the
1249 * data timeouts during the Bustest.
1250 */
1251 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1252 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301253 pr_err("%s: CMD%d: Data timeout\n",
1254 mmc_hostname(host->mmc),
1255 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301257 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 }
San Mehat9d2bd732009-09-22 16:44:22 -07001259 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001260 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001261 data->error = -EIO;
1262 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001263 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001264 data->error = -EIO;
1265 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001266 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001268 data->error = -EIO;
1269 }
San Mehat9d2bd732009-09-22 16:44:22 -07001270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001272 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 host->dummy_52_needed = 0;
1274}
San Mehat9d2bd732009-09-22 16:44:22 -07001275
1276static int
1277msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1278{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001280 uint32_t *ptr = (uint32_t *) buffer;
1281 int count = 0;
1282
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301283 if (remain % 4)
1284 remain = ((remain >> 2) + 1) << 2;
1285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1287
1288 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001289 ptr++;
1290 count += sizeof(uint32_t);
1291
1292 remain -= sizeof(uint32_t);
1293 if (remain == 0)
1294 break;
1295 }
1296 return count;
1297}
1298
1299static int
1300msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001302{
1303 void __iomem *base = host->base;
1304 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 while (readl_relaxed(base + MMCISTATUS) &
1308 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1309 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001310
San Mehat9d2bd732009-09-22 16:44:22 -07001311 count = min(remain, maxcnt);
1312
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301313 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1314 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001315 ptr += count;
1316 remain -= count;
1317
1318 if (remain == 0)
1319 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 }
1321 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001322
1323 return ptr - buffer;
1324}
1325
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001326/*
1327 * Copy up to a word (4 bytes) between a scatterlist
1328 * and a temporary bounce buffer when the word lies across
1329 * two pages. The temporary buffer can then be read to/
1330 * written from the FIFO once.
1331 */
1332static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
1333{
1334 struct msmsdcc_pio_data *pio = &host->pio;
1335 unsigned int bytes_avail;
1336
1337 if (host->curr.data->flags & MMC_DATA_READ)
1338 memcpy(pio->sg_miter.addr, pio->bounce_buf,
1339 pio->bounce_buf_len);
1340 else
1341 memcpy(pio->bounce_buf, pio->sg_miter.addr,
1342 pio->bounce_buf_len);
1343
1344 while (pio->bounce_buf_len != 4) {
1345 if (!sg_miter_next(&pio->sg_miter))
1346 break;
1347 bytes_avail = min_t(unsigned int, pio->sg_miter.length,
1348 4 - pio->bounce_buf_len);
1349 if (host->curr.data->flags & MMC_DATA_READ)
1350 memcpy(pio->sg_miter.addr,
1351 &pio->bounce_buf[pio->bounce_buf_len],
1352 bytes_avail);
1353 else
1354 memcpy(&pio->bounce_buf[pio->bounce_buf_len],
1355 pio->sg_miter.addr, bytes_avail);
1356
1357 pio->sg_miter.consumed = bytes_avail;
1358 pio->bounce_buf_len += bytes_avail;
1359 }
1360}
1361
1362/*
1363 * Use sg_miter_next to return as many 4-byte aligned
1364 * chunks as possible, using a temporary 4 byte buffer
1365 * for alignment if necessary
1366 */
1367static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
1368{
1369 struct msmsdcc_pio_data *pio = &host->pio;
1370 unsigned int length, rlength;
1371 char *buffer;
1372
1373 if (!sg_miter_next(&pio->sg_miter))
1374 return 0;
1375
1376 buffer = pio->sg_miter.addr;
1377 length = pio->sg_miter.length;
1378
1379 if (length < host->curr.xfer_remain) {
1380 rlength = round_down(length, 4);
1381 if (rlength) {
1382 /*
1383 * We have a 4-byte aligned chunk.
1384 * The rounding will be reflected by
1385 * a call to msmsdcc_sg_consumed
1386 */
1387 length = rlength;
1388 goto sg_next_end;
1389 }
1390 /*
1391 * We have a length less than 4 bytes. Check to
1392 * see if more buffer is available, and combine
1393 * to make 4 bytes if possible.
1394 */
1395 pio->bounce_buf_len = length;
1396 memset(pio->bounce_buf, 0, 4);
1397
1398 /*
1399 * On a read, get 4 bytes from FIFO, and distribute
1400 * (4-bouce_buf_len) bytes into consecutive
1401 * sgl buffers when msmsdcc_sg_consumed is called
1402 */
1403 if (host->curr.data->flags & MMC_DATA_READ) {
1404 buffer = pio->bounce_buf;
1405 length = 4;
1406 goto sg_next_end;
1407 } else {
1408 _msmsdcc_sg_consume_word(host);
1409 buffer = pio->bounce_buf;
1410 length = pio->bounce_buf_len;
1411 }
1412 }
1413
1414sg_next_end:
1415 *buf = buffer;
1416 *len = length;
1417 return 1;
1418}
1419
1420/*
1421 * Update sg_miter.consumed based on how many bytes were
1422 * consumed. If the bounce buffer was used to read from FIFO,
1423 * redistribute into sgls.
1424 */
1425static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
1426 unsigned int length)
1427{
1428 struct msmsdcc_pio_data *pio = &host->pio;
1429
1430 if (host->curr.data->flags & MMC_DATA_READ) {
1431 if (length > pio->sg_miter.consumed)
1432 /*
1433 * consumed 4 bytes, but sgl
1434 * describes < 4 bytes
1435 */
1436 _msmsdcc_sg_consume_word(host);
1437 else
1438 pio->sg_miter.consumed = length;
1439 } else
1440 if (length < pio->sg_miter.consumed)
1441 pio->sg_miter.consumed = length;
1442}
1443
1444static void msmsdcc_sg_start(struct msmsdcc_host *host)
1445{
1446 unsigned int sg_miter_flags = SG_MITER_ATOMIC;
1447
1448 host->pio.bounce_buf_len = 0;
1449
1450 if (host->curr.data->flags & MMC_DATA_READ)
1451 sg_miter_flags |= SG_MITER_TO_SG;
1452 else
1453 sg_miter_flags |= SG_MITER_FROM_SG;
1454
1455 sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
1456 host->curr.data->sg_len, sg_miter_flags);
1457}
1458
1459static void msmsdcc_sg_stop(struct msmsdcc_host *host)
1460{
1461 sg_miter_stop(&host->pio.sg_miter);
1462}
1463
San Mehat1cd22962010-02-03 12:59:29 -08001464static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001465msmsdcc_pio_irq(int irq, void *dev_id)
1466{
1467 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001469 uint32_t status;
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001470 unsigned long flags;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001471 unsigned int remain;
1472 char *buffer;
San Mehat9d2bd732009-09-22 16:44:22 -07001473
Murali Palnati36448a42011-09-02 15:06:18 +05301474 spin_lock(&host->lock);
1475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301479 (MCI_IRQ_PIO)) == 0) {
1480 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301482 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483#if IRQ_DEBUG
1484 msmsdcc_print_status(host, "irq1-r", status);
1485#endif
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001486 local_irq_save(flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001488 do {
1489 unsigned int len;
San Mehat9d2bd732009-09-22 16:44:22 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1492 | MCI_RXDATAAVLBL)))
1493 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001494
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001495 if (!msmsdcc_sg_next(host, &buffer, &remain))
1496 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497
San Mehat9d2bd732009-09-22 16:44:22 -07001498 len = 0;
1499 if (status & MCI_RXACTIVE)
1500 len = msmsdcc_pio_read(host, buffer, remain);
1501 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 len = msmsdcc_pio_write(host, buffer, remain);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001503
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301504 /* len might have aligned to 32bits above */
1505 if (len > remain)
1506 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001507
San Mehat9d2bd732009-09-22 16:44:22 -07001508 host->curr.xfer_remain -= len;
1509 host->curr.data_xfered += len;
1510 remain -= len;
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001511 msmsdcc_sg_consumed(host, len);
San Mehat9d2bd732009-09-22 16:44:22 -07001512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 if (remain) /* Done with this page? */
1514 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001517 } while (1);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001518
Oluwafemi Adeyemiecfa3df2012-02-28 18:08:54 -08001519 msmsdcc_sg_stop(host);
Oluwafemi Adeyemia981c5c2012-02-09 20:02:00 -08001520 local_irq_restore(flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1523 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1524 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1525 host->base + MMCIMASK0);
1526 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301527 /*
1528 * back to back write to MASK0 register don't need
1529 * synchronization delay.
1530 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1532 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1533 }
1534 mb();
1535 } else if (!host->curr.xfer_remain) {
1536 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1537 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1538 mb();
1539 }
San Mehat9d2bd732009-09-22 16:44:22 -07001540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001542
1543 return IRQ_HANDLED;
1544}
1545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546static void
1547msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1548
1549static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1550 struct mmc_data *data)
1551{
1552 u32 loop_cnt = 0;
1553
1554 /*
1555 * For read commands with data less than fifo size, it is possible to
1556 * get DATAEND first and RXDATA_AVAIL might be set later because of
1557 * synchronization delay through the asynchronous RX FIFO. Thus, for
1558 * such cases, even after DATAEND interrupt is received software
1559 * should poll for RXDATA_AVAIL until the requested data is read out
1560 * of FIFO. This change is needed to get around this abnormal but
1561 * sometimes expected behavior of SDCC3 controller.
1562 *
1563 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1564 * after the data is loaded into RX FIFO. This would amount to less
1565 * than a microsecond and thus looping for 1000 times is good enough
1566 * for that delay.
1567 */
1568 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1569 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1570 spin_unlock(&host->lock);
1571 msmsdcc_pio_irq(1, host);
1572 spin_lock(&host->lock);
1573 }
1574 }
1575 if (loop_cnt == 1000) {
1576 pr_info("%s: Timed out while polling for Rx Data\n",
1577 mmc_hostname(host->mmc));
1578 data->error = -ETIMEDOUT;
1579 msmsdcc_reset_and_restore(host);
1580 }
1581}
1582
San Mehat9d2bd732009-09-22 16:44:22 -07001583static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1584{
1585 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001586
1587 host->curr.cmd = NULL;
subhashj8046ae12012-05-02 12:14:52 +05301588 if (mmc_resp_type(cmd))
1589 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1590 /*
1591 * Read rest of the response registers only if
1592 * long response is expected for this command
1593 */
1594 if (mmc_resp_type(cmd) & MMC_RSP_136) {
1595 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1596 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1597 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
1598 }
San Mehat9d2bd732009-09-22 16:44:22 -07001599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301601 pr_debug("%s: CMD%d: Command timeout\n",
1602 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001603 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05301605 !host->tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301606 pr_err("%s: CMD%d: Command CRC error\n",
1607 mmc_hostname(host->mmc), cmd->opcode);
1608 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001609 cmd->error = -EILSEQ;
1610 }
1611
1612 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 if (host->curr.data && host->dma.sg &&
1614 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001615 msm_dmov_stop_cmd(host->dma.channel,
1616 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 else if (host->curr.data && host->sps.sg &&
1618 host->is_sps_mode){
1619 /* Stop current SPS transfer */
1620 msmsdcc_sps_exit_curr_xfer(host);
1621 }
San Mehat9d2bd732009-09-22 16:44:22 -07001622 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301623 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001624 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301625 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301626 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301627 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301628 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301630 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301632 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301633 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301634 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05301635 host->curr.wait_for_auto_prog_done = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001636 if (host->dummy_52_needed)
1637 host->dummy_52_needed = 0;
1638 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301640 msmsdcc_request_end(host, cmd->mrq);
1641 }
1642 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301643 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1644 if (cmd->data->flags & MMC_DATA_READ)
1645 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1646 else
1647 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301648 } else if (cmd->data) {
1649 if (!(cmd->data->flags & MMC_DATA_READ))
1650 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001651 }
1652}
1653
San Mehat9d2bd732009-09-22 16:44:22 -07001654static irqreturn_t
1655msmsdcc_irq(int irq, void *dev_id)
1656{
1657 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001658 u32 status;
1659 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001661
1662 spin_lock(&host->lock);
1663
1664 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 struct mmc_command *cmd;
1666 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 if (timer) {
1669 timer = 0;
1670 msmsdcc_delay(host);
1671 }
San Mehat865c8062009-11-13 13:42:06 -08001672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673 if (!host->clks_on) {
1674 pr_debug("%s: %s: SDIO async irq received\n",
1675 mmc_hostname(host->mmc), __func__);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301676
1677 /*
1678 * Only async interrupt can come when clocks are off,
1679 * disable further interrupts and enable them when
1680 * clocks are on.
1681 */
1682 if (!host->sdcc_irq_disabled) {
1683 disable_irq_nosync(irq);
1684 host->sdcc_irq_disabled = 1;
1685 }
1686
1687 /*
1688 * If mmc_card_wake_sdio_irq() is set, mmc core layer
1689 * will take care of signaling sdio irq during
1690 * mmc_sdio_resume().
1691 */
1692 if (host->sdcc_suspended)
1693 /*
1694 * This is a wakeup interrupt so hold wakelock
1695 * until SDCC resume is handled.
1696 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 wake_lock(&host->sdio_wlock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05301698 else
1699 mmc_signal_sdio_irq(host->mmc);
1700 ret = 1;
1701 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 }
1703
1704 status = readl_relaxed(host->base + MMCISTATUS);
1705
1706 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1707 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001708 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710#if IRQ_DEBUG
1711 msmsdcc_print_status(host, "irq0-r", status);
1712#endif
1713 status &= readl_relaxed(host->base + MMCIMASK0);
1714 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301715 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301716 if (host->clk_rate <=
1717 msmsdcc_get_min_sup_clk_rate(host))
Subhash Jadavanidd432952012-03-28 11:25:56 +05301718 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719#if IRQ_DEBUG
1720 msmsdcc_print_status(host, "irq0-p", status);
1721#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 if (status & MCI_SDIOINTROPE) {
1724 if (host->sdcc_suspending)
1725 wake_lock(&host->sdio_suspend_wlock);
1726 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001727 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001728 data = host->curr.data;
1729
1730 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1732 MCI_CMDTIMEOUT)) {
1733 if (status & MCI_CMDTIMEOUT)
1734 pr_debug("%s: dummy CMD52 timeout\n",
1735 mmc_hostname(host->mmc));
1736 if (status & MCI_CMDCRCFAIL)
1737 pr_debug("%s: dummy CMD52 CRC failed\n",
1738 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001739 host->dummy_52_sent = 0;
1740 host->dummy_52_needed = 0;
1741 if (data) {
1742 msmsdcc_stop_data(host);
1743 msmsdcc_request_end(host, data->mrq);
1744 }
1745 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 spin_unlock(&host->lock);
1747 return IRQ_HANDLED;
1748 }
1749 break;
1750 }
1751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 /*
1753 * Check for proper command response
1754 */
1755 cmd = host->curr.cmd;
1756 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1757 MCI_CMDTIMEOUT | MCI_PROGDONE |
1758 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1759 msmsdcc_do_cmdirq(host, status);
1760 }
1761
Sathish Ambley081d7842011-11-29 11:19:41 -08001762 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763 /* Check for data errors */
1764 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1765 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1766 msmsdcc_data_err(host, data, status);
1767 host->curr.data_xfered = 0;
1768 if (host->dma.sg && host->is_dma_mode)
1769 msm_dmov_stop_cmd(host->dma.channel,
1770 &host->dma.hdr, 0);
1771 else if (host->sps.sg && host->is_sps_mode) {
1772 /* Stop current SPS transfer */
1773 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301774 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 msmsdcc_reset_and_restore(host);
1776 if (host->curr.data)
1777 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301778 if (!data->stop || (host->curr.mrq->sbc
1779 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 timer |=
1781 msmsdcc_request_end(host,
1782 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301783 else if ((host->curr.mrq->sbc
1784 && data->error) ||
1785 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 msmsdcc_start_command(host,
1787 data->stop,
1788 0);
1789 timer = 1;
1790 }
1791 }
1792 }
1793
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301794 /* Check for prog done */
1795 if (host->curr.wait_for_auto_prog_done &&
1796 (status & MCI_PROGDONE))
1797 host->curr.got_auto_prog_done = 1;
1798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 /* Check for data done */
1800 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1801 host->curr.got_dataend = 1;
1802
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301803 if (host->curr.got_dataend &&
1804 (!host->curr.wait_for_auto_prog_done ||
1805 (host->curr.wait_for_auto_prog_done &&
1806 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 /*
1808 * If DMA is still in progress, we complete
1809 * via the completion handler
1810 */
1811 if (!host->dma.busy && !host->sps.busy) {
1812 /*
1813 * There appears to be an issue in the
1814 * controller where if you request a
1815 * small block transfer (< fifo size),
1816 * you may get your DATAEND/DATABLKEND
1817 * irq without the PIO data irq.
1818 *
1819 * Check to see if theres still data
1820 * to be read, and simulate a PIO irq.
1821 */
1822 if (data->flags & MMC_DATA_READ)
1823 msmsdcc_wait_for_rxdata(host,
1824 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 if (!data->error) {
1826 host->curr.data_xfered =
1827 host->curr.xfer_size;
1828 host->curr.xfer_remain -=
1829 host->curr.xfer_size;
1830 }
1831
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001832 if (!host->dummy_52_needed) {
1833 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301834 if (!data->stop ||
1835 (host->curr.mrq->sbc
1836 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001837 msmsdcc_request_end(
1838 host,
1839 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301840 else if ((host->curr.mrq->sbc
1841 && data->error) ||
1842 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001843 msmsdcc_start_command(
1844 host,
1845 data->stop, 0);
1846 timer = 1;
1847 }
1848 } else {
1849 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001851 &dummy52cmd,
1852 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 }
1854 }
1855 }
1856 }
1857
San Mehat9d2bd732009-09-22 16:44:22 -07001858 ret = 1;
1859 } while (status);
1860
1861 spin_unlock(&host->lock);
1862
San Mehat9d2bd732009-09-22 16:44:22 -07001863 return IRQ_RETVAL(ret);
1864}
1865
1866static void
Asutosh Dasaccacd42012-03-08 14:33:17 +05301867msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1868 bool is_first_request)
1869{
1870 struct msmsdcc_host *host = mmc_priv(mmc);
1871 struct mmc_data *data = mrq->data;
1872 int rc = 0;
1873
1874 if (unlikely(!data)) {
1875 pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
1876 __func__);
1877 return;
1878 }
1879 if (unlikely(data->host_cookie)) {
1880 /* Very wrong */
1881 data->host_cookie = 0;
1882 pr_err("%s: %s Request reposted for prepare\n",
1883 mmc_hostname(mmc), __func__);
1884 return;
1885 }
1886
1887 if (!msmsdcc_is_dma_possible(host, data))
1888 return;
1889
1890 rc = msmsdcc_prep_xfer(host, data);
1891 if (unlikely(rc < 0)) {
1892 data->host_cookie = 0;
1893 return;
1894 }
1895
1896 data->host_cookie = 1;
1897}
1898
1899static void
1900msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
1901{
1902 struct msmsdcc_host *host = mmc_priv(mmc);
1903 unsigned int dir;
1904 struct mmc_data *data = mrq->data;
1905
1906 if (unlikely(!data)) {
1907 pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
1908 __func__);
1909 return;
1910 }
1911 if (data->flags & MMC_DATA_READ)
1912 dir = DMA_FROM_DEVICE;
1913 else
1914 dir = DMA_TO_DEVICE;
1915
1916 if (data->host_cookie)
1917 dma_unmap_sg(mmc_dev(host->mmc), data->sg,
1918 data->sg_len, dir);
1919
1920 data->host_cookie = 0;
1921}
1922
1923static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1925{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301926 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301928 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301929 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1930 else
1931 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932 } else {
1933 msmsdcc_start_command(host, mrq->cmd, 0);
1934 }
1935}
1936
1937static void
San Mehat9d2bd732009-09-22 16:44:22 -07001938msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1939{
1940 struct msmsdcc_host *host = mmc_priv(mmc);
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301941 unsigned long flags, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943 /*
1944 * Get the SDIO AL client out of LPM.
1945 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001946 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001947 if (host->plat->is_sdio_al_client)
1948 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001949
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301950 /* check if sps pipe reset is pending? */
1951 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1952 msmsdcc_sps_pipes_reset_and_restore(host);
1953 host->sps.pipe_reset_pending = false;
1954 }
1955
San Mehat9d2bd732009-09-22 16:44:22 -07001956 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001957
1958 if (host->eject) {
1959 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1960 mrq->cmd->error = 0;
1961 mrq->data->bytes_xfered = mrq->data->blksz *
1962 mrq->data->blocks;
1963 } else
1964 mrq->cmd->error = -ENOMEDIUM;
1965
1966 spin_unlock_irqrestore(&host->lock, flags);
1967 mmc_request_done(mmc, mrq);
1968 return;
1969 }
1970
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301971 /*
subhashjf181c292012-05-02 13:07:40 +05301972 * Don't start the request if SDCC is not in proper state to handle it
1973 */
1974 if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
1975 WARN(1, "%s: %s: SDCC is in bad state. don't process"
1976 " new request (CMD%d)\n", mmc_hostname(host->mmc),
1977 __func__, mrq->cmd->opcode);
1978 msmsdcc_dump_sdcc_state(host);
1979 mrq->cmd->error = -EIO;
1980 if (mrq->data) {
1981 mrq->data->error = -EIO;
1982 mrq->data->bytes_xfered = 0;
1983 }
1984 spin_unlock_irqrestore(&host->lock, flags);
1985 mmc_request_done(mmc, mrq);
1986 return;
1987 }
1988
1989 WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
1990 " other request (CMD%d) is in progress\n",
1991 mmc_hostname(host->mmc), __func__,
1992 mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
1993
1994 /*
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05301995 * Set timeout value to 10 secs (or more in case of buggy cards)
1996 */
1997 if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
1998 timeout = 20000;
1999 else
2000 timeout = MSM_MMC_REQ_TIMEOUT;
2001 /*
2002 * Kick the software request timeout timer here with the timeout
2003 * value identified above
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302004 */
2005 mod_timer(&host->req_tout_timer,
Pratibhasagar V4ecbe652012-05-07 15:45:07 +05302006 (jiffies + msecs_to_jiffies(timeout)));
San Mehat9d2bd732009-09-22 16:44:22 -07002007
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302008 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302009 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302010 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
2011 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05302012 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302014 else
2015 /*
2016 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
2017 * write operations using CMD53 and CMD54.
2018 * Setting this bit with CMD53 would
2019 * automatically triggers PROG_DONE interrupt
2020 * without the need of sending dummy CMD52.
2021 */
2022 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05302023 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
2024 host->sdcc_version) {
2025 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 }
San Mehat9d2bd732009-09-22 16:44:22 -07002027 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05302028
Pratibhasagar V00b94332011-10-18 14:57:27 +05302029 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302030 mrq->sbc->mrq = mrq;
2031 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302032 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302033 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05302034 msmsdcc_start_command(host, mrq->sbc, 0);
2035 } else {
2036 msmsdcc_request_start(host, mrq);
2037 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05302038 } else {
2039 msmsdcc_request_start(host, mrq);
2040 }
2041
San Mehat9d2bd732009-09-22 16:44:22 -07002042 spin_unlock_irqrestore(&host->lock, flags);
2043}
2044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
2046 int min_uV, int max_uV)
2047{
2048 int rc = 0;
2049
2050 if (vreg->set_voltage_sup) {
2051 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
2052 if (rc) {
2053 pr_err("%s: regulator_set_voltage(%s) failed."
2054 " min_uV=%d, max_uV=%d, rc=%d\n",
2055 __func__, vreg->name, min_uV, max_uV, rc);
2056 }
2057 }
2058
2059 return rc;
2060}
2061
2062static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
2063 int uA_load)
2064{
2065 int rc = 0;
2066
Krishna Kondafea60182011-11-01 16:01:34 -07002067 /* regulators that do not support regulator_set_voltage also
2068 do not support regulator_set_optimum_mode */
2069 if (vreg->set_voltage_sup) {
2070 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
2071 if (rc < 0)
2072 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
2073 "uA_load=%d) failed. rc=%d\n", __func__,
2074 vreg->name, uA_load, rc);
2075 else
2076 /* regulator_set_optimum_mode() can return non zero
2077 * value even for success case.
2078 */
2079 rc = 0;
2080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081
2082 return rc;
2083}
2084
2085static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
2086 struct device *dev)
2087{
2088 int rc = 0;
2089
2090 /* check if regulator is already initialized? */
2091 if (vreg->reg)
2092 goto out;
2093
2094 /* Get the regulator handle */
2095 vreg->reg = regulator_get(dev, vreg->name);
2096 if (IS_ERR(vreg->reg)) {
2097 rc = PTR_ERR(vreg->reg);
2098 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
2099 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002100 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08002102
2103 if (regulator_count_voltages(vreg->reg) > 0)
2104 vreg->set_voltage_sup = 1;
2105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106out:
2107 return rc;
2108}
2109
2110static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
2111{
2112 if (vreg->reg)
2113 regulator_put(vreg->reg);
2114}
2115
2116/* This init function should be called only once for each SDCC slot */
2117static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
2118{
2119 int rc = 0;
2120 struct msm_mmc_slot_reg_data *curr_slot;
2121 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2122 struct device *dev = mmc_dev(host->mmc);
2123
2124 curr_slot = host->plat->vreg_data;
2125 if (!curr_slot)
2126 goto out;
2127
2128 curr_vdd_reg = curr_slot->vdd_data;
2129 curr_vccq_reg = curr_slot->vccq_data;
2130 curr_vddp_reg = curr_slot->vddp_data;
2131
2132 if (is_init) {
2133 /*
2134 * Get the regulator handle from voltage regulator framework
2135 * and then try to set the voltage level for the regulator
2136 */
2137 if (curr_vdd_reg) {
2138 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
2139 if (rc)
2140 goto out;
2141 }
2142 if (curr_vccq_reg) {
2143 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
2144 if (rc)
2145 goto vdd_reg_deinit;
2146 }
2147 if (curr_vddp_reg) {
2148 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
2149 if (rc)
2150 goto vccq_reg_deinit;
2151 }
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002152 rc = msmsdcc_vreg_reset(host);
2153 if (rc)
2154 pr_err("msmsdcc.%d vreg reset failed (%d)\n",
2155 host->pdev_id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 goto out;
2157 } else {
2158 /* Deregister all regulators from regulator framework */
2159 goto vddp_reg_deinit;
2160 }
2161vddp_reg_deinit:
2162 if (curr_vddp_reg)
2163 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
2164vccq_reg_deinit:
2165 if (curr_vccq_reg)
2166 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
2167vdd_reg_deinit:
2168 if (curr_vdd_reg)
2169 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
2170out:
2171 return rc;
2172}
2173
2174static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
2175{
2176 int rc = 0;
2177
Subhash Jadavanicc922692011-08-01 23:05:01 +05302178 /* Put regulator in HPM (high power mode) */
2179 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
2180 if (rc < 0)
2181 goto out;
2182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002183 if (!vreg->is_enabled) {
2184 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302185 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
2186 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187 if (rc)
2188 goto out;
2189
2190 rc = regulator_enable(vreg->reg);
2191 if (rc) {
2192 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
2193 __func__, vreg->name, rc);
2194 goto out;
2195 }
2196 vreg->is_enabled = true;
2197 }
2198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199out:
2200 return rc;
2201}
2202
2203static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
2204{
2205 int rc = 0;
2206
2207 /* Never disable regulator marked as always_on */
2208 if (vreg->is_enabled && !vreg->always_on) {
2209 rc = regulator_disable(vreg->reg);
2210 if (rc) {
2211 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
2212 __func__, vreg->name, rc);
2213 goto out;
2214 }
2215 vreg->is_enabled = false;
2216
2217 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
2218 if (rc < 0)
2219 goto out;
2220
2221 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302222 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 if (rc)
2224 goto out;
2225 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
2226 /* Put always_on regulator in LPM (low power mode) */
2227 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
2228 if (rc < 0)
2229 goto out;
2230 }
2231out:
2232 return rc;
2233}
2234
2235static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
2236{
2237 int rc = 0, i;
2238 struct msm_mmc_slot_reg_data *curr_slot;
2239 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
2240 struct msm_mmc_reg_data *vreg_table[3];
2241
2242 curr_slot = host->plat->vreg_data;
2243 if (!curr_slot)
2244 goto out;
2245
2246 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
2247 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
2248 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
2249
2250 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
2251 if (vreg_table[i]) {
2252 if (enable)
2253 rc = msmsdcc_vreg_enable(vreg_table[i]);
2254 else
2255 rc = msmsdcc_vreg_disable(vreg_table[i]);
2256 if (rc)
2257 goto out;
2258 }
2259 }
2260out:
2261 return rc;
2262}
2263
Oluwafemi Adeyemi4ea731c2012-03-07 14:47:36 -08002264/*
2265 * Reset vreg by ensuring it is off during probe. A call
2266 * to enable vreg is needed to balance disable vreg
2267 */
2268static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
2269{
2270 int rc;
2271
2272 rc = msmsdcc_setup_vreg(host, 1);
2273 if (rc)
2274 return rc;
2275 rc = msmsdcc_setup_vreg(host, 0);
2276 return rc;
2277}
2278
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302279static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280{
2281 int rc = 0;
2282
2283 if (host->plat->vreg_data) {
2284 struct msm_mmc_reg_data *vddp_reg =
2285 host->plat->vreg_data->vddp_data;
2286
2287 if (vddp_reg && vddp_reg->is_enabled)
2288 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
2289 }
2290
2291 return rc;
2292}
2293
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302294static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
2295{
2296 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2297 int rc = 0;
2298
2299 if (curr_slot && curr_slot->vddp_data) {
2300 rc = msmsdcc_set_vddp_level(host,
2301 curr_slot->vddp_data->low_vol_level);
2302
2303 if (rc)
2304 pr_err("%s: %s: failed to change vddp level to %d",
2305 mmc_hostname(host->mmc), __func__,
2306 curr_slot->vddp_data->low_vol_level);
2307 }
2308
2309 return rc;
2310}
2311
2312static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
2313{
2314 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2315 int rc = 0;
2316
2317 if (curr_slot && curr_slot->vddp_data) {
2318 rc = msmsdcc_set_vddp_level(host,
2319 curr_slot->vddp_data->high_vol_level);
2320
2321 if (rc)
2322 pr_err("%s: %s: failed to change vddp level to %d",
2323 mmc_hostname(host->mmc), __func__,
2324 curr_slot->vddp_data->high_vol_level);
2325 }
2326
2327 return rc;
2328}
2329
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302330static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
2331{
2332 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
2333 int rc = 0;
2334
2335 if (curr_slot && curr_slot->vccq_data) {
2336 rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
2337 level, level);
2338 if (rc)
2339 pr_err("%s: %s: failed to change vccq level to %d",
2340 mmc_hostname(host->mmc), __func__, level);
2341 }
2342
2343 return rc;
2344}
2345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2347{
2348 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2349 return 1;
2350 return 0;
2351}
2352
Asutosh Dasf5298c32012-04-03 14:51:47 +05302353/*
2354 * Any function calling msmsdcc_setup_clocks must
2355 * acquire clk_mutex. May sleep.
2356 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2358{
2359 if (enable) {
2360 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302361 clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302363 clk_prepare_enable(host->pclk);
2364 clk_prepare_enable(host->clk);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302365 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302366 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367 } else {
Subhash Jadavanidd432952012-03-28 11:25:56 +05302368 mb();
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302369 msmsdcc_delay(host);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302370 clk_disable_unprepare(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302372 clk_disable_unprepare(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002373 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05302374 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 }
2376}
2377
2378static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2379 unsigned int req_clk)
2380{
2381 unsigned int sel_clk = -1;
2382
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302383 if (req_clk < msmsdcc_get_min_sup_clk_rate(host)) {
2384 sel_clk = msmsdcc_get_min_sup_clk_rate(host);
2385 goto out;
2386 }
2387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2389 unsigned char cnt;
2390
2391 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2392 if (host->plat->sup_clk_table[cnt] > req_clk)
2393 break;
2394 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2395 sel_clk = host->plat->sup_clk_table[cnt];
2396 break;
2397 } else
2398 sel_clk = host->plat->sup_clk_table[cnt];
2399 }
2400 } else {
2401 if ((req_clk < host->plat->msmsdcc_fmax) &&
2402 (req_clk > host->plat->msmsdcc_fmid))
2403 sel_clk = host->plat->msmsdcc_fmid;
2404 else
2405 sel_clk = req_clk;
2406 }
2407
Subhash Jadavani327f4be2012-03-25 00:44:29 +05302408out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 return sel_clk;
2410}
2411
2412static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2413 struct msmsdcc_host *host)
2414{
2415 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2416 return host->plat->sup_clk_table[0];
2417 else
2418 return host->plat->msmsdcc_fmin;
2419}
2420
2421static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2422 struct msmsdcc_host *host)
2423{
2424 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2425 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2426 else
2427 return host->plat->msmsdcc_fmax;
2428}
2429
2430static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302431{
2432 struct msm_mmc_gpio_data *curr;
2433 int i, rc = 0;
2434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302436 for (i = 0; i < curr->size; i++) {
2437 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 if (curr->gpio[i].is_always_on &&
2439 curr->gpio[i].is_enabled)
2440 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302441 rc = gpio_request(curr->gpio[i].no,
2442 curr->gpio[i].name);
2443 if (rc) {
2444 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2445 mmc_hostname(host->mmc),
2446 curr->gpio[i].no,
2447 curr->gpio[i].name, rc);
2448 goto free_gpios;
2449 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302451 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452 if (curr->gpio[i].is_always_on)
2453 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302454 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302456 }
2457 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302459
2460free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302462 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 curr->gpio[i].is_enabled = false;
2464 }
2465out:
2466 return rc;
2467}
2468
2469static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2470{
2471 struct msm_mmc_pad_data *curr;
2472 int i;
2473
2474 curr = host->plat->pin_data->pad_data;
2475 for (i = 0; i < curr->drv->size; i++) {
2476 if (enable)
2477 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2478 curr->drv->on[i].val);
2479 else
2480 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2481 curr->drv->off[i].val);
2482 }
2483
2484 for (i = 0; i < curr->pull->size; i++) {
2485 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002486 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 curr->pull->on[i].val);
2488 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002489 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 curr->pull->off[i].val);
2491 }
2492
2493 return 0;
2494}
2495
2496static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2497{
2498 int rc = 0;
2499
2500 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2501 return 0;
2502
2503 if (host->plat->pin_data->is_gpio)
2504 rc = msmsdcc_setup_gpio(host, enable);
2505 else
2506 rc = msmsdcc_setup_pad(host, enable);
2507
2508 if (!rc)
2509 host->plat->pin_data->cfg_sts = enable;
2510
2511 return rc;
2512}
2513
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302514static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
2515 unsigned mode)
2516{
2517 int ret = 0;
2518 unsigned int pin = host->plat->mpm_sdiowakeup_int;
2519
2520 if (!pin)
2521 return 0;
2522
2523 switch (mode) {
2524 case SDC_DAT1_DISABLE:
2525 ret = msm_mpm_enable_pin(pin, 0);
2526 break;
2527 case SDC_DAT1_ENABLE:
2528 ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
2529 ret = msm_mpm_enable_pin(pin, 1);
2530 break;
2531 case SDC_DAT1_ENWAKE:
2532 ret = msm_mpm_set_pin_wake(pin, 1);
2533 break;
2534 case SDC_DAT1_DISWAKE:
2535 ret = msm_mpm_set_pin_wake(pin, 0);
2536 break;
2537 default:
2538 ret = -EINVAL;
2539 break;
2540 }
2541
2542 return ret;
2543}
2544
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302545static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
2546{
2547 u32 pwr = 0;
2548 int ret = 0;
2549 struct mmc_host *mmc = host->mmc;
2550
2551 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
2552 ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
2553 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2554 ret = msmsdcc_setup_vreg(host, !!ios->vdd);
2555
2556 if (ret) {
2557 pr_err("%s: Failed to setup voltage regulators\n",
2558 mmc_hostname(host->mmc));
2559 goto out;
2560 }
2561
2562 switch (ios->power_mode) {
2563 case MMC_POWER_OFF:
2564 pwr = MCI_PWR_OFF;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302565 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302566 /*
2567 * As VDD pad rail is always on, set low voltage for VDD
2568 * pad rail when slot is unused (when card is not present
2569 * or during system suspend).
2570 */
2571 msmsdcc_set_vddp_low_vol(host);
2572 msmsdcc_setup_pins(host, false);
2573 break;
2574 case MMC_POWER_UP:
2575 /* writing PWR_UP bit is redundant */
2576 pwr = MCI_PWR_UP;
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302577 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302578
2579 msmsdcc_set_vddp_high_vol(host);
2580 msmsdcc_setup_pins(host, true);
2581 break;
2582 case MMC_POWER_ON:
2583 pwr = MCI_PWR_ON;
2584 break;
2585 }
2586
2587out:
2588 return pwr;
2589}
2590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002591static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2592{
2593 unsigned int wakeup_irq;
2594
2595 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2596 host->plat->sdiowakeup_irq :
2597 host->core_irqres->start;
2598
2599 if (!host->irq_wake_enabled) {
2600 enable_irq_wake(wakeup_irq);
2601 host->irq_wake_enabled = true;
2602 }
2603}
2604
2605static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2606{
2607 unsigned int wakeup_irq;
2608
2609 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2610 host->plat->sdiowakeup_irq :
2611 host->core_irqres->start;
2612
2613 if (host->irq_wake_enabled) {
2614 disable_irq_wake(wakeup_irq);
2615 host->irq_wake_enabled = false;
2616 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302617}
2618
San Mehat9d2bd732009-09-22 16:44:22 -07002619static void
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302620msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
2621{
2622 struct mmc_host *mmc = host->mmc;
2623
2624 /*
2625 * SDIO_AL clients has different mechanism of handling LPM through
2626 * sdio_al driver itself. The sdio wakeup interrupt is configured as
2627 * part of that. Here, we are interested only in clients like WLAN.
2628 */
2629 if (!(mmc->card && mmc_card_sdio(mmc->card))
2630 || host->plat->is_sdio_al_client)
2631 goto out;
2632
2633 if (!host->sdcc_suspended) {
2634 /*
2635 * When MSM is not in power collapse and we
2636 * are disabling clocks, enable bit 22 in MASK0
2637 * to handle asynchronous SDIO interrupts.
2638 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302639 if (enable_wakeup_irq) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302640 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCIMASK0);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302641 mb();
2642 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302643 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302644 msmsdcc_sync_reg_wr(host);
2645 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302646 goto out;
2647 } else if (!mmc_card_wake_sdio_irq(mmc)) {
2648 /*
2649 * Wakeup MSM only if SDIO function drivers set
2650 * MMC_PM_WAKE_SDIO_IRQ flag in their suspend call.
2651 */
2652 goto out;
2653 }
2654
2655 if (enable_wakeup_irq) {
2656 if (!host->plat->sdiowakeup_irq) {
2657 /*
2658 * When there is no gpio line that can be configured
2659 * as wakeup interrupt handle it by configuring
2660 * asynchronous sdio interrupts and DAT1 line.
2661 */
2662 writel_relaxed(MCI_SDIOINTMASK,
2663 host->base + MMCIMASK0);
2664 mb();
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302665 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302666 /* configure sdcc core interrupt as wakeup interrupt */
2667 msmsdcc_enable_irq_wake(host);
2668 } else {
2669 /* Let gpio line handle wakeup interrupt */
2670 writel_relaxed(0, host->base + MMCIMASK0);
2671 mb();
2672 if (host->sdio_wakeupirq_disabled) {
2673 host->sdio_wakeupirq_disabled = 0;
2674 /* configure gpio line as wakeup interrupt */
2675 msmsdcc_enable_irq_wake(host);
2676 enable_irq(host->plat->sdiowakeup_irq);
2677 }
2678 }
2679 } else {
2680 if (!host->plat->sdiowakeup_irq) {
2681 /*
2682 * We may not have cleared bit 22 in the interrupt
2683 * handler as the clocks might be off at that time.
2684 */
2685 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302686 msmsdcc_sync_reg_wr(host);
Subhash Jadavanic9b85752012-04-13 11:16:49 +05302687 msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302688 msmsdcc_disable_irq_wake(host);
2689 } else if (!host->sdio_wakeupirq_disabled) {
2690 disable_irq_nosync(host->plat->sdiowakeup_irq);
2691 msmsdcc_disable_irq_wake(host);
2692 host->sdio_wakeupirq_disabled = 1;
2693 }
2694 }
2695out:
2696 return;
2697}
2698
2699static void
San Mehat9d2bd732009-09-22 16:44:22 -07002700msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2701{
2702 struct msmsdcc_host *host = mmc_priv(mmc);
2703 u32 clk = 0, pwr = 0;
2704 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002705 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002707
Sahitya Tummala7a892482011-01-18 11:22:49 +05302708
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302709 /*
2710 * Disable SDCC core interrupt until set_ios is completed.
2711 * This avoids any race conditions with interrupt raised
2712 * when turning on/off the clocks. One possible
2713 * scenario is SDIO operational interrupt while the clock
2714 * is turned off.
Asutosh Dasf5298c32012-04-03 14:51:47 +05302715 * host->lock is being released intermittently below.
2716 * Thus, prevent concurrent access to host.
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302717 */
2718
Asutosh Dasf5298c32012-04-03 14:51:47 +05302719 mutex_lock(&host->clk_mutex);
2720 DBG(host, "ios->clock = %u\n", ios->clock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302721 spin_lock_irqsave(&host->lock, flags);
2722 if (!host->sdcc_irq_disabled) {
2723 spin_unlock_irqrestore(&host->lock, flags);
2724 disable_irq(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002725 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302726 host->sdcc_irq_disabled = 1;
2727 }
2728 spin_unlock_irqrestore(&host->lock, flags);
2729
2730 pwr = msmsdcc_setup_pwr(host, ios);
2731
2732 spin_lock_irqsave(&host->lock, flags);
2733 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302735 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002736 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302737 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738 host->clks_on = 1;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302739 writel_relaxed(host->mci_irqenable,
2740 host->base + MMCIMASK0);
2741 mb();
2742 msmsdcc_cfg_sdio_wakeup(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002743 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002744
2745 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2746 /*
2747 * For DDR50 mode, controller needs clock rate to be
2748 * double than what is required on the SD card CLK pin.
2749 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302750 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751 /*
2752 * Make sure that we don't double the clock if
2753 * doubled clock rate is already set
2754 */
2755 if (!host->ddr_doubled_clk_rate ||
2756 (host->ddr_doubled_clk_rate &&
2757 (host->ddr_doubled_clk_rate != ios->clock))) {
2758 host->ddr_doubled_clk_rate =
2759 msmsdcc_get_sup_clk_rate(
2760 host, (ios->clock * 2));
2761 clock = host->ddr_doubled_clk_rate;
2762 }
2763 } else {
2764 host->ddr_doubled_clk_rate = 0;
2765 }
2766
2767 if (clock != host->clk_rate) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05302768 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 rc = clk_set_rate(host->clk, clock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302770 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302772 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773 mmc_hostname(mmc), clock);
2774 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302775 host->reg_write_delay =
2776 (1 + ((3 * USEC_PER_SEC) /
2777 (host->clk_rate ? host->clk_rate :
2778 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 }
2780 /*
2781 * give atleast 2 MCLK cycles delay for clocks
2782 * and SDCC core to stabilize
2783 */
Subhash Jadavanidd432952012-03-28 11:25:56 +05302784 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002786 clk |= MCI_CLK_ENABLE;
2787 }
2788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002789 if (ios->bus_width == MMC_BUS_WIDTH_8)
2790 clk |= MCI_CLK_WIDEBUS_8;
2791 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2792 clk |= MCI_CLK_WIDEBUS_4;
2793 else
2794 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796 if (msmsdcc_is_pwrsave(host))
2797 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801 host->tuning_needed = 0;
2802 /*
2803 * Select the controller timing mode according
2804 * to current bus speed mode
2805 */
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302806 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2807 (ios->timing == MMC_TIMING_MMC_HS200)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 clk |= (4 << 14);
2809 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302810 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811 clk |= (3 << 14);
2812 } else {
2813 clk |= (2 << 14); /* feedback clock */
2814 }
2815
2816 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2817 clk |= (2 << 23);
2818
Subhash Jadavani00083572012-02-15 16:18:01 +05302819 /* Clear IO_PAD_PWR_SWITCH while powering off the card */
2820 if (!ios->vdd)
2821 host->io_pad_pwr_switch = 0;
2822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 if (host->io_pad_pwr_switch)
2824 clk |= IO_PAD_PWR_SWITCH;
2825
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302826 /* Don't write into registers if clocks are disabled */
2827 if (host->clks_on) {
2828 if (readl_relaxed(host->base + MMCICLOCK) != clk) {
2829 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302830 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302832 if (readl_relaxed(host->base + MMCIPOWER) != pwr) {
2833 host->pwr = pwr;
2834 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302835 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002837 }
2838
2839 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302840 msmsdcc_cfg_sdio_wakeup(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302841 spin_unlock_irqrestore(&host->lock, flags);
2842 /*
2843 * May get a wake-up interrupt the instant we disable the
2844 * clocks. This would disable the wake-up interrupt.
2845 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302847 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848 host->clks_on = 0;
2849 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302850
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302851 if (host->tuning_in_progress)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302852 WARN(!host->clks_on,
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05302853 "tuning_in_progress but SDCC clocks are OFF\n");
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302854
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302855 /* Let interrupts be disabled if the host is powered off */
2856 if (ios->power_mode != MMC_POWER_OFF && host->sdcc_irq_disabled) {
2857 enable_irq(host->core_irqres->start);
2858 host->sdcc_irq_disabled = 0;
2859 }
2860
San Mehat4adbbcc2009-11-08 13:00:37 -08002861 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05302862 mutex_unlock(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07002863}
2864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2866{
2867 struct msmsdcc_host *host = mmc_priv(mmc);
2868 u32 clk;
2869
2870 clk = readl_relaxed(host->base + MMCICLOCK);
2871 pr_debug("Changing to pwr_save=%d", pwrsave);
2872 if (pwrsave && msmsdcc_is_pwrsave(host))
2873 clk |= MCI_CLK_PWRSAVE;
2874 else
2875 clk &= ~MCI_CLK_PWRSAVE;
2876 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05302877 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002878
2879 return 0;
2880}
2881
2882static int msmsdcc_get_ro(struct mmc_host *mmc)
2883{
2884 int status = -ENOSYS;
2885 struct msmsdcc_host *host = mmc_priv(mmc);
2886
2887 if (host->plat->wpswitch) {
2888 status = host->plat->wpswitch(mmc_dev(mmc));
2889 } else if (host->plat->wpswitch_gpio) {
2890 status = gpio_request(host->plat->wpswitch_gpio,
2891 "SD_WP_Switch");
2892 if (status) {
2893 pr_err("%s: %s: Failed to request GPIO %d\n",
2894 mmc_hostname(mmc), __func__,
2895 host->plat->wpswitch_gpio);
2896 } else {
2897 status = gpio_direction_input(
2898 host->plat->wpswitch_gpio);
2899 if (!status) {
2900 /*
2901 * Wait for atleast 300ms as debounce
2902 * time for GPIO input to stabilize.
2903 */
2904 msleep(300);
2905 status = gpio_get_value_cansleep(
2906 host->plat->wpswitch_gpio);
2907 status ^= !host->plat->wpswitch_polarity;
2908 }
2909 gpio_free(host->plat->wpswitch_gpio);
2910 }
2911 }
2912
2913 if (status < 0)
2914 status = -ENOSYS;
2915 pr_debug("%s: Card read-only status %d\n", __func__, status);
2916
2917 return status;
2918}
2919
San Mehat9d2bd732009-09-22 16:44:22 -07002920static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2921{
2922 struct msmsdcc_host *host = mmc_priv(mmc);
2923 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002924
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302925 /*
2926 * We may come here with clocks turned off in that case don't
2927 * attempt to write into MASK0 register. While turning on the
2928 * clocks mci_irqenable will be written to MASK0 register.
2929 */
2930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931 if (enable) {
2932 spin_lock_irqsave(&host->lock, flags);
2933 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302934 if (host->clks_on) {
2935 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302937 mb();
2938 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002939 spin_unlock_irqrestore(&host->lock, flags);
2940 } else {
2941 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302942 if (host->clks_on) {
2943 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002944 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05302945 mb();
2946 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002949
2950#ifdef CONFIG_PM_RUNTIME
subhashj245831e2012-04-30 18:46:17 +05302951static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
2952{
2953 struct device *dev = mmc_dev(host->mmc);
2954
2955 pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
2956 " is_suspended=%d, disable_depth=%d, runtime_error=%d,"
2957 " request_pending=%d, request=%d\n",
2958 mmc_hostname(host->mmc), dev->power.runtime_status,
2959 atomic_read(&dev->power.usage_count),
2960 dev->power.is_suspended, dev->power.disable_depth,
2961 dev->power.runtime_error, dev->power.request_pending,
2962 dev->power.request);
2963}
2964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965static int msmsdcc_enable(struct mmc_host *mmc)
2966{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002967 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002968 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302969 struct msmsdcc_host *host = mmc_priv(mmc);
2970
2971 msmsdcc_pm_qos_update_latency(host, 1);
2972
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002973 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302974 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002976 if (host->sdcc_suspended && host->pending_resume &&
2977 !pm_runtime_suspended(dev)) {
2978 host->pending_resume = false;
2979 pm_runtime_get_noresume(dev);
2980 rc = msmsdcc_runtime_resume(dev);
2981 goto out;
2982 }
2983
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302984 if (dev->power.runtime_status == RPM_SUSPENDING) {
2985 if (mmc->suspend_task == current) {
2986 pm_runtime_get_noresume(dev);
2987 goto out;
2988 }
2989 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302991 rc = pm_runtime_get_sync(dev);
2992
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07002993out:
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302994 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002995 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2996 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05302997 msmsdcc_print_rpm_info(host);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302998 return rc;
2999 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303000
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05303001 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002}
3003
3004static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3005{
3006 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303007 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303009 msmsdcc_pm_qos_update_latency(host, 0);
3010
3011 if (mmc->card && mmc_card_sdio(mmc->card))
3012 return 0;
3013
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05303014 if (host->plat->disable_runtime_pm)
3015 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003016
3017 rc = pm_runtime_put_sync(mmc->parent);
3018
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003019 /*
3020 * Ignore -EAGAIN as that is not fatal, it means that
3021 * either runtime usage count is non-zero or the runtime
3022 * pm itself is disabled or not in proper state to process
3023 * idle notification.
3024 */
3025 if (rc < 0 && (rc != -EAGAIN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3027 __func__, rc);
subhashj245831e2012-04-30 18:46:17 +05303028 msmsdcc_print_rpm_info(host);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003029 return rc;
3030 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303031
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003032 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003033}
3034#else
subhashj245831e2012-04-30 18:46:17 +05303035static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
3036
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303037static int msmsdcc_enable(struct mmc_host *mmc)
3038{
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003039 struct device *dev = mmc->parent;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303040 struct msmsdcc_host *host = mmc_priv(mmc);
3041 unsigned long flags;
Sujit Reddy Thumma7f5051c2012-05-04 10:14:07 +05303042 int rc = 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303043
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303044 msmsdcc_pm_qos_update_latency(host, 1);
3045
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003046 if (mmc->card && mmc_card_sdio(mmc->card))
3047 return 0;
3048
3049 if (host->sdcc_suspended && host->pending_resume) {
3050 host->pending_resume = false;
3051 rc = msmsdcc_runtime_resume(dev);
3052 goto out;
3053 }
3054
Asutosh Dasf5298c32012-04-03 14:51:47 +05303055 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303056 spin_lock_irqsave(&host->lock, flags);
3057 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303058 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303059 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303060 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303061 host->clks_on = 1;
3062 }
3063 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303064 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303065
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07003066out:
3067 if (rc < 0) {
3068 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3069 __func__, rc);
3070 return rc;
3071 }
3072
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303073 return 0;
3074}
3075
3076static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
3077{
3078 struct msmsdcc_host *host = mmc_priv(mmc);
3079 unsigned long flags;
3080
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303081 msmsdcc_pm_qos_update_latency(host, 0);
3082
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303083 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05303084 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303085
Asutosh Dasf5298c32012-04-03 14:51:47 +05303086 mutex_lock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303087 spin_lock_irqsave(&host->lock, flags);
3088 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05303089 spin_unlock_irqrestore(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303090 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303091 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303092 host->clks_on = 0;
3093 }
3094 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303095 mutex_unlock(&host->clk_mutex);
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05303096
3097 return 0;
3098}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003099#endif
3100
3101static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
3102 struct mmc_ios *ios)
3103{
3104 struct msmsdcc_host *host = mmc_priv(mmc);
3105 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303106 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107
Subhash Jadavani00083572012-02-15 16:18:01 +05303108 spin_lock_irqsave(&host->lock, flags);
3109 host->io_pad_pwr_switch = 0;
3110 spin_unlock_irqrestore(&host->lock, flags);
3111
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303112 /*
3113 * For eMMC cards, VccQ voltage range must be changed
3114 * only if it operates in HS200 SDR 1.2V mode or in
3115 * DDR 1.2V mode.
3116 */
3117 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
3118 rc = msmsdcc_set_vccq_vol(host, 1200000);
3119 goto out;
3120 }
3121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
3123 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303124 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125 goto out;
3126 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
3127 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303128 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003129 goto out;
3130 }
San Mehat9d2bd732009-09-22 16:44:22 -07003131
3132 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133 /*
3134 * If we are here means voltage switch from high voltage to
3135 * low voltage is required
3136 */
3137
3138 /*
3139 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
3140 * register until they become all zeros.
3141 */
3142 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303143 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
3145 mmc_hostname(mmc), __func__);
3146 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07003147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148
3149 /* Stop SD CLK output. */
3150 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3151 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303152 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003153 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154
3155 /*
3156 * Switch VDDPX from high voltage to low voltage
3157 * to change the VDD of the SD IO pads.
3158 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303159 rc = msmsdcc_set_vddp_low_vol(host);
3160 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003162
3163 spin_lock_irqsave(&host->lock, flags);
3164 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3165 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303166 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167 host->io_pad_pwr_switch = 1;
3168 spin_unlock_irqrestore(&host->lock, flags);
3169
3170 /* Wait 5 ms for the voltage regulater in the card to become stable. */
3171 usleep_range(5000, 5500);
3172
3173 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303174 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3176 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303177 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003178 spin_unlock_irqrestore(&host->lock, flags);
3179
3180 /*
3181 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
3182 * don't become all ones within 1 ms then a Voltage Switch
3183 * sequence has failed and a power cycle to the card is required.
3184 * Otherwise Voltage Switch sequence is completed successfully.
3185 */
3186 usleep_range(1000, 1500);
3187
3188 spin_lock_irqsave(&host->lock, flags);
3189 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
3190 != (0xF << 1)) {
3191 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
3192 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303193 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194 goto out_unlock;
3195 }
3196
3197out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05303198 /* Enable PWRSAVE */
3199 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3200 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303201 msmsdcc_sync_reg_wr(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 spin_unlock_irqrestore(&host->lock, flags);
3203out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05303204 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205}
3206
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303207static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003209 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003210
3211 /* Program the MCLK value to MCLK_FREQ bit field */
3212 if (host->clk_rate <= 112000000)
3213 mclk_freq = 0;
3214 else if (host->clk_rate <= 125000000)
3215 mclk_freq = 1;
3216 else if (host->clk_rate <= 137000000)
3217 mclk_freq = 2;
3218 else if (host->clk_rate <= 150000000)
3219 mclk_freq = 3;
3220 else if (host->clk_rate <= 162000000)
3221 mclk_freq = 4;
3222 else if (host->clk_rate <= 175000000)
3223 mclk_freq = 5;
3224 else if (host->clk_rate <= 187000000)
3225 mclk_freq = 6;
3226 else if (host->clk_rate <= 200000000)
3227 mclk_freq = 7;
3228
3229 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3230 & ~(7 << 24)) | (mclk_freq << 24)),
3231 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232}
3233
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303234/* Initialize the DLL (Programmable Delay Line ) */
3235static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003236{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003237 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303238 unsigned long flags;
3239 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303241 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 /*
3243 * Make sure that clock is always enabled when DLL
3244 * tuning is in progress. Keeping PWRSAVE ON may
3245 * turn off the clock. So let's disable the PWRSAVE
3246 * here and re-enable it once tuning is completed.
3247 */
3248 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
3249 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303250 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303251
3252 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
3253 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3254 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3255
3256 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
3257 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3258 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3259
3260 msmsdcc_cm_sdc4_dll_set_freq(host);
3261
3262 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
3263 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3264 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
3265
3266 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
3267 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3268 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
3269
3270 /* Set DLL_EN bit to 1. */
3271 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3272 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
3273
3274 /* Set CK_OUT_EN bit to 1. */
3275 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3276 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3277
3278 wait_cnt = 50;
3279 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
3280 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
3281 /* max. wait for 50us sec for LOCK bit to be set */
3282 if (--wait_cnt == 0) {
3283 pr_err("%s: %s: DLL failed to LOCK\n",
3284 mmc_hostname(host->mmc), __func__);
3285 rc = -ETIMEDOUT;
3286 goto out;
3287 }
3288 /* wait for 1us before polling again */
3289 udelay(1);
3290 }
3291
3292out:
3293 /* re-enable PWRSAVE */
3294 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
3295 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanidd432952012-03-28 11:25:56 +05303296 msmsdcc_sync_reg_wr(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303297 spin_unlock_irqrestore(&host->lock, flags);
3298
3299 return rc;
3300}
3301
3302static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
3303 u8 poll)
3304{
3305 int rc = 0;
3306 u32 wait_cnt = 50;
3307 u8 ck_out_en = 0;
3308
3309 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
3310 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3311 MCI_CK_OUT_EN);
3312
3313 while (ck_out_en != poll) {
3314 if (--wait_cnt == 0) {
3315 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
3316 mmc_hostname(host->mmc), __func__, poll);
3317 rc = -ETIMEDOUT;
3318 goto out;
3319 }
3320 udelay(1);
3321
3322 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
3323 MCI_CK_OUT_EN);
3324 }
3325out:
3326 return rc;
3327}
3328
3329/*
3330 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
3331 * calibration sequence. This function should be called before
3332 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
3333 * commands (CMD17/CMD18).
3334 *
3335 * This function gets called when host spinlock acquired.
3336 */
3337static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
3338{
3339 int rc = 0;
3340 u32 config;
3341
3342 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3343 config |= MCI_CDR_EN;
3344 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
3345 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3346
3347 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3348 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3349 if (rc)
3350 goto err_out;
3351
3352 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3353 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3354 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3355
3356 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3357 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3358 if (rc)
3359 goto err_out;
3360
3361 goto out;
3362
3363err_out:
3364 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
3365out:
3366 return rc;
3367}
3368
3369static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
3370 u8 phase)
3371{
3372 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05303373 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
3374 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
3375 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303376 unsigned long flags;
3377 u32 config;
3378
3379 spin_lock_irqsave(&host->lock, flags);
3380
3381 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3382 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
3383 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
3384 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3385
3386 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
3387 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
3388 if (rc)
3389 goto err_out;
3390
3391 /*
3392 * Write the selected DLL clock output phase (0 ... 15)
3393 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
3394 */
3395 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
3396 & ~(0xF << 20))
3397 | (grey_coded_phase_table[phase] << 20)),
3398 host->base + MCI_DLL_CONFIG);
3399
3400 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
3401 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
3402 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
3403
3404 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
3405 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
3406 if (rc)
3407 goto err_out;
3408
3409 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
3410 config |= MCI_CDR_EN;
3411 config &= ~MCI_CDR_EXT_EN;
3412 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
3413 goto out;
3414
3415err_out:
3416 pr_err("%s: %s: Failed to set DLL phase: %d\n",
3417 mmc_hostname(host->mmc), __func__, phase);
3418out:
3419 spin_unlock_irqrestore(&host->lock, flags);
3420 return rc;
3421}
3422
3423/*
3424 * Find out the greatest range of consecuitive selected
3425 * DLL clock output phases that can be used as sampling
3426 * setting for SD3.0 UHS-I card read operation (in SDR104
3427 * timing mode) or for eMMC4.5 card read operation (in HS200
3428 * timing mode).
3429 * Select the 3/4 of the range and configure the DLL with the
3430 * selected DLL clock output phase.
3431*/
Subhash Jadavani34187042012-03-02 10:59:49 +05303432static int find_most_appropriate_phase(struct msmsdcc_host *host,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303433 u8 *phase_table, u8 total_phases)
3434{
Subhash Jadavani6159c622012-03-15 19:05:55 +05303435 #define MAX_PHASES 16
Subhash Jadavani34187042012-03-02 10:59:49 +05303436 int ret;
Subhash Jadavani6159c622012-03-15 19:05:55 +05303437 u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
3438 u8 phases_per_row[MAX_PHASES] = {0};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303439 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303440 int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
3441 bool phase_0_found = false, phase_15_found = false;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303442
Subhash Jadavani6159c622012-03-15 19:05:55 +05303443 if (!total_phases || (total_phases > MAX_PHASES)) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303444 pr_err("%s: %s: invalid argument: total_phases=%d\n",
3445 mmc_hostname(host->mmc), __func__, total_phases);
3446 return -EINVAL;
3447 }
3448
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303449 for (cnt = 0; cnt < total_phases; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303450 ranges[row_index][col_index] = phase_table[cnt];
3451 phases_per_row[row_index] += 1;
3452 col_index++;
3453
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303454 if ((cnt + 1) == total_phases) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303455 continue;
3456 /* check if next phase in phase_table is consecutive or not */
3457 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
3458 row_index++;
3459 col_index = 0;
3460 }
3461 }
3462
Subhash Jadavani6159c622012-03-15 19:05:55 +05303463 if (row_index >= MAX_PHASES)
3464 return -EINVAL;
3465
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303466 /* Check if phase-0 is present in first valid window? */
3467 if (!ranges[0][0]) {
3468 phase_0_found = true;
3469 phase_0_raw_index = 0;
3470 /* Check if cycle exist between 2 valid windows */
3471 for (cnt = 1; cnt <= row_index; cnt++) {
3472 if (phases_per_row[cnt]) {
Subhash Jadavani6159c622012-03-15 19:05:55 +05303473 for (i = 0; i < phases_per_row[cnt]; i++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303474 if (ranges[cnt][i] == 15) {
3475 phase_15_found = true;
3476 phase_15_raw_index = cnt;
3477 break;
3478 }
3479 }
3480 }
3481 }
3482 }
3483
3484 /* If 2 valid windows form cycle then merge them as single window */
3485 if (phase_0_found && phase_15_found) {
3486 /* number of phases in raw where phase 0 is present */
3487 u8 phases_0 = phases_per_row[phase_0_raw_index];
3488 /* number of phases in raw where phase 15 is present */
3489 u8 phases_15 = phases_per_row[phase_15_raw_index];
3490
Subhash Jadavani6159c622012-03-15 19:05:55 +05303491 if (phases_0 + phases_15 >= MAX_PHASES)
3492 /*
3493 * If there are more than 1 phase windows then total
3494 * number of phases in both the windows should not be
3495 * more than or equal to MAX_PHASES.
3496 */
3497 return -EINVAL;
3498
3499 /* Merge 2 cyclic windows */
3500 i = phases_15;
3501 for (cnt = 0; cnt < phases_0; cnt++) {
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303502 ranges[phase_15_raw_index][i] =
3503 ranges[phase_0_raw_index][cnt];
Subhash Jadavani6159c622012-03-15 19:05:55 +05303504 if (++i >= MAX_PHASES)
3505 break;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303506 }
Subhash Jadavani6159c622012-03-15 19:05:55 +05303507
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303508 phases_per_row[phase_0_raw_index] = 0;
3509 phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
3510 }
3511
3512 for (cnt = 0; cnt <= row_index; cnt++) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303513 if (phases_per_row[cnt] > curr_max) {
3514 curr_max = phases_per_row[cnt];
3515 selected_row_index = cnt;
3516 }
3517 }
3518
Subhash Jadavani6159c622012-03-15 19:05:55 +05303519 i = ((curr_max * 3) / 4);
3520 if (i)
3521 i--;
3522
Subhash Jadavani34187042012-03-02 10:59:49 +05303523 ret = (int)ranges[selected_row_index][i];
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303524
Subhash Jadavani6159c622012-03-15 19:05:55 +05303525 if (ret >= MAX_PHASES) {
3526 ret = -EINVAL;
3527 pr_err("%s: %s: invalid phase selected=%d\n",
3528 mmc_hostname(host->mmc), __func__, ret);
3529 }
3530
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303531 return ret;
3532}
3533
Girish K Sa3f41692012-02-29 12:00:09 +05303534static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303535{
3536 int rc = 0;
3537 struct msmsdcc_host *host = mmc_priv(mmc);
3538 unsigned long flags;
3539 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303540 const u32 *tuning_block_pattern = tuning_block_64;
3541 int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303542
3543 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
3544
3545 /* Tuning is only required for SDR104 modes */
3546 if (!host->tuning_needed) {
3547 rc = 0;
3548 goto exit;
3549 }
3550
3551 spin_lock_irqsave(&host->lock, flags);
3552 WARN(!host->pwr, "SDCC power is turned off\n");
3553 WARN(!host->clks_on, "SDCC clocks are turned off\n");
3554 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
3555
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303556 host->tuning_in_progress = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303557 if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
3558 (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
3559 tuning_block_pattern = tuning_block_128;
3560 size = sizeof(tuning_block_128);
3561 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303562 spin_unlock_irqrestore(&host->lock, flags);
3563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 /* first of all reset the tuning block */
3565 rc = msmsdcc_init_cm_sdc4_dll(host);
3566 if (rc)
3567 goto out;
3568
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303569 data_buf = kmalloc(size, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003570 if (!data_buf) {
3571 rc = -ENOMEM;
3572 goto out;
3573 }
3574
3575 phase = 0;
3576 do {
3577 struct mmc_command cmd = {0};
3578 struct mmc_data data = {0};
3579 struct mmc_request mrq = {
3580 .cmd = &cmd,
3581 .data = &data
3582 };
3583 struct scatterlist sg;
3584
3585 /* set the phase in delay line hw block */
3586 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3587 if (rc)
3588 goto kfree;
3589
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303590 cmd.opcode = opcode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003591 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
3592
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303593 data.blksz = size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003594 data.blocks = 1;
3595 data.flags = MMC_DATA_READ;
3596 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
3597
3598 data.sg = &sg;
3599 data.sg_len = 1;
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303600 sg_init_one(&sg, data_buf, size);
3601 memset(data_buf, 0, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 mmc_wait_for_req(mmc, &mrq);
3603
3604 if (!cmd.error && !data.error &&
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303605 !memcmp(data_buf, tuning_block_pattern, size)) {
3606 /* tuning is successful at this tuning point */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 tuned_phases[tuned_phase_cnt++] = phase;
Subhash Jadavani8b6ee572012-02-02 18:24:45 +05303608 pr_debug("%s: %s: found good phase = %d\n",
3609 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003610 }
3611 } while (++phase < 16);
3612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613 if (tuned_phase_cnt) {
Subhash Jadavani34187042012-03-02 10:59:49 +05303614 rc = find_most_appropriate_phase(host, tuned_phases,
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303615 tuned_phase_cnt);
Subhash Jadavani34187042012-03-02 10:59:49 +05303616 if (rc < 0)
3617 goto kfree;
3618 else
3619 phase = (u8)rc;
3620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003621 /*
3622 * Finally set the selected phase in delay
3623 * line hw block.
3624 */
3625 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
3626 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303627 goto kfree;
3628 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
3629 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003630 } else {
3631 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303632 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003633 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303634 msmsdcc_dump_sdcc_state(host);
3635 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003637
3638kfree:
3639 kfree(data_buf);
3640out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303641 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05303642 host->tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303643 spin_unlock_irqrestore(&host->lock, flags);
3644exit:
3645 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003647}
3648
3649static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 .enable = msmsdcc_enable,
3651 .disable = msmsdcc_disable,
Asutosh Dasaccacd42012-03-08 14:33:17 +05303652 .pre_req = msmsdcc_pre_req,
3653 .post_req = msmsdcc_post_req,
San Mehat9d2bd732009-09-22 16:44:22 -07003654 .request = msmsdcc_request,
3655 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 .get_ro = msmsdcc_get_ro,
San Mehat9d2bd732009-09-22 16:44:22 -07003657 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003658 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3659 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003660};
3661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662static unsigned int
3663msmsdcc_slot_status(struct msmsdcc_host *host)
3664{
3665 int status;
3666 unsigned int gpio_no = host->plat->status_gpio;
3667
3668 status = gpio_request(gpio_no, "SD_HW_Detect");
3669 if (status) {
3670 pr_err("%s: %s: Failed to request GPIO %d\n",
3671 mmc_hostname(host->mmc), __func__, gpio_no);
3672 } else {
3673 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003674 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003675 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003676 if (host->plat->is_status_gpio_active_low)
3677 status = !status;
3678 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003679 gpio_free(gpio_no);
3680 }
3681 return status;
3682}
3683
San Mehat9d2bd732009-09-22 16:44:22 -07003684static void
3685msmsdcc_check_status(unsigned long data)
3686{
3687 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3688 unsigned int status;
3689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003690 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003691 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003693 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003694 status = msmsdcc_slot_status(host);
3695
Krishna Konda941604a2012-01-10 17:46:34 -08003696 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003698 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003699 if (host->plat->status)
3700 pr_info("%s: Slot status change detected "
3701 "(%d -> %d)\n",
3702 mmc_hostname(host->mmc),
3703 host->oldstat, status);
3704 else if (host->plat->is_status_gpio_active_low)
3705 pr_info("%s: Slot status change detected "
3706 "(%d -> %d) and the card detect GPIO"
3707 " is ACTIVE_LOW\n",
3708 mmc_hostname(host->mmc),
3709 host->oldstat, status);
3710 else
3711 pr_info("%s: Slot status change detected "
3712 "(%d -> %d) and the card detect GPIO"
3713 " is ACTIVE_HIGH\n",
3714 mmc_hostname(host->mmc),
3715 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003716 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717 }
3718 host->oldstat = status;
3719 } else {
3720 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003721 }
San Mehat9d2bd732009-09-22 16:44:22 -07003722}
3723
3724static irqreturn_t
3725msmsdcc_platform_status_irq(int irq, void *dev_id)
3726{
3727 struct msmsdcc_host *host = dev_id;
3728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003729 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003730 msmsdcc_check_status((unsigned long) host);
3731 return IRQ_HANDLED;
3732}
3733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003734static irqreturn_t
3735msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3736{
3737 struct msmsdcc_host *host = dev_id;
3738
3739 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3740 spin_lock(&host->lock);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303741 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742 disable_irq_nosync(irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303743 if (host->sdcc_suspended) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744 wake_lock(&host->sdio_wlock);
3745 msmsdcc_disable_irq_wake(host);
3746 }
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05303747 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748 }
3749 if (host->plat->is_sdio_al_client) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 wake_lock(&host->sdio_wlock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05303751 mmc_signal_sdio_irq(host->mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 }
3753 spin_unlock(&host->lock);
3754
3755 return IRQ_HANDLED;
3756}
3757
San Mehat9d2bd732009-09-22 16:44:22 -07003758static void
3759msmsdcc_status_notify_cb(int card_present, void *dev_id)
3760{
3761 struct msmsdcc_host *host = dev_id;
3762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003763 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003764 card_present);
3765 msmsdcc_check_status((unsigned long) host);
3766}
3767
San Mehat9d2bd732009-09-22 16:44:22 -07003768static int
3769msmsdcc_init_dma(struct msmsdcc_host *host)
3770{
3771 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3772 host->dma.host = host;
3773 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003774 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003775
3776 if (!host->dmares)
3777 return -ENODEV;
3778
3779 host->dma.nc = dma_alloc_coherent(NULL,
3780 sizeof(struct msmsdcc_nc_dmadata),
3781 &host->dma.nc_busaddr,
3782 GFP_KERNEL);
3783 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003784 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003785 return -ENOMEM;
3786 }
3787 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3788 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3789 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3790 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3791 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003792 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003793
3794 return 0;
3795}
3796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003797#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3798/**
3799 * Allocate and Connect a SDCC peripheral's SPS endpoint
3800 *
3801 * This function allocates endpoint context and
3802 * connect it with memory endpoint by calling
3803 * appropriate SPS driver APIs.
3804 *
3805 * Also registers a SPS callback function with
3806 * SPS driver
3807 *
3808 * This function should only be called once typically
3809 * during driver probe.
3810 *
3811 * @host - Pointer to sdcc host structure
3812 * @ep - Pointer to sps endpoint data structure
3813 * @is_produce - 1 means Producer endpoint
3814 * 0 means Consumer endpoint
3815 *
3816 * @return - 0 if successful else negative value.
3817 *
3818 */
3819static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3820 struct msmsdcc_sps_ep_conn_data *ep,
3821 bool is_producer)
3822{
3823 int rc = 0;
3824 struct sps_pipe *sps_pipe_handle;
3825 struct sps_connect *sps_config = &ep->config;
3826 struct sps_register_event *sps_event = &ep->event;
3827
3828 /* Allocate endpoint context */
3829 sps_pipe_handle = sps_alloc_endpoint();
3830 if (!sps_pipe_handle) {
3831 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3832 mmc_hostname(host->mmc), is_producer);
3833 rc = -ENOMEM;
3834 goto out;
3835 }
3836
3837 /* Get default connection configuration for an endpoint */
3838 rc = sps_get_config(sps_pipe_handle, sps_config);
3839 if (rc) {
3840 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3841 " rc=%d", mmc_hostname(host->mmc),
3842 (u32)sps_pipe_handle, rc);
3843 goto get_config_err;
3844 }
3845
3846 /* Modify the default connection configuration */
3847 if (is_producer) {
3848 /*
3849 * For SDCC producer transfer, source should be
3850 * SDCC peripheral where as destination should
3851 * be system memory.
3852 */
3853 sps_config->source = host->sps.bam_handle;
3854 sps_config->destination = SPS_DEV_HANDLE_MEM;
3855 /* Producer pipe will handle this connection */
3856 sps_config->mode = SPS_MODE_SRC;
3857 sps_config->options =
3858 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3859 } else {
3860 /*
3861 * For SDCC consumer transfer, source should be
3862 * system memory where as destination should
3863 * SDCC peripheral
3864 */
3865 sps_config->source = SPS_DEV_HANDLE_MEM;
3866 sps_config->destination = host->sps.bam_handle;
3867 sps_config->mode = SPS_MODE_DEST;
3868 sps_config->options =
3869 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3870 }
3871
3872 /* Producer pipe index */
3873 sps_config->src_pipe_index = host->sps.src_pipe_index;
3874 /* Consumer pipe index */
3875 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3876 /*
3877 * This event thresold value is only significant for BAM-to-BAM
3878 * transfer. It's ignored for BAM-to-System mode transfer.
3879 */
3880 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303881
3882 /* Allocate maximum descriptor fifo size */
3883 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3884 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3886 sps_config->desc.size,
3887 &sps_config->desc.phys_base,
3888 GFP_KERNEL);
3889
Pratibhasagar V00b94332011-10-18 14:57:27 +05303890 if (!sps_config->desc.base) {
3891 rc = -ENOMEM;
3892 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3893 , mmc_hostname(host->mmc));
3894 goto get_config_err;
3895 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3897
3898 /* Establish connection between peripheral and memory endpoint */
3899 rc = sps_connect(sps_pipe_handle, sps_config);
3900 if (rc) {
3901 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3902 " rc=%d", mmc_hostname(host->mmc),
3903 (u32)sps_pipe_handle, rc);
3904 goto sps_connect_err;
3905 }
3906
3907 sps_event->mode = SPS_TRIGGER_CALLBACK;
3908 sps_event->options = SPS_O_EOT;
3909 sps_event->callback = msmsdcc_sps_complete_cb;
3910 sps_event->xfer_done = NULL;
3911 sps_event->user = (void *)host;
3912
3913 /* Register callback event for EOT (End of transfer) event. */
3914 rc = sps_register_event(sps_pipe_handle, sps_event);
3915 if (rc) {
3916 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3917 " rc=%d", mmc_hostname(host->mmc),
3918 (u32)sps_pipe_handle, rc);
3919 goto reg_event_err;
3920 }
3921 /* Now save the sps pipe handle */
3922 ep->pipe_handle = sps_pipe_handle;
3923 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3924 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3925 __func__, is_producer ? "READ" : "WRITE",
3926 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3927 goto out;
3928
3929reg_event_err:
3930 sps_disconnect(sps_pipe_handle);
3931sps_connect_err:
3932 dma_free_coherent(mmc_dev(host->mmc),
3933 sps_config->desc.size,
3934 sps_config->desc.base,
3935 sps_config->desc.phys_base);
3936get_config_err:
3937 sps_free_endpoint(sps_pipe_handle);
3938out:
3939 return rc;
3940}
3941
3942/**
3943 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3944 *
3945 * This function disconnect endpoint and deallocates
3946 * endpoint context.
3947 *
3948 * This function should only be called once typically
3949 * during driver remove.
3950 *
3951 * @host - Pointer to sdcc host structure
3952 * @ep - Pointer to sps endpoint data structure
3953 *
3954 */
3955static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3956 struct msmsdcc_sps_ep_conn_data *ep)
3957{
3958 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3959 struct sps_connect *sps_config = &ep->config;
3960 struct sps_register_event *sps_event = &ep->event;
3961
3962 sps_event->xfer_done = NULL;
3963 sps_event->callback = NULL;
3964 sps_register_event(sps_pipe_handle, sps_event);
3965 sps_disconnect(sps_pipe_handle);
3966 dma_free_coherent(mmc_dev(host->mmc),
3967 sps_config->desc.size,
3968 sps_config->desc.base,
3969 sps_config->desc.phys_base);
3970 sps_free_endpoint(sps_pipe_handle);
3971}
3972
3973/**
3974 * Reset SDCC peripheral's SPS endpoint
3975 *
3976 * This function disconnects an endpoint.
3977 *
3978 * This function should be called for reseting
3979 * SPS endpoint when data transfer error is
3980 * encountered during data transfer. This
3981 * can be considered as soft reset to endpoint.
3982 *
3983 * This function should only be called if
3984 * msmsdcc_sps_init() is already called.
3985 *
3986 * @host - Pointer to sdcc host structure
3987 * @ep - Pointer to sps endpoint data structure
3988 *
3989 * @return - 0 if successful else negative value.
3990 */
3991static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3992 struct msmsdcc_sps_ep_conn_data *ep)
3993{
3994 int rc = 0;
3995 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3996
3997 rc = sps_disconnect(sps_pipe_handle);
3998 if (rc) {
3999 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
4000 " rc=%d", mmc_hostname(host->mmc), __func__,
4001 (u32)sps_pipe_handle, rc);
4002 goto out;
4003 }
4004 out:
4005 return rc;
4006}
4007
4008/**
4009 * Restore SDCC peripheral's SPS endpoint
4010 *
4011 * This function connects an endpoint.
4012 *
4013 * This function should be called for restoring
4014 * SPS endpoint after data transfer error is
4015 * encountered during data transfer. This
4016 * can be considered as soft reset to endpoint.
4017 *
4018 * This function should only be called if
4019 * msmsdcc_sps_reset_ep() is called before.
4020 *
4021 * @host - Pointer to sdcc host structure
4022 * @ep - Pointer to sps endpoint data structure
4023 *
4024 * @return - 0 if successful else negative value.
4025 */
4026static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
4027 struct msmsdcc_sps_ep_conn_data *ep)
4028{
4029 int rc = 0;
4030 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
4031 struct sps_connect *sps_config = &ep->config;
4032 struct sps_register_event *sps_event = &ep->event;
4033
4034 /* Establish connection between peripheral and memory endpoint */
4035 rc = sps_connect(sps_pipe_handle, sps_config);
4036 if (rc) {
4037 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
4038 " rc=%d", mmc_hostname(host->mmc), __func__,
4039 (u32)sps_pipe_handle, rc);
4040 goto out;
4041 }
4042
4043 /* Register callback event for EOT (End of transfer) event. */
4044 rc = sps_register_event(sps_pipe_handle, sps_event);
4045 if (rc) {
4046 pr_err("%s: %s: sps_register_event() failed!!!"
4047 " pipe_handle=0x%x, rc=%d",
4048 mmc_hostname(host->mmc), __func__,
4049 (u32)sps_pipe_handle, rc);
4050 goto reg_event_err;
4051 }
4052 goto out;
4053
4054reg_event_err:
4055 sps_disconnect(sps_pipe_handle);
4056out:
4057 return rc;
4058}
4059
4060/**
4061 * Initialize SPS HW connected with SDCC core
4062 *
4063 * This function register BAM HW resources with
4064 * SPS driver and then initialize 2 SPS endpoints
4065 *
4066 * This function should only be called once typically
4067 * during driver probe.
4068 *
4069 * @host - Pointer to sdcc host structure
4070 *
4071 * @return - 0 if successful else negative value.
4072 *
4073 */
4074static int msmsdcc_sps_init(struct msmsdcc_host *host)
4075{
4076 int rc = 0;
4077 struct sps_bam_props bam = {0};
4078
4079 host->bam_base = ioremap(host->bam_memres->start,
4080 resource_size(host->bam_memres));
4081 if (!host->bam_base) {
4082 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
4083 " size=0x%x", mmc_hostname(host->mmc),
4084 host->bam_memres->start,
4085 (host->bam_memres->end -
4086 host->bam_memres->start));
4087 rc = -ENOMEM;
4088 goto out;
4089 }
4090
4091 bam.phys_addr = host->bam_memres->start;
4092 bam.virt_addr = host->bam_base;
4093 /*
4094 * This event thresold value is only significant for BAM-to-BAM
4095 * transfer. It's ignored for BAM-to-System mode transfer.
4096 */
4097 bam.event_threshold = 0x10; /* Pipe event threshold */
4098 /*
4099 * This threshold controls when the BAM publish
4100 * the descriptor size on the sideband interface.
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304101 * SPS HW will be used for data transfer size even
4102 * less than SDCC FIFO size. So let's set BAM summing
4103 * thresold to SPS_MIN_XFER_SIZE bytes.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104 */
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304105 bam.summing_threshold = SPS_MIN_XFER_SIZE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004106 /* SPS driver wll handle the SDCC BAM IRQ */
4107 bam.irq = (u32)host->bam_irqres->start;
4108 bam.manage = SPS_BAM_MGR_LOCAL;
4109
4110 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
4111 (u32)bam.phys_addr);
4112 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
4113 (u32)bam.virt_addr);
4114
4115 /* Register SDCC Peripheral BAM device to SPS driver */
4116 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
4117 if (rc) {
4118 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
4119 mmc_hostname(host->mmc), rc);
4120 goto reg_bam_err;
4121 }
4122 pr_info("%s: BAM device registered. bam_handle=0x%x",
4123 mmc_hostname(host->mmc), host->sps.bam_handle);
4124
4125 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
4126 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
4127
4128 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
4129 SPS_PROD_PERIPHERAL);
4130 if (rc)
4131 goto sps_reset_err;
4132 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
4133 SPS_CONS_PERIPHERAL);
4134 if (rc)
4135 goto cons_conn_err;
4136
4137 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
4138 mmc_hostname(host->mmc),
4139 (unsigned long long)host->bam_memres->start,
4140 (unsigned int)host->bam_irqres->start);
4141 goto out;
4142
4143cons_conn_err:
4144 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4145sps_reset_err:
4146 sps_deregister_bam_device(host->sps.bam_handle);
4147reg_bam_err:
4148 iounmap(host->bam_base);
4149out:
4150 return rc;
4151}
4152
4153/**
4154 * De-initialize SPS HW connected with SDCC core
4155 *
4156 * This function deinitialize SPS endpoints and then
4157 * deregisters BAM resources from SPS driver.
4158 *
4159 * This function should only be called once typically
4160 * during driver remove.
4161 *
4162 * @host - Pointer to sdcc host structure
4163 *
4164 */
4165static void msmsdcc_sps_exit(struct msmsdcc_host *host)
4166{
4167 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
4168 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
4169 sps_deregister_bam_device(host->sps.bam_handle);
4170 iounmap(host->bam_base);
4171}
4172#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
4173
4174static ssize_t
4175show_polling(struct device *dev, struct device_attribute *attr, char *buf)
4176{
4177 struct mmc_host *mmc = dev_get_drvdata(dev);
4178 struct msmsdcc_host *host = mmc_priv(mmc);
4179 int poll;
4180 unsigned long flags;
4181
4182 spin_lock_irqsave(&host->lock, flags);
4183 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
4184 spin_unlock_irqrestore(&host->lock, flags);
4185
4186 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
4187}
4188
4189static ssize_t
4190set_polling(struct device *dev, struct device_attribute *attr,
4191 const char *buf, size_t count)
4192{
4193 struct mmc_host *mmc = dev_get_drvdata(dev);
4194 struct msmsdcc_host *host = mmc_priv(mmc);
4195 int value;
4196 unsigned long flags;
4197
4198 sscanf(buf, "%d", &value);
4199
4200 spin_lock_irqsave(&host->lock, flags);
4201 if (value) {
4202 mmc->caps |= MMC_CAP_NEEDS_POLL;
4203 mmc_detect_change(host->mmc, 0);
4204 } else {
4205 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4206 }
4207#ifdef CONFIG_HAS_EARLYSUSPEND
4208 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
4209#endif
4210 spin_unlock_irqrestore(&host->lock, flags);
4211 return count;
4212}
4213
4214static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
4215 show_polling, set_polling);
4216static struct attribute *dev_attrs[] = {
4217 &dev_attr_polling.attr,
4218 NULL,
4219};
4220static struct attribute_group dev_attr_grp = {
4221 .attrs = dev_attrs,
4222};
4223
4224#ifdef CONFIG_HAS_EARLYSUSPEND
4225static void msmsdcc_early_suspend(struct early_suspend *h)
4226{
4227 struct msmsdcc_host *host =
4228 container_of(h, struct msmsdcc_host, early_suspend);
4229 unsigned long flags;
4230
4231 spin_lock_irqsave(&host->lock, flags);
4232 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
4233 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
4234 spin_unlock_irqrestore(&host->lock, flags);
4235};
4236static void msmsdcc_late_resume(struct early_suspend *h)
4237{
4238 struct msmsdcc_host *host =
4239 container_of(h, struct msmsdcc_host, early_suspend);
4240 unsigned long flags;
4241
4242 if (host->polling_enabled) {
4243 spin_lock_irqsave(&host->lock, flags);
4244 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
4245 mmc_detect_change(host->mmc, 0);
4246 spin_unlock_irqrestore(&host->lock, flags);
4247 }
4248};
4249#endif
4250
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304251static void msmsdcc_print_regs(const char *name, void __iomem *base,
4252 u32 phys_base, unsigned int no_of_regs)
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304253{
4254 unsigned int i;
4255
4256 if (!base)
4257 return;
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304258
4259 pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
4260 " =====\n", name, phys_base, (u32)base);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304261 for (i = 0; i < no_of_regs; i = i + 4) {
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304262 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
4263 (u32)readl_relaxed(base + i*4),
4264 (u32)readl_relaxed(base + ((i+1)*4)),
4265 (u32)readl_relaxed(base + ((i+2)*4)),
4266 (u32)readl_relaxed(base + ((i+3)*4)));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304267 }
4268}
4269
4270static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
4271{
4272 /* Dump current state of SDCC clocks, power and irq */
4273 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304274 (host->pwr ? "ON" : "OFF"));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304275 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304276 mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
4277 (u32)clk_get_rate(host->clk));
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304278 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
4279 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
4280
4281 /* Now dump SDCC registers. Don't print FIFO registers */
4282 if (host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304283 msmsdcc_print_regs("SDCC-CORE", host->base,
4284 host->core_memres->start, 28);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304285
4286 if (host->curr.data) {
Subhash Jadavanie6e1b822012-03-12 18:17:58 +05304287 if (!msmsdcc_is_dma_possible(host, host->curr.data))
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304288 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
4289 else if (host->is_dma_mode)
4290 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
4291 mmc_hostname(host->mmc), host->dma.busy,
4292 host->dma.channel, host->dma.crci);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304293 else if (host->is_sps_mode) {
subhashj245831e2012-04-30 18:46:17 +05304294 if (host->sps.busy && host->clks_on)
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304295 msmsdcc_print_regs("SDCC-DML", host->dml_base,
4296 host->dml_memres->start,
4297 16);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304298 pr_info("%s: SPS mode: busy=%d\n",
4299 mmc_hostname(host->mmc), host->sps.busy);
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304300 }
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304301
4302 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
4303 mmc_hostname(host->mmc), host->curr.xfer_size,
4304 host->curr.data_xfered, host->curr.xfer_remain);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304305 }
4306
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304307 pr_info("%s: got_dataend=%d, prog_enable=%d,"
4308 " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
4309 mmc_hostname(host->mmc), host->curr.got_dataend,
4310 host->prog_enable, host->curr.wait_for_auto_prog_done,
4311 host->curr.got_auto_prog_done);
subhashj245831e2012-04-30 18:46:17 +05304312 msmsdcc_print_rpm_info(host);
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304313}
Subhash Jadavani8ce4d2c2012-04-23 18:12:45 +05304314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
4316{
4317 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
4318 struct mmc_request *mrq;
4319 unsigned long flags;
4320
4321 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004322 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004323 pr_info("%s: %s: dummy CMD52 timeout\n",
4324 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07004325 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004326 }
4327
4328 mrq = host->curr.mrq;
4329
4330 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304331 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
4332 mrq->cmd->opcode);
4333 msmsdcc_dump_sdcc_state(host);
4334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004335 if (!mrq->cmd->error)
4336 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05304337 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004339 if (mrq->data && !mrq->data->error)
4340 mrq->data->error = -ETIMEDOUT;
4341 host->curr.data_xfered = 0;
4342 if (host->dma.sg && host->is_dma_mode) {
4343 msm_dmov_stop_cmd(host->dma.channel,
4344 &host->dma.hdr, 0);
4345 } else if (host->sps.sg && host->is_sps_mode) {
4346 /* Stop current SPS transfer */
4347 msmsdcc_sps_exit_curr_xfer(host);
4348 } else {
4349 msmsdcc_reset_and_restore(host);
4350 msmsdcc_stop_data(host);
4351 if (mrq->data && mrq->data->stop)
4352 msmsdcc_start_command(host,
4353 mrq->data->stop, 0);
4354 else
4355 msmsdcc_request_end(host, mrq);
4356 }
4357 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304358 host->prog_enable = 0;
Subhash Jadavanied6b0e42012-03-07 16:36:27 +05304359 host->curr.wait_for_auto_prog_done = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360 msmsdcc_reset_and_restore(host);
4361 msmsdcc_request_end(host, mrq);
4362 }
4363 }
4364 spin_unlock_irqrestore(&host->lock, flags);
4365}
4366
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304367static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
4368{
4369 int i, ret;
4370 struct mmc_platform_data *pdata;
4371 struct device_node *np = dev->of_node;
4372 u32 bus_width = 0;
4373 u32 *clk_table;
4374 int clk_table_len;
4375 u32 *sup_voltages;
4376 int sup_volt_len;
4377
4378 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4379 if (!pdata) {
4380 dev_err(dev, "could not allocate memory for platform data\n");
4381 goto err;
4382 }
4383
4384 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
4385 if (bus_width == 8) {
4386 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
4387 } else if (bus_width == 4) {
4388 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
4389 } else {
4390 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
4391 pdata->mmc_bus_width = 0;
4392 }
4393
4394 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
4395 size_t sz;
4396 sz = sup_volt_len / sizeof(*sup_voltages);
4397 if (sz > 0) {
4398 sup_voltages = devm_kzalloc(dev,
4399 sz * sizeof(*sup_voltages), GFP_KERNEL);
4400 if (!sup_voltages) {
4401 dev_err(dev, "No memory for supported voltage\n");
4402 goto err;
4403 }
4404
4405 ret = of_property_read_u32_array(np,
4406 "qcom,sdcc-sup-voltages", sup_voltages, sz);
4407 if (ret < 0) {
4408 dev_err(dev, "error while reading voltage"
4409 "ranges %d\n", ret);
4410 goto err;
4411 }
4412 } else {
4413 dev_err(dev, "No supported voltages\n");
4414 goto err;
4415 }
4416 for (i = 0; i < sz; i += 2) {
4417 u32 mask;
4418
4419 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
4420 sup_voltages[i + 1]);
4421 if (!mask)
4422 dev_err(dev, "Invalide voltage range %d\n", i);
4423 pdata->ocr_mask |= mask;
4424 }
4425 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
4426 } else {
4427 dev_err(dev, "Supported voltage range not specified\n");
4428 }
4429
4430 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
4431 size_t sz;
4432 sz = clk_table_len / sizeof(*clk_table);
4433
4434 if (sz > 0) {
4435 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
4436 GFP_KERNEL);
4437 if (!clk_table) {
4438 dev_err(dev, "No memory for clock table\n");
4439 goto err;
4440 }
4441
4442 ret = of_property_read_u32_array(np,
4443 "qcom,sdcc-clk-rates", clk_table, sz);
4444 if (ret < 0) {
4445 dev_err(dev, "error while reading clk"
4446 "table %d\n", ret);
4447 goto err;
4448 }
4449 } else {
4450 dev_err(dev, "clk_table not specified\n");
4451 goto err;
4452 }
4453 pdata->sup_clk_table = clk_table;
4454 pdata->sup_clk_cnt = sz;
4455 } else {
4456 dev_err(dev, "Supported clock rates not specified\n");
4457 }
4458
4459 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
4460 pdata->nonremovable = true;
4461 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
4462 pdata->disable_cmd23 = true;
4463
4464 return pdata;
4465err:
4466 return NULL;
4467}
4468
San Mehat9d2bd732009-09-22 16:44:22 -07004469static int
4470msmsdcc_probe(struct platform_device *pdev)
4471{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304472 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07004473 struct msmsdcc_host *host;
4474 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004475 unsigned long flags;
4476 struct resource *core_irqres = NULL;
4477 struct resource *bam_irqres = NULL;
4478 struct resource *core_memres = NULL;
4479 struct resource *dml_memres = NULL;
4480 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07004481 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07004482 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05304483 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004484 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07004485
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304486 if (pdev->dev.of_node) {
4487 plat = msmsdcc_populate_pdata(&pdev->dev);
4488 of_property_read_u32((&pdev->dev)->of_node,
4489 "cell-index", &pdev->id);
4490 } else {
4491 plat = pdev->dev.platform_data;
4492 }
4493
San Mehat9d2bd732009-09-22 16:44:22 -07004494 /* must have platform data */
4495 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004496 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004497 ret = -EINVAL;
4498 goto out;
4499 }
4500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004501 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07004502 return -EINVAL;
4503
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304504 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
4505 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
4506 return -EINVAL;
4507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508
San Mehat9d2bd732009-09-22 16:44:22 -07004509 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004510 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004511 return -ENXIO;
4512 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304513 if (pdev->dev.of_node) {
4514 /*
4515 * Device tree iomem resources are only accessible by index.
4516 * index = 0 -> SDCC register interface
4517 * index = 1 -> DML register interface
4518 * index = 2 -> BAM register interface
4519 * IRQ resources:
4520 * index = 0 -> SDCC IRQ
4521 * index = 1 -> BAM IRQ
4522 */
4523 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4524 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4525 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4526 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4527 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
4528 } else {
4529 for (i = 0; i < pdev->num_resources; i++) {
4530 if (pdev->resource[i].flags & IORESOURCE_MEM) {
4531 if (!strncmp(pdev->resource[i].name,
4532 "sdcc_dml_addr",
4533 sizeof("sdcc_dml_addr")))
4534 dml_memres = &pdev->resource[i];
4535 else if (!strncmp(pdev->resource[i].name,
4536 "sdcc_bam_addr",
4537 sizeof("sdcc_bam_addr")))
4538 bam_memres = &pdev->resource[i];
4539 else
4540 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07004541
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304542 }
4543 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
4544 if (!strncmp(pdev->resource[i].name,
4545 "sdcc_bam_irq",
4546 sizeof("sdcc_bam_irq")))
4547 bam_irqres = &pdev->resource[i];
4548 else
4549 core_irqres = &pdev->resource[i];
4550 }
4551 if (pdev->resource[i].flags & IORESOURCE_DMA) {
4552 if (!strncmp(pdev->resource[i].name,
4553 "sdcc_dma_chnl",
4554 sizeof("sdcc_dma_chnl")))
4555 dmares = &pdev->resource[i];
4556 else if (!strncmp(pdev->resource[i].name,
4557 "sdcc_dma_crci",
4558 sizeof("sdcc_dma_crci")))
4559 dma_crci_res = &pdev->resource[i];
4560 }
Krishna Konda25786ec2011-07-25 16:21:36 -07004561 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004562 }
4563
4564 if (!core_irqres || !core_memres) {
4565 pr_err("%s: Invalid sdcc core resource\n", __func__);
4566 return -ENXIO;
4567 }
4568
4569 /*
4570 * Both BAM and DML memory resource should be preset.
4571 * BAM IRQ resource should also be present.
4572 */
4573 if ((bam_memres && !dml_memres) ||
4574 (!bam_memres && dml_memres) ||
4575 ((bam_memres && dml_memres) && !bam_irqres)) {
4576 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004577 return -ENXIO;
4578 }
4579
4580 /*
4581 * Setup our host structure
4582 */
San Mehat9d2bd732009-09-22 16:44:22 -07004583 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
4584 if (!mmc) {
4585 ret = -ENOMEM;
4586 goto out;
4587 }
4588
4589 host = mmc_priv(mmc);
4590 host->pdev_id = pdev->id;
4591 host->plat = plat;
4592 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08004593 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05304594
4595 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004596 host->is_sps_mode = 1;
4597 else if (dmares)
4598 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07004599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004600 host->base = ioremap(core_memres->start,
4601 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07004602 if (!host->base) {
4603 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004605 }
4606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004607 host->core_irqres = core_irqres;
4608 host->bam_irqres = bam_irqres;
4609 host->core_memres = core_memres;
4610 host->dml_memres = dml_memres;
4611 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07004612 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07004613 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07004614 spin_lock_init(&host->lock);
Asutosh Dasf5298c32012-04-03 14:51:47 +05304615 mutex_init(&host->clk_mutex);
San Mehat9d2bd732009-09-22 16:44:22 -07004616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004617#ifdef CONFIG_MMC_EMBEDDED_SDIO
4618 if (plat->embedded_sdio)
4619 mmc_set_embedded_sdio_data(mmc,
4620 &plat->embedded_sdio->cis,
4621 &plat->embedded_sdio->cccr,
4622 plat->embedded_sdio->funcs,
4623 plat->embedded_sdio->num_funcs);
4624#endif
4625
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304626 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4627 (unsigned long)host);
4628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004629 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4630 (unsigned long)host);
4631 if (host->is_dma_mode) {
4632 /* Setup DMA */
4633 ret = msmsdcc_init_dma(host);
4634 if (ret)
4635 goto ioremap_free;
4636 } else {
4637 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004638 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004639 }
4640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004641 /*
4642 * Setup SDCC clock if derived from Dayatona
4643 * fabric core clock.
4644 */
4645 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004646 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004647 if (!IS_ERR(host->dfab_pclk)) {
4648 /* Set the clock rate to 64MHz for max. performance */
4649 ret = clk_set_rate(host->dfab_pclk, 64000000);
4650 if (ret)
4651 goto dfab_pclk_put;
Asutosh Dasf5298c32012-04-03 14:51:47 +05304652 ret = clk_prepare_enable(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004653 if (ret)
4654 goto dfab_pclk_put;
4655 } else
4656 goto dma_free;
4657 }
4658
4659 /*
4660 * Setup main peripheral bus clock
4661 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004662 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004663 if (!IS_ERR(host->pclk)) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05304664 ret = clk_prepare_enable(host->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665 if (ret)
4666 goto pclk_put;
4667
4668 host->pclk_rate = clk_get_rate(host->pclk);
4669 }
4670
4671 /*
4672 * Setup SDC MMC clock
4673 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004674 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004675 if (IS_ERR(host->clk)) {
4676 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004677 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004678 }
4679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004680 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4681 if (ret) {
4682 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4683 goto clk_put;
4684 }
4685
Asutosh Dasf5298c32012-04-03 14:51:47 +05304686 ret = clk_prepare_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004687 if (ret)
4688 goto clk_put;
4689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004690 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304691 if (!host->clk_rate)
4692 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304693
4694 /*
4695 * Lookup the Controller Version, to identify the supported features
4696 * Version number read as 0 would indicate SDCC3 or earlier versions
4697 */
4698 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4699 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4700 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304701 /*
4702 * Set the register write delay according to min. clock frequency
4703 * supported and update later when the host->clk_rate changes.
4704 */
4705 host->reg_write_delay =
4706 (1 + ((3 * USEC_PER_SEC) /
4707 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004708
4709 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304710 /* Apply Hard reset to SDCC to put it in power on default state */
4711 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004712
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004713#define MSM_MMC_DEFAULT_CPUDMA_LATENCY 200 /* usecs */
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304714 /* pm qos request to prevent apps idle power collapse */
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07004715 if (host->plat->cpu_dma_latency)
4716 host->cpu_dma_latency = host->plat->cpu_dma_latency;
4717 else
4718 host->cpu_dma_latency = MSM_MMC_DEFAULT_CPUDMA_LATENCY;
4719 pm_qos_add_request(&host->pm_qos_req_dma,
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304720 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004722 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004723 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004724 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004725 goto clk_disable;
4726 }
4727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728
4729 /* Clocks has to be running before accessing SPS/DML HW blocks */
4730 if (host->is_sps_mode) {
4731 /* Initialize SPS */
4732 ret = msmsdcc_sps_init(host);
4733 if (ret)
4734 goto vreg_deinit;
4735 /* Initialize DML */
4736 ret = msmsdcc_dml_init(host);
4737 if (ret)
4738 goto sps_exit;
4739 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304740 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004741
San Mehat9d2bd732009-09-22 16:44:22 -07004742 /*
4743 * Setup MMC host structure
4744 */
4745 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004746 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4747 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004748 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004749 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4750 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004751
San Mehat9d2bd732009-09-22 16:44:22 -07004752 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Sujit Reddy Thumma31a45ce2012-03-07 09:43:59 +05304753 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304754
4755 /*
4756 * If we send the CMD23 before multi block write/read command
4757 * then we need not to send CMD12 at the end of the transfer.
4758 * If we don't send the CMD12 then only way to detect the PROG_DONE
4759 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4760 * controller. So let's enable the CMD23 for SDCC4 only.
4761 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304762 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304763 mmc->caps |= MMC_CAP_CMD23;
4764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004765 mmc->caps |= plat->uhs_caps;
4766 /*
4767 * XPC controls the maximum current in the default speed mode of SDXC
4768 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4769 * XPC=1 means 150mA (max.) and speed class is supported.
4770 */
4771 if (plat->xpc_cap)
4772 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4773 MMC_CAP_SET_XPC_180);
4774
Subhash Jadavani6bb34a82012-04-18 13:18:40 +05304775 mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
Subhash Jadavani56e0eaa2012-03-13 18:06:04 +05304776 if (pdev->dev.of_node) {
4777 if (of_get_property((&pdev->dev)->of_node,
4778 "qcom,sdcc-hs200", NULL))
4779 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
4780 }
4781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782 if (plat->nonremovable)
4783 mmc->caps |= MMC_CAP_NONREMOVABLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004784 mmc->caps |= MMC_CAP_SDIO_IRQ;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785
4786 if (plat->is_sdio_al_client)
4787 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004788
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304789 mmc->max_segs = msmsdcc_get_nr_sg(host);
4790 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4791 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004792
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304793 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304794 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796 writel_relaxed(0, host->base + MMCIMASK0);
4797 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
Subhash Jadavanidd432952012-03-28 11:25:56 +05304798 msmsdcc_sync_reg_wr(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004800 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4801 mb();
4802 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004804 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4805 DRIVER_NAME " (cmd)", host);
4806 if (ret)
4807 goto dml_exit;
4808
4809 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4810 DRIVER_NAME " (pio)", host);
4811 if (ret)
4812 goto irq_free;
4813
4814 /*
4815 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4816 * IRQ is un-necessarily being monitored by MPM (Modem power
4817 * management block) during idle-power collapse. The MPM will be
4818 * configured to monitor the DATA1 GPIO line with level-low trigger
4819 * and thus depending on the GPIO status, it prevents TCXO shutdown
4820 * during idle-power collapse.
4821 */
4822 disable_irq(core_irqres->start);
4823 host->sdcc_irq_disabled = 1;
4824
4825 if (plat->sdiowakeup_irq) {
4826 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4827 mmc_hostname(mmc));
4828 ret = request_irq(plat->sdiowakeup_irq,
4829 msmsdcc_platform_sdiowakeup_irq,
4830 IRQF_SHARED | IRQF_TRIGGER_LOW,
4831 DRIVER_NAME "sdiowakeup", host);
4832 if (ret) {
4833 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4834 plat->sdiowakeup_irq, ret);
4835 goto pio_irq_free;
4836 } else {
4837 spin_lock_irqsave(&host->lock, flags);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304838 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004839 disable_irq_nosync(plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05304840 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004841 }
4842 spin_unlock_irqrestore(&host->lock, flags);
4843 }
4844 }
4845
Subhash Jadavanic9b85752012-04-13 11:16:49 +05304846 if (host->plat->mpm_sdiowakeup_int) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004847 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4848 mmc_hostname(mmc));
4849 }
4850
4851 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4852 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004853 /*
4854 * Setup card detect change
4855 */
4856
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004857 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004858 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004859 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004860 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004861 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004862
Krishna Konda941604a2012-01-10 17:46:34 -08004863 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004864 }
San Mehat9d2bd732009-09-22 16:44:22 -07004865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 if (plat->status_irq) {
4867 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004868 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004869 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004870 DRIVER_NAME " (slot)",
4871 host);
4872 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004873 pr_err("Unable to get slot IRQ %d (%d)\n",
4874 plat->status_irq, ret);
4875 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004876 }
4877 } else if (plat->register_status_notify) {
4878 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4879 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004880 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004881 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004882
4883 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004884
4885 ret = pm_runtime_set_active(&(pdev)->dev);
4886 if (ret < 0)
4887 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4888 __func__, ret);
4889 /*
4890 * There is no notion of suspend/resume for SD/MMC/SDIO
4891 * cards. So host can be suspended/resumed with out
4892 * worrying about its children.
4893 */
4894 pm_suspend_ignore_children(&(pdev)->dev, true);
4895
4896 /*
4897 * MMC/SD/SDIO bus suspend/resume operations are defined
4898 * only for the slots that will be used for non-removable
4899 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4900 * defined. Otherwise, they simply become card removal and
4901 * insertion events during suspend and resume respectively.
4902 * Hence, enable run-time PM only for slots for which bus
4903 * suspend/resume operations are defined.
4904 */
4905#ifdef CONFIG_MMC_UNSAFE_RESUME
4906 /*
4907 * If this capability is set, MMC core will enable/disable host
4908 * for every claim/release operation on a host. We use this
4909 * notification to increment/decrement runtime pm usage count.
4910 */
4911 mmc->caps |= MMC_CAP_DISABLE;
4912 pm_runtime_enable(&(pdev)->dev);
4913#else
4914 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4915 mmc->caps |= MMC_CAP_DISABLE;
4916 pm_runtime_enable(&(pdev)->dev);
4917 }
4918#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304919#ifndef CONFIG_PM_RUNTIME
4920 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4921#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004922 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4923 (unsigned long)host);
4924
San Mehat9d2bd732009-09-22 16:44:22 -07004925 mmc_add_host(mmc);
4926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004927#ifdef CONFIG_HAS_EARLYSUSPEND
4928 host->early_suspend.suspend = msmsdcc_early_suspend;
4929 host->early_suspend.resume = msmsdcc_late_resume;
4930 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4931 register_early_suspend(&host->early_suspend);
4932#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004933
Krishna Konda25786ec2011-07-25 16:21:36 -07004934 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4935 " dmacrcri %d\n", mmc_hostname(mmc),
4936 (unsigned long long)core_memres->start,
4937 (unsigned int) core_irqres->start,
4938 (unsigned int) plat->status_irq, host->dma.channel,
4939 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940
4941 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4942 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4943 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4944 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4945 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4946 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4947 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4948 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4949 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4950 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4951 host->eject);
4952 pr_info("%s: Power save feature enable = %d\n",
4953 mmc_hostname(mmc), msmsdcc_pwrsave);
4954
Krishna Konda25786ec2011-07-25 16:21:36 -07004955 if (host->is_dma_mode && host->dma.channel != -1
4956 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004957 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004958 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004959 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004960 mmc_hostname(mmc), host->dma.cmd_busaddr,
4961 host->dma.cmdptr_busaddr);
4962 } else if (host->is_sps_mode) {
4963 pr_info("%s: SPS-BAM data transfer mode available\n",
4964 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004965 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004966 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004968#if defined(CONFIG_DEBUG_FS)
4969 msmsdcc_dbg_createhost(host);
4970#endif
4971 if (!plat->status_irq) {
4972 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4973 if (ret)
4974 goto platform_irq_free;
4975 }
San Mehat9d2bd732009-09-22 16:44:22 -07004976 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977
4978 platform_irq_free:
4979 del_timer_sync(&host->req_tout_timer);
4980 pm_runtime_disable(&(pdev)->dev);
4981 pm_runtime_set_suspended(&(pdev)->dev);
4982
4983 if (plat->status_irq)
4984 free_irq(plat->status_irq, host);
4985 sdiowakeup_irq_free:
4986 wake_lock_destroy(&host->sdio_suspend_wlock);
4987 if (plat->sdiowakeup_irq)
4988 free_irq(plat->sdiowakeup_irq, host);
4989 pio_irq_free:
4990 if (plat->sdiowakeup_irq)
4991 wake_lock_destroy(&host->sdio_wlock);
4992 free_irq(core_irqres->start, host);
4993 irq_free:
4994 free_irq(core_irqres->start, host);
4995 dml_exit:
4996 if (host->is_sps_mode)
4997 msmsdcc_dml_exit(host);
4998 sps_exit:
4999 if (host->is_sps_mode)
5000 msmsdcc_sps_exit(host);
5001 vreg_deinit:
5002 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07005003 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004 clk_disable(host->clk);
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005005 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305006 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07005007 clk_put:
5008 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005009 pclk_disable:
5010 if (!IS_ERR(host->pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305011 clk_disable_unprepare(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07005012 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005013 if (!IS_ERR(host->pclk))
5014 clk_put(host->pclk);
5015 if (!IS_ERR_OR_NULL(host->dfab_pclk))
Asutosh Dasf5298c32012-04-03 14:51:47 +05305016 clk_disable_unprepare(host->dfab_pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005017 dfab_pclk_put:
5018 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5019 clk_put(host->dfab_pclk);
5020 dma_free:
5021 if (host->is_dma_mode) {
5022 if (host->dmares)
5023 dma_free_coherent(NULL,
5024 sizeof(struct msmsdcc_nc_dmadata),
5025 host->dma.nc, host->dma.nc_busaddr);
5026 }
5027 ioremap_free:
5028 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07005029 host_free:
5030 mmc_free_host(mmc);
5031 out:
5032 return ret;
5033}
5034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07005036{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005037 struct mmc_host *mmc = mmc_get_drvdata(pdev);
5038 struct mmc_platform_data *plat;
5039 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005041 if (!mmc)
5042 return -ENXIO;
5043
5044 if (pm_runtime_suspended(&(pdev)->dev))
5045 pm_runtime_resume(&(pdev)->dev);
5046
5047 host = mmc_priv(mmc);
5048
5049 DBG(host, "Removing SDCC device = %d\n", pdev->id);
5050 plat = host->plat;
5051
5052 if (!plat->status_irq)
5053 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
5054
5055 del_timer_sync(&host->req_tout_timer);
5056 tasklet_kill(&host->dma_tlet);
5057 tasklet_kill(&host->sps.tlet);
5058 mmc_remove_host(mmc);
5059
5060 if (plat->status_irq)
5061 free_irq(plat->status_irq, host);
5062
5063 wake_lock_destroy(&host->sdio_suspend_wlock);
5064 if (plat->sdiowakeup_irq) {
5065 wake_lock_destroy(&host->sdio_wlock);
5066 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
5067 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07005068 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005069
5070 free_irq(host->core_irqres->start, host);
5071 free_irq(host->core_irqres->start, host);
5072
5073 clk_put(host->clk);
5074 if (!IS_ERR(host->pclk))
5075 clk_put(host->pclk);
5076 if (!IS_ERR_OR_NULL(host->dfab_pclk))
5077 clk_put(host->dfab_pclk);
5078
Oluwafemi Adeyemi784b4392012-04-10 13:49:38 -07005079 if (host->cpu_dma_latency)
Subhash Jadavani933e6a62011-12-26 18:05:04 +05305080 pm_qos_remove_request(&host->pm_qos_req_dma);
5081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005082 msmsdcc_vreg_init(host, false);
5083
5084 if (host->is_dma_mode) {
5085 if (host->dmares)
5086 dma_free_coherent(NULL,
5087 sizeof(struct msmsdcc_nc_dmadata),
5088 host->dma.nc, host->dma.nc_busaddr);
5089 }
5090
5091 if (host->is_sps_mode) {
5092 msmsdcc_dml_exit(host);
5093 msmsdcc_sps_exit(host);
5094 }
5095
5096 iounmap(host->base);
5097 mmc_free_host(mmc);
5098
5099#ifdef CONFIG_HAS_EARLYSUSPEND
5100 unregister_early_suspend(&host->early_suspend);
5101#endif
5102 pm_runtime_disable(&(pdev)->dev);
5103 pm_runtime_set_suspended(&(pdev)->dev);
5104
5105 return 0;
5106}
5107
5108#ifdef CONFIG_MSM_SDIO_AL
5109int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5110{
5111 struct msmsdcc_host *host = mmc_priv(mmc);
5112 unsigned long flags;
5113
Asutosh Dasf5298c32012-04-03 14:51:47 +05305114 mutex_lock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005115 spin_lock_irqsave(&host->lock, flags);
5116 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
5117 enable ? "En" : "Dis");
5118
5119 if (enable) {
5120 if (!host->sdcc_irq_disabled) {
5121 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05305122 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005123 host->sdcc_irq_disabled = 1;
5124 }
5125
5126 if (host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305127 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005128 msmsdcc_setup_clocks(host, false);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305129 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005130 host->clks_on = 0;
5131 }
5132
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305133 if (host->plat->sdio_lpm_gpio_setup &&
5134 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005135 spin_unlock_irqrestore(&host->lock, flags);
5136 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
5137 spin_lock_irqsave(&host->lock, flags);
5138 host->sdio_gpio_lpm = 1;
5139 }
5140
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305141 if (host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005142 msmsdcc_enable_irq_wake(host);
5143 enable_irq(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305144 host->sdio_wakeupirq_disabled = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005145 }
5146 } else {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305147 if (!host->sdio_wakeupirq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005148 disable_irq_nosync(host->plat->sdiowakeup_irq);
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305149 host->sdio_wakeupirq_disabled = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005150 msmsdcc_disable_irq_wake(host);
5151 }
5152
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05305153 if (host->plat->sdio_lpm_gpio_setup &&
5154 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005155 spin_unlock_irqrestore(&host->lock, flags);
5156 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
5157 spin_lock_irqsave(&host->lock, flags);
5158 host->sdio_gpio_lpm = 0;
5159 }
5160
5161 if (!host->clks_on) {
Asutosh Dasf5298c32012-04-03 14:51:47 +05305162 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005163 msmsdcc_setup_clocks(host, true);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305164 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005165 host->clks_on = 1;
5166 }
5167
5168 if (host->sdcc_irq_disabled) {
5169 writel_relaxed(host->mci_irqenable,
5170 host->base + MMCIMASK0);
5171 mb();
5172 enable_irq(host->core_irqres->start);
5173 host->sdcc_irq_disabled = 0;
5174 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005175 }
5176 spin_unlock_irqrestore(&host->lock, flags);
Asutosh Dasf5298c32012-04-03 14:51:47 +05305177 mutex_unlock(&host->clk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005178 return 0;
5179}
5180#else
5181int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
5182{
5183 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07005184}
5185#endif
5186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005187#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07005188static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005190{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005191 struct mmc_host *mmc = dev_get_drvdata(dev);
5192 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07005193 int rc = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305194 unsigned long flags;
5195
San Mehat9d2bd732009-09-22 16:44:22 -07005196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005197 if (host->plat->is_sdio_al_client)
5198 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05305199 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005200 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005201 host->sdcc_suspending = 1;
5202 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07005203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005204 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005205 * MMC core thinks that host is disabled by now since
5206 * runtime suspend is scheduled after msmsdcc_disable()
5207 * is called. Thus, MMC core will try to enable the host
5208 * while suspending it. This results in a synchronous
5209 * runtime resume request while in runtime suspending
5210 * context and hence inorder to complete this resume
5211 * requet, it will wait for suspend to be complete,
5212 * but runtime suspend also can not proceed further
5213 * until the host is resumed. Thus, it leads to a hang.
5214 * Hence, increase the pm usage count before suspending
5215 * the host so that any resume requests after this will
5216 * simple become pm usage counter increment operations.
5217 */
5218 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305219 /* If there is pending detect work abort runtime suspend */
5220 if (unlikely(work_busy(&mmc->detect.work)))
5221 rc = -EAGAIN;
5222 else
5223 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005224 pm_runtime_put_noidle(dev);
5225
5226 if (!rc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305227 spin_lock_irqsave(&host->lock, flags);
5228 host->sdcc_suspended = true;
5229 spin_unlock_irqrestore(&host->lock, flags);
5230 if (mmc->card && mmc_card_sdio(mmc->card) &&
5231 mmc->ios.clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005232 /*
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305233 * If SDIO function driver doesn't want
5234 * to power off the card, atleast turn off
5235 * clocks to allow deep sleep (TCXO shutdown).
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005236 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305237 mmc_host_clk_hold(mmc);
5238 spin_lock_irqsave(&mmc->clk_lock, flags);
5239 mmc->clk_old = mmc->ios.clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005240 mmc->ios.clock = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305241 mmc->clk_gated = true;
5242 spin_unlock_irqrestore(&mmc->clk_lock, flags);
5243 mmc_set_ios(mmc);
5244 mmc_host_clk_release(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005245 }
5246 }
5247 host->sdcc_suspending = 0;
5248 mmc->suspend_task = NULL;
5249 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
5250 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005251 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05305252 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07005253 return rc;
5254}
5255
5256static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005257msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07005258{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005259 struct mmc_host *mmc = dev_get_drvdata(dev);
5260 struct msmsdcc_host *host = mmc_priv(mmc);
5261 unsigned long flags;
5262
5263 if (host->plat->is_sdio_al_client)
5264 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07005265
Sahitya Tummala7661a452011-07-18 13:28:35 +05305266 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005267 if (mmc) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305268 if (mmc->card && mmc_card_sdio(mmc->card) &&
5269 mmc_card_keep_power(mmc)) {
5270 mmc_host_clk_hold(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305271 mmc->ios.clock = host->clk_rate;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305272 mmc_set_ios(mmc);
5273 mmc_host_clk_release(mmc);
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05305274 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005275
5276 mmc_resume_host(mmc);
5277
5278 /*
5279 * FIXME: Clearing of flags must be handled in clients
5280 * resume handler.
5281 */
5282 spin_lock_irqsave(&host->lock, flags);
5283 mmc->pm_flags = 0;
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305284 host->sdcc_suspended = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005285 spin_unlock_irqrestore(&host->lock, flags);
5286
5287 /*
5288 * After resuming the host wait for sometime so that
5289 * the SDIO work will be processed.
5290 */
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305291 if (mmc->card && mmc_card_sdio(mmc->card)) {
Subhash Jadavanic9b85752012-04-13 11:16:49 +05305292 if ((host->plat->mpm_sdiowakeup_int ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005293 host->plat->sdiowakeup_irq) &&
5294 wake_lock_active(&host->sdio_wlock))
5295 wake_lock_timeout(&host->sdio_wlock, 1);
5296 }
5297
5298 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07005299 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05305300 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07005301 return 0;
5302}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005303
5304static int msmsdcc_runtime_idle(struct device *dev)
5305{
5306 struct mmc_host *mmc = dev_get_drvdata(dev);
5307 struct msmsdcc_host *host = mmc_priv(mmc);
5308
5309 if (host->plat->is_sdio_al_client)
5310 return 0;
5311
5312 /* Idle timeout is not configurable for now */
5313 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
5314
5315 return -EAGAIN;
5316}
5317
5318static int msmsdcc_pm_suspend(struct device *dev)
5319{
5320 struct mmc_host *mmc = dev_get_drvdata(dev);
5321 struct msmsdcc_host *host = mmc_priv(mmc);
5322 int rc = 0;
5323
5324 if (host->plat->is_sdio_al_client)
5325 return 0;
5326
5327
5328 if (host->plat->status_irq)
5329 disable_irq(host->plat->status_irq);
5330
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005331 if (!pm_runtime_suspended(dev))
5332 rc = msmsdcc_runtime_suspend(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005333
5334 return rc;
5335}
5336
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305337static int msmsdcc_suspend_noirq(struct device *dev)
5338{
5339 struct mmc_host *mmc = dev_get_drvdata(dev);
5340 struct msmsdcc_host *host = mmc_priv(mmc);
5341 int rc = 0;
5342
5343 /*
5344 * After platform suspend there may be active request
5345 * which might have enabled clocks. For example, in SDIO
5346 * case, ksdioirq thread might have scheduled after sdcc
5347 * suspend but before system freeze. In that case abort
5348 * suspend and retry instead of keeping the clocks on
5349 * during suspend and not allowing TCXO.
5350 */
5351
Asutosh Dasf5298c32012-04-03 14:51:47 +05305352 if (host->clks_on && !host->plat->is_sdio_al_client) {
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305353 pr_warn("%s: clocks are on after suspend, aborting system "
5354 "suspend\n", mmc_hostname(mmc));
5355 rc = -EAGAIN;
5356 }
5357
5358 return rc;
5359}
5360
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005361static int msmsdcc_pm_resume(struct device *dev)
5362{
5363 struct mmc_host *mmc = dev_get_drvdata(dev);
5364 struct msmsdcc_host *host = mmc_priv(mmc);
5365 int rc = 0;
5366
5367 if (host->plat->is_sdio_al_client)
5368 return 0;
5369
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005370 if (mmc->card && mmc_card_sdio(mmc->card))
Sahitya Tummalafb486372011-09-02 19:01:49 +05305371 rc = msmsdcc_runtime_resume(dev);
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005372 else
5373 host->pending_resume = true;
5374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005375 if (host->plat->status_irq) {
5376 msmsdcc_check_status((unsigned long)host);
5377 enable_irq(host->plat->status_irq);
5378 }
5379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005380 return rc;
5381}
5382
Daniel Walker08ecfde2010-06-23 12:32:20 -07005383#else
Oluwafemi Adeyemi9acea6b2012-04-27 00:12:07 -07005384static int msmsdcc_runtime_suspend(struct device *dev)
5385{
5386 return 0;
5387}
5388static int msmsdcc_runtime_idle(struct device *dev)
5389{
5390 return 0;
5391}
5392static int msmsdcc_pm_suspend(struct device *dev)
5393{
5394 return 0;
5395}
5396static int msmsdcc_pm_resume(struct device *dev)
5397{
5398 return 0;
5399}
5400static int msmsdcc_suspend_noirq(struct device *dev)
5401{
5402 return 0;
5403}
5404static int msmsdcc_runtime_resume(struct device *dev)
5405{
5406 return 0;
5407}
Daniel Walker08ecfde2010-06-23 12:32:20 -07005408#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005410static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
5411 .runtime_suspend = msmsdcc_runtime_suspend,
5412 .runtime_resume = msmsdcc_runtime_resume,
5413 .runtime_idle = msmsdcc_runtime_idle,
5414 .suspend = msmsdcc_pm_suspend,
5415 .resume = msmsdcc_pm_resume,
Sujit Reddy Thummaf4a999c2012-02-09 23:14:45 +05305416 .suspend_noirq = msmsdcc_suspend_noirq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005417};
5418
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305419static const struct of_device_id msmsdcc_dt_match[] = {
5420 {.compatible = "qcom,msm-sdcc"},
5421
5422};
5423MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
5424
San Mehat9d2bd732009-09-22 16:44:22 -07005425static struct platform_driver msmsdcc_driver = {
5426 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005427 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07005428 .driver = {
5429 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005430 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05305431 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07005432 },
5433};
5434
5435static int __init msmsdcc_init(void)
5436{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005437#if defined(CONFIG_DEBUG_FS)
5438 int ret = 0;
5439 ret = msmsdcc_dbg_init();
5440 if (ret) {
5441 pr_err("Failed to create debug fs dir \n");
5442 return ret;
5443 }
5444#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005445 return platform_driver_register(&msmsdcc_driver);
5446}
5447
5448static void __exit msmsdcc_exit(void)
5449{
5450 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005451
5452#if defined(CONFIG_DEBUG_FS)
5453 debugfs_remove(debugfs_file);
5454 debugfs_remove(debugfs_dir);
5455#endif
San Mehat9d2bd732009-09-22 16:44:22 -07005456}
5457
5458module_init(msmsdcc_init);
5459module_exit(msmsdcc_exit);
5460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005461MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07005462MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005463
5464#if defined(CONFIG_DEBUG_FS)
5465
5466static int
5467msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
5468{
5469 file->private_data = inode->i_private;
5470 return 0;
5471}
5472
5473static ssize_t
5474msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
5475 size_t count, loff_t *ppos)
5476{
5477 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08005478 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005479 int max, i;
5480
5481 i = 0;
5482 max = sizeof(buf) - 1;
5483
5484 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
5485 host->curr.cmd, host->curr.data);
5486 if (host->curr.cmd) {
5487 struct mmc_command *cmd = host->curr.cmd;
5488
5489 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
5490 cmd->opcode, cmd->arg, cmd->flags);
5491 }
5492 if (host->curr.data) {
5493 struct mmc_data *data = host->curr.data;
5494 i += scnprintf(buf + i, max - i,
5495 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
5496 data->timeout_ns, data->timeout_clks,
5497 data->blksz, data->blocks, data->error,
5498 data->flags);
5499 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
5500 host->curr.xfer_size, host->curr.xfer_remain,
5501 host->curr.data_xfered, host->dma.sg);
5502 }
5503
5504 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
5505}
5506
5507static const struct file_operations msmsdcc_dbg_state_ops = {
5508 .read = msmsdcc_dbg_state_read,
5509 .open = msmsdcc_dbg_state_open,
5510};
5511
5512static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
5513{
5514 if (debugfs_dir) {
5515 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
5516 0644, debugfs_dir, host,
5517 &msmsdcc_dbg_state_ops);
5518 }
5519}
5520
5521static int __init msmsdcc_dbg_init(void)
5522{
5523 int err;
5524
5525 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
5526 if (IS_ERR(debugfs_dir)) {
5527 err = PTR_ERR(debugfs_dir);
5528 debugfs_dir = NULL;
5529 return err;
5530 }
5531
5532 return 0;
5533}
5534#endif