blob: 3cffd65f91185c3587605035e726da82880786cd [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>
San Mehat9d2bd732009-09-22 16:44:22 -070046
47#include <asm/cacheflush.h>
48#include <asm/div64.h>
49#include <asm/sizes.h>
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070052#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053053#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054#include <mach/dma.h>
55#include <mach/htc_pwrsink.h>
56#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070057
San Mehat9d2bd732009-09-22 16:44:22 -070058#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070060
61#define DRIVER_NAME "msm-sdcc"
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define DBG(host, fmt, args...) \
64 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
65
66#define IRQ_DEBUG 0
67#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
68#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
69#define SPS_CONS_PERIPHERAL 0
70#define SPS_PROD_PERIPHERAL 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72#if defined(CONFIG_DEBUG_FS)
73static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
74static struct dentry *debugfs_dir;
75static struct dentry *debugfs_file;
76static int msmsdcc_dbg_init(void);
77#endif
78
Subhash Jadavani8766e352011-11-30 11:30:32 +053079static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070080static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082static struct mmc_command dummy52cmd;
83static struct mmc_request dummy52mrq = {
84 .cmd = &dummy52cmd,
85 .data = NULL,
86 .stop = NULL,
87};
88static struct mmc_command dummy52cmd = {
89 .opcode = SD_IO_RW_DIRECT,
90 .flags = MMC_RSP_PRESENT,
91 .data = NULL,
92 .mrq = &dummy52mrq,
93};
94/*
95 * An array holding the Tuning pattern to compare with when
96 * executing a tuning cycle.
97 */
98static const u32 cmd19_tuning_block[16] = {
99 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
100 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
101 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
102 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
103};
San Mehat865c8062009-11-13 13:42:06 -0800104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105#if IRQ_DEBUG == 1
106static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
107 "dattimeout", "txunderrun", "rxoverrun",
108 "cmdrespend", "cmdsent", "dataend", NULL,
109 "datablkend", "cmdactive", "txactive",
110 "rxactive", "txhalfempty", "rxhalffull",
111 "txfifofull", "rxfifofull", "txfifoempty",
112 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
113 "sdiointr", "progdone", "atacmdcompl",
114 "sdiointrope", "ccstimeout", NULL, NULL,
115 NULL, NULL, NULL };
116
117static void
118msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800119{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
123 for (i = 0; i < 32; i++) {
124 if (status & (1 << i))
125 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800128}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129#endif
San Mehat865c8062009-11-13 13:42:06 -0800130
San Mehat9d2bd732009-09-22 16:44:22 -0700131static void
132msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
133 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530134static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530135static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530136
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530137static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
138{
139 unsigned short ret = NR_SG;
140
141 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530142 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530143 } else { /* DMA or PIO mode */
144 if (NR_SG > MAX_NR_SG_DMA_PIO)
145 ret = MAX_NR_SG_DMA_PIO;
146 }
147
148 return ret;
149}
150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
152static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
153 struct msmsdcc_sps_ep_conn_data *ep);
154static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
155 struct msmsdcc_sps_ep_conn_data *ep);
156#else
157static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
158 struct msmsdcc_sps_ep_conn_data *ep,
159 bool is_producer) { return 0; }
160static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
161 struct msmsdcc_sps_ep_conn_data *ep) { }
162static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
163 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530164{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 return 0;
166}
167static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
168 struct msmsdcc_sps_ep_conn_data *ep)
169{
170 return 0;
171}
172static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
173static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
174#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530177 * Apply soft reset to all SDCC BAM pipes
178 *
179 * This function applies soft reset to SDCC BAM pipe.
180 *
181 * This function should be called to recover from error
182 * conditions encountered during CMD/DATA tranfsers with card.
183 *
184 * @host - Pointer to driver's host structure
185 *
186 */
187static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
188{
189 int rc;
190
191 /* Reset all SDCC BAM pipes */
192 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
193 if (rc)
194 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
195 mmc_hostname(host->mmc), rc);
196 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
197 if (rc)
198 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
199 mmc_hostname(host->mmc), rc);
200
201 /* Restore all BAM pipes connections */
202 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
203 if (rc)
204 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
205 mmc_hostname(host->mmc), rc);
206 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
207 if (rc)
208 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
209 mmc_hostname(host->mmc), rc);
210}
211
212/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 * Apply soft reset
214 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530215 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 *
217 * This function should be called to recover from error
218 * conditions encountered with CMD/DATA tranfsers with card.
219 *
220 * Soft reset should only be used with SDCC controller v4.
221 *
222 * @host - Pointer to driver's host structure
223 *
224 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530225static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 /*
228 * Reset SDCC controller's DPSM (data path state machine
229 * and CPSM (command path state machine).
230 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530232 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530234 msmsdcc_delay(host);
235}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530236
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530237static void msmsdcc_hard_reset(struct msmsdcc_host *host)
238{
239 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530240
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530241 /* Reset the controller */
242 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
243 if (ret)
244 pr_err("%s: Clock assert failed at %u Hz"
245 " with err %d\n", mmc_hostname(host->mmc),
246 host->clk_rate, ret);
247
248 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
249 if (ret)
250 pr_err("%s: Clock deassert failed at %u Hz"
251 " with err %d\n", mmc_hostname(host->mmc),
252 host->clk_rate, ret);
253
254 /* Give some delay for clock reset to propogate to controller */
255 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530256}
257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
259{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530260 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530261 if (host->is_sps_mode) {
262 /* Reset DML first */
263 msmsdcc_dml_reset(host);
264 /*
265 * delay the SPS pipe reset in thread context as
266 * sps_connect/sps_disconnect APIs can be called
267 * only from non-atomic context.
268 */
269 host->sps.pipe_reset_pending = true;
270 }
271 mb();
272 msmsdcc_soft_reset(host);
273
274 pr_debug("%s: Applied soft reset to Controller\n",
275 mmc_hostname(host->mmc));
276
277 if (host->is_sps_mode)
278 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 } else {
280 /* Give Clock reset (hard reset) to controller */
281 u32 mci_clk = 0;
282 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283
284 /* Save the controller state */
285 mci_clk = readl_relaxed(host->base + MMCICLOCK);
286 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530289 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 pr_debug("%s: Controller has been reinitialized\n",
291 mmc_hostname(host->mmc));
292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 /* Restore the contoller state */
294 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530295 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530297 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530299 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530301
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700302 if (host->dummy_52_needed)
303 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304}
305
306static int
San Mehat9d2bd732009-09-22 16:44:22 -0700307msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
308{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 int retval = 0;
310
San Mehat9d2bd732009-09-22 16:44:22 -0700311 BUG_ON(host->curr.data);
312
313 host->curr.mrq = NULL;
314 host->curr.cmd = NULL;
315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 del_timer(&host->req_tout_timer);
317
San Mehat9d2bd732009-09-22 16:44:22 -0700318 if (mrq->data)
319 mrq->data->bytes_xfered = host->curr.data_xfered;
320 if (mrq->cmd->error == -ETIMEDOUT)
321 mdelay(5);
322
323 /*
324 * Need to drop the host lock here; mmc_request_done may call
325 * back into the driver...
326 */
327 spin_unlock(&host->lock);
328 mmc_request_done(host->mmc, mrq);
329 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330
331 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700332}
333
334static void
335msmsdcc_stop_data(struct msmsdcc_host *host)
336{
San Mehat9d2bd732009-09-22 16:44:22 -0700337 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530338 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530339 host->curr.wait_for_auto_prog_done = 0;
340 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700341 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
342 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700343 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700344}
345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700347{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 return host->core_memres->start + MMCIFIFO;
349}
350
351static inline unsigned int msmsdcc_get_min_sup_clk_rate(
352 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static inline void msmsdcc_delay(struct msmsdcc_host *host)
355{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530356 ktime_t start, diff;
357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530359 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530360
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530361 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530362 (readl_relaxed(host->base + MCI_STATUS2) &
363 MCI_MCLK_REG_WR_ACTIVE)) {
364 start = ktime_get();
365 while (readl_relaxed(host->base + MCI_STATUS2) &
366 MCI_MCLK_REG_WR_ACTIVE) {
367 diff = ktime_sub(ktime_get(), start);
368 /* poll for max. 1 ms */
369 if (ktime_to_us(diff) > 1000) {
370 pr_warning("%s: previous reg. write is"
371 " still active\n",
372 mmc_hostname(host->mmc));
373 break;
374 }
375 }
376 }
San Mehat9d2bd732009-09-22 16:44:22 -0700377}
378
San Mehat56a8b5b2009-11-21 12:29:46 -0800379static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
381{
382 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530384 /*
385 * As after sending the command, we don't write any of the
386 * controller registers and just wait for the
387 * CMD_RESPOND_END/CMD_SENT/Command failure notication
388 * from Controller.
389 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800391}
392
393static void
394msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
395{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
399 writel_relaxed((unsigned int)host->curr.xfer_size,
400 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
402 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800403
San Mehat6ac9ea62009-12-02 17:24:58 -0800404 if (host->cmd_cmd) {
405 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800407 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800408}
409
San Mehat9d2bd732009-09-22 16:44:22 -0700410static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530411msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700412{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530413 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700414 unsigned long flags;
415 struct mmc_request *mrq;
416
417 spin_lock_irqsave(&host->lock, flags);
418 mrq = host->curr.mrq;
419 BUG_ON(!mrq);
420
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530421 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700422 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700423 goto out;
424 }
425
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530426 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700427 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700429 } else {
430 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530431 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700432 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530433 mmc_hostname(host->mmc), host->dma.result);
434 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700435 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530436 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530437 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 host->dma.err.flush[0], host->dma.err.flush[1],
439 host->dma.err.flush[2], host->dma.err.flush[3],
440 host->dma.err.flush[4],
441 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530442 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700443 if (!mrq->data->error)
444 mrq->data->error = -EIO;
445 }
San Mehat9d2bd732009-09-22 16:44:22 -0700446 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
447 host->dma.dir);
448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 if (host->curr.user_pages) {
450 struct scatterlist *sg = host->dma.sg;
451 int i;
452
453 for (i = 0; i < host->dma.num_ents; i++, sg++)
454 flush_dcache_page(sg_page(sg));
455 }
456
San Mehat9d2bd732009-09-22 16:44:22 -0700457 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800458 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700459
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530460 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
461 (host->curr.wait_for_auto_prog_done &&
462 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700463 /*
464 * If we've already gotten our DATAEND / DATABLKEND
465 * for this request, then complete it through here.
466 */
San Mehat9d2bd732009-09-22 16:44:22 -0700467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 if (!mrq->data->error) {
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;
471 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700472 if (host->dummy_52_needed) {
473 mrq->data->bytes_xfered = host->curr.data_xfered;
474 host->dummy_52_sent = 1;
475 msmsdcc_start_command(host, &dummy52cmd,
476 MCI_CPSM_PROGENA);
477 goto out;
478 }
479 msmsdcc_stop_data(host);
Sujit Reddy Thumma521cdce2011-12-30 16:27:52 +0530480
481 if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
482 || !mrq->sbc)) {
483 msmsdcc_start_command(host, mrq->data->stop, 0);
484 } else if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530485 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700486 host->curr.mrq = NULL;
487 host->curr.cmd = NULL;
488 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700490 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491
San Mehat9d2bd732009-09-22 16:44:22 -0700492 mmc_request_done(host->mmc, mrq);
493 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530494 }
San Mehat9d2bd732009-09-22 16:44:22 -0700495 }
496
497out:
498 spin_unlock_irqrestore(&host->lock, flags);
499 return;
500}
501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
503/**
504 * Callback notification from SPS driver
505 *
506 * This callback function gets triggered called from
507 * SPS driver when requested SPS data transfer is
508 * completed.
509 *
510 * SPS driver invokes this callback in BAM irq context so
511 * SDCC driver schedule a tasklet for further processing
512 * this callback notification at later point of time in
513 * tasklet context and immediately returns control back
514 * to SPS driver.
515 *
516 * @nofity - Pointer to sps event notify sturcture
517 *
518 */
519static void
520msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
521{
522 struct msmsdcc_host *host =
523 (struct msmsdcc_host *)
524 ((struct sps_event_notify *)notify)->user;
525
526 host->sps.notify = *notify;
527 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
528 mmc_hostname(host->mmc), __func__, notify->event_id,
529 notify->data.transfer.iovec.addr,
530 notify->data.transfer.iovec.size,
531 notify->data.transfer.iovec.flags);
532 /* Schedule a tasklet for completing data transfer */
533 tasklet_schedule(&host->sps.tlet);
534}
535
536/**
537 * Tasklet handler for processing SPS callback event
538 *
539 * This function processing SPS event notification and
540 * checks if the SPS transfer is completed or not and
541 * then accordingly notifies status to MMC core layer.
542 *
543 * This function is called in tasklet context.
544 *
545 * @data - Pointer to sdcc driver data
546 *
547 */
548static void msmsdcc_sps_complete_tlet(unsigned long data)
549{
550 unsigned long flags;
551 int i, rc;
552 u32 data_xfered = 0;
553 struct mmc_request *mrq;
554 struct sps_iovec iovec;
555 struct sps_pipe *sps_pipe_handle;
556 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
557 struct sps_event_notify *notify = &host->sps.notify;
558
559 spin_lock_irqsave(&host->lock, flags);
560 if (host->sps.dir == DMA_FROM_DEVICE)
561 sps_pipe_handle = host->sps.prod.pipe_handle;
562 else
563 sps_pipe_handle = host->sps.cons.pipe_handle;
564 mrq = host->curr.mrq;
565
566 if (!mrq) {
567 spin_unlock_irqrestore(&host->lock, flags);
568 return;
569 }
570
571 pr_debug("%s: %s: sps event_id=%d\n",
572 mmc_hostname(host->mmc), __func__,
573 notify->event_id);
574
575 if (msmsdcc_is_dml_busy(host)) {
576 /* oops !!! this should never happen. */
577 pr_err("%s: %s: Received SPS EOT event"
578 " but DML HW is still busy !!!\n",
579 mmc_hostname(host->mmc), __func__);
580 }
581 /*
582 * Got End of transfer event!!! Check if all of the data
583 * has been transferred?
584 */
585 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
586 rc = sps_get_iovec(sps_pipe_handle, &iovec);
587 if (rc) {
588 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
589 mmc_hostname(host->mmc), __func__, rc, i);
590 break;
591 }
592 data_xfered += iovec.size;
593 }
594
595 if (data_xfered == host->curr.xfer_size) {
596 host->curr.data_xfered = host->curr.xfer_size;
597 host->curr.xfer_remain -= host->curr.xfer_size;
598 pr_debug("%s: Data xfer success. data_xfered=0x%x",
599 mmc_hostname(host->mmc),
600 host->curr.xfer_size);
601 } else {
602 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
603 " xfer_size=%d", mmc_hostname(host->mmc),
604 data_xfered, host->curr.xfer_size);
605 msmsdcc_reset_and_restore(host);
606 if (!mrq->data->error)
607 mrq->data->error = -EIO;
608 }
609
610 /* Unmap sg buffers */
611 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
612 host->sps.dir);
613
614 host->sps.sg = NULL;
615 host->sps.busy = 0;
616
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530617 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
618 (host->curr.wait_for_auto_prog_done &&
619 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 /*
621 * If we've already gotten our DATAEND / DATABLKEND
622 * for this request, then complete it through here.
623 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624
625 if (!mrq->data->error) {
626 host->curr.data_xfered = host->curr.xfer_size;
627 host->curr.xfer_remain -= host->curr.xfer_size;
628 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700629 if (host->dummy_52_needed) {
630 mrq->data->bytes_xfered = host->curr.data_xfered;
631 host->dummy_52_sent = 1;
632 msmsdcc_start_command(host, &dummy52cmd,
633 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700634 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700635 return;
636 }
637 msmsdcc_stop_data(host);
Sujit Reddy Thumma521cdce2011-12-30 16:27:52 +0530638 if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
639 || !mrq->sbc)) {
640 msmsdcc_start_command(host, mrq->data->stop, 0);
641 } else if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530642 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643 host->curr.mrq = NULL;
644 host->curr.cmd = NULL;
645 mrq->data->bytes_xfered = host->curr.data_xfered;
646 del_timer(&host->req_tout_timer);
647 spin_unlock_irqrestore(&host->lock, flags);
648
649 mmc_request_done(host->mmc, mrq);
650 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 }
652 }
653 spin_unlock_irqrestore(&host->lock, flags);
654}
655
656/**
657 * Exit from current SPS data transfer
658 *
659 * This function exits from current SPS data transfer.
660 *
661 * This function should be called when error condition
662 * is encountered during data transfer.
663 *
664 * @host - Pointer to sdcc host structure
665 *
666 */
667static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
668{
669 struct mmc_request *mrq;
670
671 mrq = host->curr.mrq;
672 BUG_ON(!mrq);
673
674 msmsdcc_reset_and_restore(host);
675 if (!mrq->data->error)
676 mrq->data->error = -EIO;
677
678 /* Unmap sg buffers */
679 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
680 host->sps.dir);
681
682 host->sps.sg = NULL;
683 host->sps.busy = 0;
684 if (host->curr.data)
685 msmsdcc_stop_data(host);
686
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530687 if (!mrq->data->stop || mrq->cmd->error ||
688 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530690 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
691 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 msmsdcc_start_command(host, mrq->data->stop, 0);
693
694}
695#else
696static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
697static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
698static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
699#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
700
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530701static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530703static void
704msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
705 unsigned int result,
706 struct msm_dmov_errdata *err)
707{
708 struct msmsdcc_dma_data *dma_data =
709 container_of(cmd, struct msmsdcc_dma_data, hdr);
710 struct msmsdcc_host *host = dma_data->host;
711
712 dma_data->result = result;
713 if (err)
714 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
715
716 tasklet_schedule(&host->dma_tlet);
717}
718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700720{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
722 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700723 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 else
725 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700726}
727
728static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
729{
730 struct msmsdcc_nc_dmadata *nc;
731 dmov_box *box;
732 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700733 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530734 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700735 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530736 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700737
Krishna Konda25786ec2011-07-25 16:21:36 -0700738 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700740
Krishna Konda25786ec2011-07-25 16:21:36 -0700741 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
742
San Mehat9d2bd732009-09-22 16:44:22 -0700743 host->dma.sg = data->sg;
744 host->dma.num_ents = data->sg_len;
745
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530746 /* Prevent memory corruption */
747 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800748
San Mehat9d2bd732009-09-22 16:44:22 -0700749 nc = host->dma.nc;
750
San Mehat9d2bd732009-09-22 16:44:22 -0700751 if (data->flags & MMC_DATA_READ)
752 host->dma.dir = DMA_FROM_DEVICE;
753 else
754 host->dma.dir = DMA_TO_DEVICE;
755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
757 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758
759 if (n != host->dma.num_ents) {
760 pr_err("%s: Unable to map in all sg elements\n",
761 mmc_hostname(host->mmc));
762 host->dma.sg = NULL;
763 host->dma.num_ents = 0;
764 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800765 }
San Mehat9d2bd732009-09-22 16:44:22 -0700766
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530767 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
768 host->curr.user_pages = 0;
769 box = &nc->cmd[0];
770 for (i = 0; i < host->dma.num_ents; i++) {
771 len = sg_dma_len(sg);
772 offset = 0;
773
774 do {
775 /* Check if we can do DMA */
776 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
777 err = -ENOTSUPP;
778 goto unmap;
779 }
780
781 box->cmd = CMD_MODE_BOX;
782
783 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
784 len = MMC_MAX_DMA_BOX_LENGTH;
785 len -= len % data->blksz;
786 }
787 rows = (len % MCI_FIFOSIZE) ?
788 (len / MCI_FIFOSIZE) + 1 :
789 (len / MCI_FIFOSIZE);
790
791 if (data->flags & MMC_DATA_READ) {
792 box->src_row_addr = msmsdcc_fifo_addr(host);
793 box->dst_row_addr = sg_dma_address(sg) + offset;
794 box->src_dst_len = (MCI_FIFOSIZE << 16) |
795 (MCI_FIFOSIZE);
796 box->row_offset = MCI_FIFOSIZE;
797 box->num_rows = rows * ((1 << 16) + 1);
798 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
799 } else {
800 box->src_row_addr = sg_dma_address(sg) + offset;
801 box->dst_row_addr = msmsdcc_fifo_addr(host);
802 box->src_dst_len = (MCI_FIFOSIZE << 16) |
803 (MCI_FIFOSIZE);
804 box->row_offset = (MCI_FIFOSIZE << 16);
805 box->num_rows = rows * ((1 << 16) + 1);
806 box->cmd |= CMD_DST_CRCI(host->dma.crci);
807 }
808
809 offset += len;
810 len = sg_dma_len(sg) - offset;
811 box++;
812 box_cmd_cnt++;
813 } while (len);
814 sg++;
815 }
816 /* Mark last command */
817 box--;
818 box->cmd |= CMD_LC;
819
820 /* location of command block must be 64 bit aligned */
821 BUG_ON(host->dma.cmd_busaddr & 0x07);
822
823 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
824 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
825 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
826 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
827
828 /* Flush all data to memory before starting dma */
829 mb();
830
831unmap:
832 if (err) {
833 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
834 host->dma.num_ents, host->dma.dir);
835 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
836 mmc_hostname(host->mmc), err);
837 }
838
839 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700840}
841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
843/**
844 * Submits data transfer request to SPS driver
845 *
846 * This function make sg (scatter gather) data buffers
847 * DMA ready and then submits them to SPS driver for
848 * transfer.
849 *
850 * @host - Pointer to sdcc host structure
851 * @data - Pointer to mmc_data structure
852 *
853 * @return 0 if success else negative value
854 */
855static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
856 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800857{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858 int rc = 0;
859 u32 flags;
860 int i;
861 u32 addr, len, data_cnt;
862 struct scatterlist *sg = data->sg;
863 struct sps_pipe *sps_pipe_handle;
864
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530865 /* Prevent memory corruption */
866 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867
868 host->sps.sg = data->sg;
869 host->sps.num_ents = data->sg_len;
870 host->sps.xfer_req_cnt = 0;
871 if (data->flags & MMC_DATA_READ) {
872 host->sps.dir = DMA_FROM_DEVICE;
873 sps_pipe_handle = host->sps.prod.pipe_handle;
874 } else {
875 host->sps.dir = DMA_TO_DEVICE;
876 sps_pipe_handle = host->sps.cons.pipe_handle;
877 }
878
879 /* Make sg buffers DMA ready */
880 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
881 host->sps.dir);
882
883 if (rc != data->sg_len) {
884 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
885 mmc_hostname(host->mmc), rc);
886 host->sps.sg = NULL;
887 host->sps.num_ents = 0;
888 rc = -ENOMEM;
889 goto dma_map_err;
890 }
891
892 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
893 mmc_hostname(host->mmc), __func__,
894 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
895 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
896
897 for (i = 0; i < data->sg_len; i++) {
898 /*
899 * Check if this is the last buffer to transfer?
900 * If yes then set the INT and EOT flags.
901 */
902 len = sg_dma_len(sg);
903 addr = sg_dma_address(sg);
904 flags = 0;
905 while (len > 0) {
906 if (len > SPS_MAX_DESC_SIZE) {
907 data_cnt = SPS_MAX_DESC_SIZE;
908 } else {
909 data_cnt = len;
910 if (i == data->sg_len - 1)
911 flags = SPS_IOVEC_FLAG_INT |
912 SPS_IOVEC_FLAG_EOT;
913 }
914 rc = sps_transfer_one(sps_pipe_handle, addr,
915 data_cnt, host, flags);
916 if (rc) {
917 pr_err("%s: sps_transfer_one() error! rc=%d,"
918 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
919 mmc_hostname(host->mmc), rc,
920 (u32)sps_pipe_handle, (u32)sg, i);
921 goto dma_map_err;
922 }
923 addr += data_cnt;
924 len -= data_cnt;
925 host->sps.xfer_req_cnt++;
926 }
927 sg++;
928 }
929 goto out;
930
931dma_map_err:
932 /* unmap sg buffers */
933 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
934 host->sps.dir);
935out:
936 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700937}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938#else
939static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
940 struct mmc_data *data) { return 0; }
941#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700942
943static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800944msmsdcc_start_command_deferred(struct msmsdcc_host *host,
945 struct mmc_command *cmd, u32 *c)
946{
Sujit Reddy Thumma521cdce2011-12-30 16:27:52 +0530947 DBG(host, "op %d arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 cmd->opcode, cmd->arg, cmd->flags);
949
San Mehat56a8b5b2009-11-21 12:29:46 -0800950 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
951
952 if (cmd->flags & MMC_RSP_PRESENT) {
953 if (cmd->flags & MMC_RSP_136)
954 *c |= MCI_CPSM_LONGRSP;
955 *c |= MCI_CPSM_RESPONSE;
956 }
957
958 if (/*interrupt*/0)
959 *c |= MCI_CPSM_INTERRUPT;
960
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530961 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
962 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
963 cmd->opcode == MMC_WRITE_BLOCK ||
964 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
965 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800966 *c |= MCI_CSPM_DATCMD;
967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530969 if (host->tuning_needed) {
970 /*
971 * For open ended block read operation (without CMD23),
972 * AUTO_CMD19 bit should be set while sending the READ command.
973 * For close ended block read operation (with CMD23),
974 * AUTO_CMD19 bit should be set while sending CMD23.
975 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530976 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
977 host->curr.mrq->cmd->opcode ==
978 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530979 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530980 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
981 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530982 msmsdcc_enable_cdr_cm_sdc4_dll(host);
983 *c |= MCI_CSPM_AUTO_CMD19;
984 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 }
986
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530987 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530988 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530990 }
991
San Mehat56a8b5b2009-11-21 12:29:46 -0800992 if (cmd == cmd->mrq->stop)
993 *c |= MCI_CSPM_MCIABORT;
994
San Mehat56a8b5b2009-11-21 12:29:46 -0800995 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 pr_err("%s: Overlapping command requests\n",
997 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800998 }
999 host->curr.cmd = cmd;
1000}
1001
1002static void
1003msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1004 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001005{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301006 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001007 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001008 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001009 unsigned int pio_irqmask = 0;
1010
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301011 BUG_ON(!data->sg);
1012 BUG_ON(!data->sg_len);
1013
San Mehat9d2bd732009-09-22 16:44:22 -07001014 host->curr.data = data;
1015 host->curr.xfer_size = data->blksz * data->blocks;
1016 host->curr.xfer_remain = host->curr.xfer_size;
1017 host->curr.data_xfered = 0;
1018 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301019 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001020
1021 memset(&host->pio, 0, sizeof(host->pio));
1022
San Mehat9d2bd732009-09-22 16:44:22 -07001023 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1024
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301025 if (host->curr.wait_for_auto_prog_done)
1026 datactrl |= MCI_AUTO_PROG_DONE;
1027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 if (!msmsdcc_check_dma_op_req(data)) {
1029 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1030 datactrl |= MCI_DPSM_DMAENABLE;
1031 } else if (host->is_sps_mode) {
1032 if (!msmsdcc_is_dml_busy(host)) {
1033 if (!msmsdcc_sps_start_xfer(host, data)) {
1034 /* Now kick start DML transfer */
1035 mb();
1036 msmsdcc_dml_start_xfer(host, data);
1037 datactrl |= MCI_DPSM_DMAENABLE;
1038 host->sps.busy = 1;
1039 }
1040 } else {
1041 /*
1042 * Can't proceed with new transfer as
1043 * previous trasnfer is already in progress.
1044 * There is no point of going into PIO mode
1045 * as well. Is this a time to do kernel panic?
1046 */
1047 pr_err("%s: %s: DML HW is busy!!!"
1048 " Can't perform new SPS transfers"
1049 " now\n", mmc_hostname(host->mmc),
1050 __func__);
1051 }
1052 }
1053 }
1054
1055 /* Is data transfer in PIO mode required? */
1056 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001057 host->pio.sg = data->sg;
1058 host->pio.sg_len = data->sg_len;
1059 host->pio.sg_off = 0;
1060
1061 if (data->flags & MMC_DATA_READ) {
1062 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1063 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1064 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1065 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1067 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001068 }
1069
1070 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301071 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001072
San Mehat56a8b5b2009-11-21 12:29:46 -08001073 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001075 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1078 /* Use ADM (Application Data Mover) HW for Data transfer */
1079 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001080 host->cmd_timeout = timeout;
1081 host->cmd_pio_irqmask = pio_irqmask;
1082 host->cmd_datactrl = datactrl;
1083 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1086 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001087 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001088
1089 if (cmd) {
1090 msmsdcc_start_command_deferred(host, cmd, &c);
1091 host->cmd_c = c;
1092 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1094 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1095 host->base + MMCIMASK0);
1096 mb();
1097 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001098 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1105 (~(MCI_IRQ_PIO))) | pio_irqmask,
1106 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301108 /*
1109 * We don't need delay after writing to DATA_CTRL register
1110 * if we are not writing to CMD register immediately after
1111 * this. As we already have delay before sending the
1112 * command, we just need mb() here.
1113 */
1114 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001115
1116 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001118 /* Daisy-chain the command if requested */
1119 msmsdcc_start_command(host, cmd, c);
1120 }
San Mehat9d2bd732009-09-22 16:44:22 -07001121 }
1122}
1123
1124static void
1125msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1126{
San Mehat56a8b5b2009-11-21 12:29:46 -08001127 msmsdcc_start_command_deferred(host, cmd, &c);
1128 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001129}
1130
1131static void
1132msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1133 unsigned int status)
1134{
1135 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1137 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1138 pr_err("%s: Data CRC error\n",
1139 mmc_hostname(host->mmc));
1140 pr_err("%s: opcode 0x%.8x\n", __func__,
1141 data->mrq->cmd->opcode);
1142 pr_err("%s: blksz %d, blocks %d\n", __func__,
1143 data->blksz, data->blocks);
1144 data->error = -EILSEQ;
1145 }
San Mehat9d2bd732009-09-22 16:44:22 -07001146 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 /* CRC is optional for the bus test commands, not all
1148 * cards respond back with CRC. However controller
1149 * waits for the CRC and times out. Hence ignore the
1150 * data timeouts during the Bustest.
1151 */
1152 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1153 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301154 pr_err("%s: CMD%d: Data timeout\n",
1155 mmc_hostname(host->mmc),
1156 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301158 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 }
San Mehat9d2bd732009-09-22 16:44:22 -07001160 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001161 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001162 data->error = -EIO;
1163 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001164 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001165 data->error = -EIO;
1166 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001167 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001169 data->error = -EIO;
1170 }
San Mehat9d2bd732009-09-22 16:44:22 -07001171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001173 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 host->dummy_52_needed = 0;
1175}
San Mehat9d2bd732009-09-22 16:44:22 -07001176
1177static int
1178msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1179{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001181 uint32_t *ptr = (uint32_t *) buffer;
1182 int count = 0;
1183
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301184 if (remain % 4)
1185 remain = ((remain >> 2) + 1) << 2;
1186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1188
1189 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001190 ptr++;
1191 count += sizeof(uint32_t);
1192
1193 remain -= sizeof(uint32_t);
1194 if (remain == 0)
1195 break;
1196 }
1197 return count;
1198}
1199
1200static int
1201msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001203{
1204 void __iomem *base = host->base;
1205 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 while (readl_relaxed(base + MMCISTATUS) &
1209 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1210 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001211
San Mehat9d2bd732009-09-22 16:44:22 -07001212 count = min(remain, maxcnt);
1213
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301214 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1215 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001216 ptr += count;
1217 remain -= count;
1218
1219 if (remain == 0)
1220 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 }
1222 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001223
1224 return ptr - buffer;
1225}
1226
San Mehat1cd22962010-02-03 12:59:29 -08001227static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001228msmsdcc_pio_irq(int irq, void *dev_id)
1229{
1230 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001232 uint32_t status;
1233
Murali Palnati36448a42011-09-02 15:06:18 +05301234 spin_lock(&host->lock);
1235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301239 (MCI_IRQ_PIO)) == 0) {
1240 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301242 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243
1244#if IRQ_DEBUG
1245 msmsdcc_print_status(host, "irq1-r", status);
1246#endif
1247
San Mehat9d2bd732009-09-22 16:44:22 -07001248 do {
1249 unsigned long flags;
1250 unsigned int remain, len;
1251 char *buffer;
1252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1254 | MCI_RXDATAAVLBL)))
1255 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001256
1257 /* Map the current scatter buffer */
1258 local_irq_save(flags);
1259 buffer = kmap_atomic(sg_page(host->pio.sg),
1260 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1261 buffer += host->pio.sg_off;
1262 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263
San Mehat9d2bd732009-09-22 16:44:22 -07001264 len = 0;
1265 if (status & MCI_RXACTIVE)
1266 len = msmsdcc_pio_read(host, buffer, remain);
1267 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 len = msmsdcc_pio_write(host, buffer, remain);
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301269 /* len might have aligned to 32bits above */
1270 if (len > remain)
1271 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001272
1273 /* Unmap the buffer */
1274 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1275 local_irq_restore(flags);
1276
1277 host->pio.sg_off += len;
1278 host->curr.xfer_remain -= len;
1279 host->curr.data_xfered += len;
1280 remain -= len;
1281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 if (remain) /* Done with this page? */
1283 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 if (status & MCI_RXACTIVE && host->curr.user_pages)
1286 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288 if (!--host->pio.sg_len) {
1289 memset(&host->pio, 0, sizeof(host->pio));
1290 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001291 }
1292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 /* Advance to next sg */
1294 host->pio.sg++;
1295 host->pio.sg_off = 0;
1296
1297 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001298 } while (1);
1299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1301 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1302 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1303 host->base + MMCIMASK0);
1304 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301305 /*
1306 * back to back write to MASK0 register don't need
1307 * synchronization delay.
1308 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1310 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1311 }
1312 mb();
1313 } else if (!host->curr.xfer_remain) {
1314 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1315 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1316 mb();
1317 }
San Mehat9d2bd732009-09-22 16:44:22 -07001318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001320
1321 return IRQ_HANDLED;
1322}
1323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324static void
1325msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1326
1327static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1328 struct mmc_data *data)
1329{
1330 u32 loop_cnt = 0;
1331
1332 /*
1333 * For read commands with data less than fifo size, it is possible to
1334 * get DATAEND first and RXDATA_AVAIL might be set later because of
1335 * synchronization delay through the asynchronous RX FIFO. Thus, for
1336 * such cases, even after DATAEND interrupt is received software
1337 * should poll for RXDATA_AVAIL until the requested data is read out
1338 * of FIFO. This change is needed to get around this abnormal but
1339 * sometimes expected behavior of SDCC3 controller.
1340 *
1341 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1342 * after the data is loaded into RX FIFO. This would amount to less
1343 * than a microsecond and thus looping for 1000 times is good enough
1344 * for that delay.
1345 */
1346 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1347 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1348 spin_unlock(&host->lock);
1349 msmsdcc_pio_irq(1, host);
1350 spin_lock(&host->lock);
1351 }
1352 }
1353 if (loop_cnt == 1000) {
1354 pr_info("%s: Timed out while polling for Rx Data\n",
1355 mmc_hostname(host->mmc));
1356 data->error = -ETIMEDOUT;
1357 msmsdcc_reset_and_restore(host);
1358 }
1359}
1360
San Mehat9d2bd732009-09-22 16:44:22 -07001361static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1362{
1363 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001364
1365 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1367 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1368 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1369 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301372 pr_debug("%s: CMD%d: Command timeout\n",
1373 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001374 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1376 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301377 pr_err("%s: CMD%d: Command CRC error\n",
1378 mmc_hostname(host->mmc), cmd->opcode);
1379 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001380 cmd->error = -EILSEQ;
1381 }
1382
1383 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 if (host->curr.data && host->dma.sg &&
1385 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001386 msm_dmov_stop_cmd(host->dma.channel,
1387 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 else if (host->curr.data && host->sps.sg &&
1389 host->is_sps_mode){
1390 /* Stop current SPS transfer */
1391 msmsdcc_sps_exit_curr_xfer(host);
1392 }
San Mehat9d2bd732009-09-22 16:44:22 -07001393 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301394 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001395 msmsdcc_stop_data(host);
Sujit Reddy Thumma521cdce2011-12-30 16:27:52 +05301396 if (cmd->data && cmd->data->stop)
1397 msmsdcc_start_command(host,
1398 cmd->data->stop, 0);
1399 else
1400 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301401 } else { /* host->data == NULL */
Sujit Reddy Thumma521cdce2011-12-30 16:27:52 +05301402 if (cmd->data && cmd->data->stop) {
1403 msmsdcc_start_command(host,
1404 cmd->data->stop, 0);
1405 } else if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301406 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301408 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301410 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301411 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301412 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001413 if (host->dummy_52_needed)
1414 host->dummy_52_needed = 0;
1415 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301417 msmsdcc_request_end(host, cmd->mrq);
1418 }
1419 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301420 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1421 if (cmd->data->flags & MMC_DATA_READ)
1422 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1423 else
1424 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301425 } else if (cmd->data) {
1426 if (!(cmd->data->flags & MMC_DATA_READ))
1427 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001428 }
1429}
1430
San Mehat9d2bd732009-09-22 16:44:22 -07001431static irqreturn_t
1432msmsdcc_irq(int irq, void *dev_id)
1433{
1434 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001435 u32 status;
1436 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001438
1439 spin_lock(&host->lock);
1440
1441 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 struct mmc_command *cmd;
1443 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 if (timer) {
1446 timer = 0;
1447 msmsdcc_delay(host);
1448 }
San Mehat865c8062009-11-13 13:42:06 -08001449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 if (!host->clks_on) {
1451 pr_debug("%s: %s: SDIO async irq received\n",
1452 mmc_hostname(host->mmc), __func__);
1453 host->mmc->ios.clock = host->clk_rate;
1454 spin_unlock(&host->lock);
1455 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1456 spin_lock(&host->lock);
1457 if (host->plat->cfg_mpm_sdiowakeup &&
1458 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1459 wake_lock(&host->sdio_wlock);
1460 /* only ansyc interrupt can come when clocks are off */
1461 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301462 if (host->clk_rate <=
1463 msmsdcc_get_min_sup_clk_rate(host))
1464 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 }
1466
1467 status = readl_relaxed(host->base + MMCISTATUS);
1468
1469 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1470 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001471 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473#if IRQ_DEBUG
1474 msmsdcc_print_status(host, "irq0-r", status);
1475#endif
1476 status &= readl_relaxed(host->base + MMCIMASK0);
1477 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301478 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301479 if (host->clk_rate <=
1480 msmsdcc_get_min_sup_clk_rate(host))
1481 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482#if IRQ_DEBUG
1483 msmsdcc_print_status(host, "irq0-p", status);
1484#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1487 if (status & MCI_SDIOINTROPE) {
1488 if (host->sdcc_suspending)
1489 wake_lock(&host->sdio_suspend_wlock);
1490 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001493 data = host->curr.data;
1494
1495 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1497 MCI_CMDTIMEOUT)) {
1498 if (status & MCI_CMDTIMEOUT)
1499 pr_debug("%s: dummy CMD52 timeout\n",
1500 mmc_hostname(host->mmc));
1501 if (status & MCI_CMDCRCFAIL)
1502 pr_debug("%s: dummy CMD52 CRC failed\n",
1503 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001504 host->dummy_52_sent = 0;
1505 host->dummy_52_needed = 0;
1506 if (data) {
1507 msmsdcc_stop_data(host);
1508 msmsdcc_request_end(host, data->mrq);
1509 }
1510 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 spin_unlock(&host->lock);
1512 return IRQ_HANDLED;
1513 }
1514 break;
1515 }
1516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 /*
1518 * Check for proper command response
1519 */
1520 cmd = host->curr.cmd;
1521 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1522 MCI_CMDTIMEOUT | MCI_PROGDONE |
1523 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1524 msmsdcc_do_cmdirq(host, status);
1525 }
1526
Sathish Ambley081d7842011-11-29 11:19:41 -08001527 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 /* Check for data errors */
1529 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1530 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1531 msmsdcc_data_err(host, data, status);
1532 host->curr.data_xfered = 0;
1533 if (host->dma.sg && host->is_dma_mode)
1534 msm_dmov_stop_cmd(host->dma.channel,
1535 &host->dma.hdr, 0);
1536 else if (host->sps.sg && host->is_sps_mode) {
1537 /* Stop current SPS transfer */
1538 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301539 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 msmsdcc_reset_and_restore(host);
1541 if (host->curr.data)
1542 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301543 if (!data->stop || (host->curr.mrq->sbc
1544 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 timer |=
1546 msmsdcc_request_end(host,
1547 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301548 else if ((host->curr.mrq->sbc
1549 && data->error) ||
1550 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 msmsdcc_start_command(host,
1552 data->stop,
1553 0);
1554 timer = 1;
1555 }
1556 }
1557 }
1558
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301559 /* Check for prog done */
1560 if (host->curr.wait_for_auto_prog_done &&
1561 (status & MCI_PROGDONE))
1562 host->curr.got_auto_prog_done = 1;
1563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 /* Check for data done */
1565 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1566 host->curr.got_dataend = 1;
1567
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301568 if (host->curr.got_dataend &&
1569 (!host->curr.wait_for_auto_prog_done ||
1570 (host->curr.wait_for_auto_prog_done &&
1571 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572 /*
1573 * If DMA is still in progress, we complete
1574 * via the completion handler
1575 */
1576 if (!host->dma.busy && !host->sps.busy) {
1577 /*
1578 * There appears to be an issue in the
1579 * controller where if you request a
1580 * small block transfer (< fifo size),
1581 * you may get your DATAEND/DATABLKEND
1582 * irq without the PIO data irq.
1583 *
1584 * Check to see if theres still data
1585 * to be read, and simulate a PIO irq.
1586 */
1587 if (data->flags & MMC_DATA_READ)
1588 msmsdcc_wait_for_rxdata(host,
1589 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 if (!data->error) {
1591 host->curr.data_xfered =
1592 host->curr.xfer_size;
1593 host->curr.xfer_remain -=
1594 host->curr.xfer_size;
1595 }
1596
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001597 if (!host->dummy_52_needed) {
1598 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301599 if (!data->stop ||
1600 (host->curr.mrq->sbc
1601 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001602 msmsdcc_request_end(
1603 host,
1604 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301605 else if ((host->curr.mrq->sbc
1606 && data->error) ||
1607 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001608 msmsdcc_start_command(
1609 host,
1610 data->stop, 0);
1611 timer = 1;
1612 }
1613 } else {
1614 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001616 &dummy52cmd,
1617 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 }
1619 }
1620 }
1621 }
1622
San Mehat9d2bd732009-09-22 16:44:22 -07001623 ret = 1;
1624 } while (status);
1625
1626 spin_unlock(&host->lock);
1627
San Mehat9d2bd732009-09-22 16:44:22 -07001628 return IRQ_RETVAL(ret);
1629}
1630
1631static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1633{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301634 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301636 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301637 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1638 else
1639 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 } else {
1641 msmsdcc_start_command(host, mrq->cmd, 0);
1642 }
1643}
1644
1645static void
San Mehat9d2bd732009-09-22 16:44:22 -07001646msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1647{
1648 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 /*
1652 * Get the SDIO AL client out of LPM.
1653 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001654 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 if (host->plat->is_sdio_al_client)
1656 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001657
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301658 /* check if sps pipe reset is pending? */
1659 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1660 msmsdcc_sps_pipes_reset_and_restore(host);
1661 host->sps.pipe_reset_pending = false;
1662 }
1663
San Mehat9d2bd732009-09-22 16:44:22 -07001664 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 WARN(host->curr.mrq, "Request in progress\n");
1666 WARN(!host->pwr, "SDCC power is turned off\n");
1667 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1668 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001669
1670 if (host->eject) {
1671 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1672 mrq->cmd->error = 0;
1673 mrq->data->bytes_xfered = mrq->data->blksz *
1674 mrq->data->blocks;
1675 } else
1676 mrq->cmd->error = -ENOMEDIUM;
1677
1678 spin_unlock_irqrestore(&host->lock, flags);
1679 mmc_request_done(mmc, mrq);
1680 return;
1681 }
1682
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301683 /*
1684 * Kick the software command timeout timer here.
1685 * Timer expires in 10 secs.
1686 */
1687 mod_timer(&host->req_tout_timer,
1688 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001689
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301690 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301691 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301692 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1693 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301694 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301696 else
1697 /*
1698 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1699 * write operations using CMD53 and CMD54.
1700 * Setting this bit with CMD53 would
1701 * automatically triggers PROG_DONE interrupt
1702 * without the need of sending dummy CMD52.
1703 */
1704 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301705 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1706 host->sdcc_version) {
1707 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001708 }
San Mehat9d2bd732009-09-22 16:44:22 -07001709 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301710
Pratibhasagar V00b94332011-10-18 14:57:27 +05301711 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301712 mrq->sbc->mrq = mrq;
1713 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301714 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301715 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301716 msmsdcc_start_command(host, mrq->sbc, 0);
1717 } else {
1718 msmsdcc_request_start(host, mrq);
1719 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301720 } else {
1721 msmsdcc_request_start(host, mrq);
1722 }
1723
San Mehat9d2bd732009-09-22 16:44:22 -07001724 spin_unlock_irqrestore(&host->lock, flags);
1725}
1726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1728 int min_uV, int max_uV)
1729{
1730 int rc = 0;
1731
1732 if (vreg->set_voltage_sup) {
1733 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1734 if (rc) {
1735 pr_err("%s: regulator_set_voltage(%s) failed."
1736 " min_uV=%d, max_uV=%d, rc=%d\n",
1737 __func__, vreg->name, min_uV, max_uV, rc);
1738 }
1739 }
1740
1741 return rc;
1742}
1743
1744static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1745 int uA_load)
1746{
1747 int rc = 0;
1748
Krishna Kondafea60182011-11-01 16:01:34 -07001749 /* regulators that do not support regulator_set_voltage also
1750 do not support regulator_set_optimum_mode */
1751 if (vreg->set_voltage_sup) {
1752 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1753 if (rc < 0)
1754 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1755 "uA_load=%d) failed. rc=%d\n", __func__,
1756 vreg->name, uA_load, rc);
1757 else
1758 /* regulator_set_optimum_mode() can return non zero
1759 * value even for success case.
1760 */
1761 rc = 0;
1762 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763
1764 return rc;
1765}
1766
1767static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1768 struct device *dev)
1769{
1770 int rc = 0;
1771
1772 /* check if regulator is already initialized? */
1773 if (vreg->reg)
1774 goto out;
1775
1776 /* Get the regulator handle */
1777 vreg->reg = regulator_get(dev, vreg->name);
1778 if (IS_ERR(vreg->reg)) {
1779 rc = PTR_ERR(vreg->reg);
1780 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1781 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001782 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001784
1785 if (regulator_count_voltages(vreg->reg) > 0)
1786 vreg->set_voltage_sup = 1;
1787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788out:
1789 return rc;
1790}
1791
1792static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1793{
1794 if (vreg->reg)
1795 regulator_put(vreg->reg);
1796}
1797
1798/* This init function should be called only once for each SDCC slot */
1799static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1800{
1801 int rc = 0;
1802 struct msm_mmc_slot_reg_data *curr_slot;
1803 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1804 struct device *dev = mmc_dev(host->mmc);
1805
1806 curr_slot = host->plat->vreg_data;
1807 if (!curr_slot)
1808 goto out;
1809
1810 curr_vdd_reg = curr_slot->vdd_data;
1811 curr_vccq_reg = curr_slot->vccq_data;
1812 curr_vddp_reg = curr_slot->vddp_data;
1813
1814 if (is_init) {
1815 /*
1816 * Get the regulator handle from voltage regulator framework
1817 * and then try to set the voltage level for the regulator
1818 */
1819 if (curr_vdd_reg) {
1820 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1821 if (rc)
1822 goto out;
1823 }
1824 if (curr_vccq_reg) {
1825 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1826 if (rc)
1827 goto vdd_reg_deinit;
1828 }
1829 if (curr_vddp_reg) {
1830 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1831 if (rc)
1832 goto vccq_reg_deinit;
1833 }
1834 goto out;
1835 } else {
1836 /* Deregister all regulators from regulator framework */
1837 goto vddp_reg_deinit;
1838 }
1839vddp_reg_deinit:
1840 if (curr_vddp_reg)
1841 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1842vccq_reg_deinit:
1843 if (curr_vccq_reg)
1844 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1845vdd_reg_deinit:
1846 if (curr_vdd_reg)
1847 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1848out:
1849 return rc;
1850}
1851
1852static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1853{
1854 int rc = 0;
1855
Subhash Jadavanicc922692011-08-01 23:05:01 +05301856 /* Put regulator in HPM (high power mode) */
1857 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1858 if (rc < 0)
1859 goto out;
1860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 if (!vreg->is_enabled) {
1862 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301863 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1864 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 if (rc)
1866 goto out;
1867
1868 rc = regulator_enable(vreg->reg);
1869 if (rc) {
1870 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1871 __func__, vreg->name, rc);
1872 goto out;
1873 }
1874 vreg->is_enabled = true;
1875 }
1876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877out:
1878 return rc;
1879}
1880
1881static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1882{
1883 int rc = 0;
1884
1885 /* Never disable regulator marked as always_on */
1886 if (vreg->is_enabled && !vreg->always_on) {
1887 rc = regulator_disable(vreg->reg);
1888 if (rc) {
1889 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1890 __func__, vreg->name, rc);
1891 goto out;
1892 }
1893 vreg->is_enabled = false;
1894
1895 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1896 if (rc < 0)
1897 goto out;
1898
1899 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301900 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 if (rc)
1902 goto out;
1903 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1904 /* Put always_on regulator in LPM (low power mode) */
1905 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1906 if (rc < 0)
1907 goto out;
1908 }
1909out:
1910 return rc;
1911}
1912
1913static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1914{
1915 int rc = 0, i;
1916 struct msm_mmc_slot_reg_data *curr_slot;
1917 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1918 struct msm_mmc_reg_data *vreg_table[3];
1919
1920 curr_slot = host->plat->vreg_data;
1921 if (!curr_slot)
1922 goto out;
1923
1924 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1925 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1926 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1927
1928 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1929 if (vreg_table[i]) {
1930 if (enable)
1931 rc = msmsdcc_vreg_enable(vreg_table[i]);
1932 else
1933 rc = msmsdcc_vreg_disable(vreg_table[i]);
1934 if (rc)
1935 goto out;
1936 }
1937 }
1938out:
1939 return rc;
1940}
1941
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301942static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943{
1944 int rc = 0;
1945
1946 if (host->plat->vreg_data) {
1947 struct msm_mmc_reg_data *vddp_reg =
1948 host->plat->vreg_data->vddp_data;
1949
1950 if (vddp_reg && vddp_reg->is_enabled)
1951 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1952 }
1953
1954 return rc;
1955}
1956
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301957static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1958{
1959 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1960 int rc = 0;
1961
1962 if (curr_slot && curr_slot->vddp_data) {
1963 rc = msmsdcc_set_vddp_level(host,
1964 curr_slot->vddp_data->low_vol_level);
1965
1966 if (rc)
1967 pr_err("%s: %s: failed to change vddp level to %d",
1968 mmc_hostname(host->mmc), __func__,
1969 curr_slot->vddp_data->low_vol_level);
1970 }
1971
1972 return rc;
1973}
1974
1975static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1976{
1977 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1978 int rc = 0;
1979
1980 if (curr_slot && curr_slot->vddp_data) {
1981 rc = msmsdcc_set_vddp_level(host,
1982 curr_slot->vddp_data->high_vol_level);
1983
1984 if (rc)
1985 pr_err("%s: %s: failed to change vddp level to %d",
1986 mmc_hostname(host->mmc), __func__,
1987 curr_slot->vddp_data->high_vol_level);
1988 }
1989
1990 return rc;
1991}
1992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1994{
1995 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1996 return 1;
1997 return 0;
1998}
1999
2000static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2001{
2002 if (enable) {
2003 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2004 clk_enable(host->dfab_pclk);
2005 if (!IS_ERR(host->pclk))
2006 clk_enable(host->pclk);
2007 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302008 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302010 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 clk_disable(host->clk);
2012 if (!IS_ERR(host->pclk))
2013 clk_disable(host->pclk);
2014 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2015 clk_disable(host->dfab_pclk);
2016 }
2017}
2018
2019static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2020 unsigned int req_clk)
2021{
2022 unsigned int sel_clk = -1;
2023
2024 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2025 unsigned char cnt;
2026
2027 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2028 if (host->plat->sup_clk_table[cnt] > req_clk)
2029 break;
2030 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2031 sel_clk = host->plat->sup_clk_table[cnt];
2032 break;
2033 } else
2034 sel_clk = host->plat->sup_clk_table[cnt];
2035 }
2036 } else {
2037 if ((req_clk < host->plat->msmsdcc_fmax) &&
2038 (req_clk > host->plat->msmsdcc_fmid))
2039 sel_clk = host->plat->msmsdcc_fmid;
2040 else
2041 sel_clk = req_clk;
2042 }
2043
2044 return sel_clk;
2045}
2046
2047static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2048 struct msmsdcc_host *host)
2049{
2050 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2051 return host->plat->sup_clk_table[0];
2052 else
2053 return host->plat->msmsdcc_fmin;
2054}
2055
2056static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2057 struct msmsdcc_host *host)
2058{
2059 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2060 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2061 else
2062 return host->plat->msmsdcc_fmax;
2063}
2064
2065static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302066{
2067 struct msm_mmc_gpio_data *curr;
2068 int i, rc = 0;
2069
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302071 for (i = 0; i < curr->size; i++) {
2072 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002073 if (curr->gpio[i].is_always_on &&
2074 curr->gpio[i].is_enabled)
2075 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302076 rc = gpio_request(curr->gpio[i].no,
2077 curr->gpio[i].name);
2078 if (rc) {
2079 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2080 mmc_hostname(host->mmc),
2081 curr->gpio[i].no,
2082 curr->gpio[i].name, rc);
2083 goto free_gpios;
2084 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302086 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087 if (curr->gpio[i].is_always_on)
2088 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302089 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302091 }
2092 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302094
2095free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302097 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 curr->gpio[i].is_enabled = false;
2099 }
2100out:
2101 return rc;
2102}
2103
2104static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2105{
2106 struct msm_mmc_pad_data *curr;
2107 int i;
2108
2109 curr = host->plat->pin_data->pad_data;
2110 for (i = 0; i < curr->drv->size; i++) {
2111 if (enable)
2112 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2113 curr->drv->on[i].val);
2114 else
2115 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2116 curr->drv->off[i].val);
2117 }
2118
2119 for (i = 0; i < curr->pull->size; i++) {
2120 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002121 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122 curr->pull->on[i].val);
2123 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002124 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 curr->pull->off[i].val);
2126 }
2127
2128 return 0;
2129}
2130
2131static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2132{
2133 int rc = 0;
2134
2135 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2136 return 0;
2137
2138 if (host->plat->pin_data->is_gpio)
2139 rc = msmsdcc_setup_gpio(host, enable);
2140 else
2141 rc = msmsdcc_setup_pad(host, enable);
2142
2143 if (!rc)
2144 host->plat->pin_data->cfg_sts = enable;
2145
2146 return rc;
2147}
2148
2149static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2150{
2151 unsigned int wakeup_irq;
2152
2153 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2154 host->plat->sdiowakeup_irq :
2155 host->core_irqres->start;
2156
2157 if (!host->irq_wake_enabled) {
2158 enable_irq_wake(wakeup_irq);
2159 host->irq_wake_enabled = true;
2160 }
2161}
2162
2163static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2164{
2165 unsigned int wakeup_irq;
2166
2167 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2168 host->plat->sdiowakeup_irq :
2169 host->core_irqres->start;
2170
2171 if (host->irq_wake_enabled) {
2172 disable_irq_wake(wakeup_irq);
2173 host->irq_wake_enabled = false;
2174 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302175}
2176
San Mehat9d2bd732009-09-22 16:44:22 -07002177static void
2178msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2179{
2180 struct msmsdcc_host *host = mmc_priv(mmc);
2181 u32 clk = 0, pwr = 0;
2182 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002183 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002184 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302187
San Mehat9d2bd732009-09-22 16:44:22 -07002188 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 spin_lock_irqsave(&host->lock, flags);
2190 if (!host->clks_on) {
2191 msmsdcc_setup_clocks(host, true);
2192 host->clks_on = 1;
2193 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2194 if (!host->plat->sdiowakeup_irq) {
2195 writel_relaxed(host->mci_irqenable,
2196 host->base + MMCIMASK0);
2197 mb();
2198 if (host->plat->cfg_mpm_sdiowakeup &&
2199 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2200 host->plat->cfg_mpm_sdiowakeup(
2201 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2202 msmsdcc_disable_irq_wake(host);
2203 } else if (!(mmc->pm_flags &
2204 MMC_PM_WAKE_SDIO_IRQ)) {
2205 writel_relaxed(host->mci_irqenable,
2206 host->base + MMCIMASK0);
2207 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302208 } else {
2209 writel_relaxed(host->mci_irqenable,
2210 host->base + MMCIMASK0);
2211 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002212 }
San Mehat9d2bd732009-09-22 16:44:22 -07002213 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002214 spin_unlock_irqrestore(&host->lock, flags);
2215
2216 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2217 /*
2218 * For DDR50 mode, controller needs clock rate to be
2219 * double than what is required on the SD card CLK pin.
2220 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302221 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002222 /*
2223 * Make sure that we don't double the clock if
2224 * doubled clock rate is already set
2225 */
2226 if (!host->ddr_doubled_clk_rate ||
2227 (host->ddr_doubled_clk_rate &&
2228 (host->ddr_doubled_clk_rate != ios->clock))) {
2229 host->ddr_doubled_clk_rate =
2230 msmsdcc_get_sup_clk_rate(
2231 host, (ios->clock * 2));
2232 clock = host->ddr_doubled_clk_rate;
2233 }
2234 } else {
2235 host->ddr_doubled_clk_rate = 0;
2236 }
2237
2238 if (clock != host->clk_rate) {
2239 rc = clk_set_rate(host->clk, clock);
2240 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302241 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 mmc_hostname(mmc), clock);
2243 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302244 host->reg_write_delay =
2245 (1 + ((3 * USEC_PER_SEC) /
2246 (host->clk_rate ? host->clk_rate :
2247 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 }
2249 /*
2250 * give atleast 2 MCLK cycles delay for clocks
2251 * and SDCC core to stabilize
2252 */
2253 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002254 clk |= MCI_CLK_ENABLE;
2255 }
2256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 if (ios->bus_width == MMC_BUS_WIDTH_8)
2258 clk |= MCI_CLK_WIDEBUS_8;
2259 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2260 clk |= MCI_CLK_WIDEBUS_4;
2261 else
2262 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 if (msmsdcc_is_pwrsave(host))
2265 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 host->tuning_needed = 0;
2270 /*
2271 * Select the controller timing mode according
2272 * to current bus speed mode
2273 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302274 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 clk |= (4 << 14);
2276 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302277 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 clk |= (3 << 14);
2279 } else {
2280 clk |= (2 << 14); /* feedback clock */
2281 }
2282
2283 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2284 clk |= (2 << 23);
2285
2286 if (host->io_pad_pwr_switch)
2287 clk |= IO_PAD_PWR_SWITCH;
2288
2289 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002290 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2292 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002293
2294 switch (ios->power_mode) {
2295 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2297 if (!host->sdcc_irq_disabled) {
2298 if (host->plat->cfg_mpm_sdiowakeup)
2299 host->plat->cfg_mpm_sdiowakeup(
2300 mmc_dev(mmc), SDC_DAT1_DISABLE);
2301 disable_irq(host->core_irqres->start);
2302 host->sdcc_irq_disabled = 1;
2303 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302304 /*
2305 * As VDD pad rail is always on, set low voltage for VDD
2306 * pad rail when slot is unused (when card is not present
2307 * or during system suspend).
2308 */
2309 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002311 break;
2312 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302313 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002314 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315 if (host->sdcc_irq_disabled) {
2316 if (host->plat->cfg_mpm_sdiowakeup)
2317 host->plat->cfg_mpm_sdiowakeup(
2318 mmc_dev(mmc), SDC_DAT1_ENABLE);
2319 enable_irq(host->core_irqres->start);
2320 host->sdcc_irq_disabled = 0;
2321 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302322 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002324 break;
2325 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002327 pwr |= MCI_PWR_ON;
2328 break;
2329 }
2330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331 spin_lock_irqsave(&host->lock, flags);
2332 if (!host->clks_on) {
2333 /* force the clocks to be on */
2334 msmsdcc_setup_clocks(host, true);
2335 /*
2336 * give atleast 2 MCLK cycles delay for clocks
2337 * and SDCC core to stabilize
2338 */
2339 msmsdcc_delay(host);
2340 }
2341 writel_relaxed(clk, host->base + MMCICLOCK);
2342 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002343
2344 if (host->pwr != pwr) {
2345 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302347 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002348 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 if (!host->clks_on) {
2350 /* force the clocks to be off */
2351 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 }
2353
2354 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2355 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2356 if (!host->plat->sdiowakeup_irq) {
2357 writel_relaxed(MCI_SDIOINTMASK,
2358 host->base + MMCIMASK0);
2359 mb();
2360 if (host->plat->cfg_mpm_sdiowakeup &&
2361 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2362 host->plat->cfg_mpm_sdiowakeup(
2363 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2364 msmsdcc_enable_irq_wake(host);
2365 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2366 writel_relaxed(0, host->base + MMCIMASK0);
2367 } else {
2368 writel_relaxed(MCI_SDIOINTMASK,
2369 host->base + MMCIMASK0);
2370 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302371 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 }
2373 msmsdcc_setup_clocks(host, false);
2374 host->clks_on = 0;
2375 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302376
2377 if (host->cmd19_tuning_in_progress)
2378 WARN(!host->clks_on,
2379 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2380
San Mehat4adbbcc2009-11-08 13:00:37 -08002381 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002382}
2383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002384int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2385{
2386 struct msmsdcc_host *host = mmc_priv(mmc);
2387 u32 clk;
2388
2389 clk = readl_relaxed(host->base + MMCICLOCK);
2390 pr_debug("Changing to pwr_save=%d", pwrsave);
2391 if (pwrsave && msmsdcc_is_pwrsave(host))
2392 clk |= MCI_CLK_PWRSAVE;
2393 else
2394 clk &= ~MCI_CLK_PWRSAVE;
2395 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302396 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002397
2398 return 0;
2399}
2400
2401static int msmsdcc_get_ro(struct mmc_host *mmc)
2402{
2403 int status = -ENOSYS;
2404 struct msmsdcc_host *host = mmc_priv(mmc);
2405
2406 if (host->plat->wpswitch) {
2407 status = host->plat->wpswitch(mmc_dev(mmc));
2408 } else if (host->plat->wpswitch_gpio) {
2409 status = gpio_request(host->plat->wpswitch_gpio,
2410 "SD_WP_Switch");
2411 if (status) {
2412 pr_err("%s: %s: Failed to request GPIO %d\n",
2413 mmc_hostname(mmc), __func__,
2414 host->plat->wpswitch_gpio);
2415 } else {
2416 status = gpio_direction_input(
2417 host->plat->wpswitch_gpio);
2418 if (!status) {
2419 /*
2420 * Wait for atleast 300ms as debounce
2421 * time for GPIO input to stabilize.
2422 */
2423 msleep(300);
2424 status = gpio_get_value_cansleep(
2425 host->plat->wpswitch_gpio);
2426 status ^= !host->plat->wpswitch_polarity;
2427 }
2428 gpio_free(host->plat->wpswitch_gpio);
2429 }
2430 }
2431
2432 if (status < 0)
2433 status = -ENOSYS;
2434 pr_debug("%s: Card read-only status %d\n", __func__, status);
2435
2436 return status;
2437}
2438
2439#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002440static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2441{
2442 struct msmsdcc_host *host = mmc_priv(mmc);
2443 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444
2445 if (enable) {
2446 spin_lock_irqsave(&host->lock, flags);
2447 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2448 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2449 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2450 spin_unlock_irqrestore(&host->lock, flags);
2451 } else {
2452 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2453 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2454 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2455 }
2456 mb();
2457}
2458#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2459
2460#ifdef CONFIG_PM_RUNTIME
2461static int msmsdcc_enable(struct mmc_host *mmc)
2462{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302463 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 struct device *dev = mmc->parent;
2465
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302466 if (dev->power.runtime_status == RPM_SUSPENDING) {
2467 if (mmc->suspend_task == current) {
2468 pm_runtime_get_noresume(dev);
2469 goto out;
2470 }
2471 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302473 rc = pm_runtime_get_sync(dev);
2474
2475 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2477 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302478 return rc;
2479 }
2480out:
2481 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482}
2483
2484static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2485{
2486 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302487 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302489 if (host->plat->disable_runtime_pm)
2490 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2492 return -ENOTSUPP;
2493
2494 rc = pm_runtime_put_sync(mmc->parent);
2495
2496 if (rc < 0)
2497 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2498 __func__, rc);
2499 return rc;
2500}
2501#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302502static int msmsdcc_enable(struct mmc_host *mmc)
2503{
2504 struct msmsdcc_host *host = mmc_priv(mmc);
2505 unsigned long flags;
2506
2507 spin_lock_irqsave(&host->lock, flags);
2508 if (!host->clks_on) {
2509 msmsdcc_setup_clocks(host, true);
2510 host->clks_on = 1;
2511 }
2512 spin_unlock_irqrestore(&host->lock, flags);
2513
2514 return 0;
2515}
2516
2517static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2518{
2519 struct msmsdcc_host *host = mmc_priv(mmc);
2520 unsigned long flags;
2521
2522 if (mmc->card && mmc_card_sdio(mmc->card))
2523 return -ENOTSUPP;
2524
2525 spin_lock_irqsave(&host->lock, flags);
2526 if (host->clks_on) {
2527 msmsdcc_setup_clocks(host, false);
2528 host->clks_on = 0;
2529 }
2530 spin_unlock_irqrestore(&host->lock, flags);
2531
2532 return 0;
2533}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534#endif
2535
2536static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2537 struct mmc_ios *ios)
2538{
2539 struct msmsdcc_host *host = mmc_priv(mmc);
2540 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302541 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542
2543 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2544 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302545 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 goto out;
2547 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2548 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302549 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 goto out;
2551 }
San Mehat9d2bd732009-09-22 16:44:22 -07002552
2553 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554 /*
2555 * If we are here means voltage switch from high voltage to
2556 * low voltage is required
2557 */
2558
2559 /*
2560 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2561 * register until they become all zeros.
2562 */
2563 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302564 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2566 mmc_hostname(mmc), __func__);
2567 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002568 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569
2570 /* Stop SD CLK output. */
2571 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2572 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302573 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002574 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575
2576 /*
2577 * Switch VDDPX from high voltage to low voltage
2578 * to change the VDD of the SD IO pads.
2579 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302580 rc = msmsdcc_set_vddp_low_vol(host);
2581 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583
2584 spin_lock_irqsave(&host->lock, flags);
2585 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2586 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302587 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 host->io_pad_pwr_switch = 1;
2589 spin_unlock_irqrestore(&host->lock, flags);
2590
2591 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2592 usleep_range(5000, 5500);
2593
2594 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302595 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2597 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302598 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 spin_unlock_irqrestore(&host->lock, flags);
2600
2601 /*
2602 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2603 * don't become all ones within 1 ms then a Voltage Switch
2604 * sequence has failed and a power cycle to the card is required.
2605 * Otherwise Voltage Switch sequence is completed successfully.
2606 */
2607 usleep_range(1000, 1500);
2608
2609 spin_lock_irqsave(&host->lock, flags);
2610 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2611 != (0xF << 1)) {
2612 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2613 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302614 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 goto out_unlock;
2616 }
2617
2618out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302619 /* Enable PWRSAVE */
2620 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2621 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 spin_unlock_irqrestore(&host->lock, flags);
2623out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302624 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625}
2626
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302627static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630
2631 /* Program the MCLK value to MCLK_FREQ bit field */
2632 if (host->clk_rate <= 112000000)
2633 mclk_freq = 0;
2634 else if (host->clk_rate <= 125000000)
2635 mclk_freq = 1;
2636 else if (host->clk_rate <= 137000000)
2637 mclk_freq = 2;
2638 else if (host->clk_rate <= 150000000)
2639 mclk_freq = 3;
2640 else if (host->clk_rate <= 162000000)
2641 mclk_freq = 4;
2642 else if (host->clk_rate <= 175000000)
2643 mclk_freq = 5;
2644 else if (host->clk_rate <= 187000000)
2645 mclk_freq = 6;
2646 else if (host->clk_rate <= 200000000)
2647 mclk_freq = 7;
2648
2649 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2650 & ~(7 << 24)) | (mclk_freq << 24)),
2651 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652}
2653
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302654/* Initialize the DLL (Programmable Delay Line ) */
2655static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302658 unsigned long flags;
2659 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302661 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 /*
2663 * Make sure that clock is always enabled when DLL
2664 * tuning is in progress. Keeping PWRSAVE ON may
2665 * turn off the clock. So let's disable the PWRSAVE
2666 * here and re-enable it once tuning is completed.
2667 */
2668 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2669 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302670
2671 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2672 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2673 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2674
2675 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2676 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2677 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2678
2679 msmsdcc_cm_sdc4_dll_set_freq(host);
2680
2681 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2682 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2683 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2684
2685 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2686 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2687 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2688
2689 /* Set DLL_EN bit to 1. */
2690 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2691 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2692
2693 /* Set CK_OUT_EN bit to 1. */
2694 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2695 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2696
2697 wait_cnt = 50;
2698 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2699 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2700 /* max. wait for 50us sec for LOCK bit to be set */
2701 if (--wait_cnt == 0) {
2702 pr_err("%s: %s: DLL failed to LOCK\n",
2703 mmc_hostname(host->mmc), __func__);
2704 rc = -ETIMEDOUT;
2705 goto out;
2706 }
2707 /* wait for 1us before polling again */
2708 udelay(1);
2709 }
2710
2711out:
2712 /* re-enable PWRSAVE */
2713 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2714 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2715 spin_unlock_irqrestore(&host->lock, flags);
2716
2717 return rc;
2718}
2719
2720static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2721 u8 poll)
2722{
2723 int rc = 0;
2724 u32 wait_cnt = 50;
2725 u8 ck_out_en = 0;
2726
2727 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2728 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2729 MCI_CK_OUT_EN);
2730
2731 while (ck_out_en != poll) {
2732 if (--wait_cnt == 0) {
2733 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2734 mmc_hostname(host->mmc), __func__, poll);
2735 rc = -ETIMEDOUT;
2736 goto out;
2737 }
2738 udelay(1);
2739
2740 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2741 MCI_CK_OUT_EN);
2742 }
2743out:
2744 return rc;
2745}
2746
2747/*
2748 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2749 * calibration sequence. This function should be called before
2750 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2751 * commands (CMD17/CMD18).
2752 *
2753 * This function gets called when host spinlock acquired.
2754 */
2755static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2756{
2757 int rc = 0;
2758 u32 config;
2759
2760 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2761 config |= MCI_CDR_EN;
2762 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2763 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2764
2765 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2766 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2767 if (rc)
2768 goto err_out;
2769
2770 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2771 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2772 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2773
2774 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2775 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2776 if (rc)
2777 goto err_out;
2778
2779 goto out;
2780
2781err_out:
2782 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2783out:
2784 return rc;
2785}
2786
2787static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2788 u8 phase)
2789{
2790 int rc = 0;
2791 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6,
2792 0x7, 0x5, 0x4, 0x8, 0x9,
2793 0xB, 0xA, 0xE, 0xF, 0xD,
2794 0xC};
2795 unsigned long flags;
2796 u32 config;
2797
2798 spin_lock_irqsave(&host->lock, flags);
2799
2800 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2801 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2802 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2803 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2804
2805 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2806 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2807 if (rc)
2808 goto err_out;
2809
2810 /*
2811 * Write the selected DLL clock output phase (0 ... 15)
2812 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2813 */
2814 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2815 & ~(0xF << 20))
2816 | (grey_coded_phase_table[phase] << 20)),
2817 host->base + MCI_DLL_CONFIG);
2818
2819 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2820 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2821 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2822
2823 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2824 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2825 if (rc)
2826 goto err_out;
2827
2828 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2829 config |= MCI_CDR_EN;
2830 config &= ~MCI_CDR_EXT_EN;
2831 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2832 goto out;
2833
2834err_out:
2835 pr_err("%s: %s: Failed to set DLL phase: %d\n",
2836 mmc_hostname(host->mmc), __func__, phase);
2837out:
2838 spin_unlock_irqrestore(&host->lock, flags);
2839 return rc;
2840}
2841
2842/*
2843 * Find out the greatest range of consecuitive selected
2844 * DLL clock output phases that can be used as sampling
2845 * setting for SD3.0 UHS-I card read operation (in SDR104
2846 * timing mode) or for eMMC4.5 card read operation (in HS200
2847 * timing mode).
2848 * Select the 3/4 of the range and configure the DLL with the
2849 * selected DLL clock output phase.
2850*/
2851
2852static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
2853 u8 *phase_table, u8 total_phases)
2854{
2855 u8 ret, temp;
2856 u8 ranges[16][16] = { {0}, {0} };
2857 u8 phases_per_row[16] = {0};
2858 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
2859 int cnt;
2860
2861 for (cnt = 0; cnt <= total_phases; cnt++) {
2862 ranges[row_index][col_index] = phase_table[cnt];
2863 phases_per_row[row_index] += 1;
2864 col_index++;
2865
2866 if ((cnt + 1) > total_phases) {
2867 continue;
2868 /* check if next phase in phase_table is consecutive or not */
2869 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2870 row_index++;
2871 col_index = 0;
2872 }
2873 }
2874
2875 for (cnt = 0; cnt <= total_phases; cnt++) {
2876 if (phases_per_row[cnt] > curr_max) {
2877 curr_max = phases_per_row[cnt];
2878 selected_row_index = cnt;
2879 }
2880 }
2881
2882 temp = ((curr_max * 3) / 4);
2883 ret = ranges[selected_row_index][temp];
2884
2885 return ret;
2886}
2887
2888static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2889{
2890 int rc = 0;
2891 struct msmsdcc_host *host = mmc_priv(mmc);
2892 unsigned long flags;
2893 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2894
2895 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2896
2897 /* Tuning is only required for SDR104 modes */
2898 if (!host->tuning_needed) {
2899 rc = 0;
2900 goto exit;
2901 }
2902
2903 spin_lock_irqsave(&host->lock, flags);
2904 WARN(!host->pwr, "SDCC power is turned off\n");
2905 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2906 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2907
2908 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302909 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302910 spin_unlock_irqrestore(&host->lock, flags);
2911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002912 /* first of all reset the tuning block */
2913 rc = msmsdcc_init_cm_sdc4_dll(host);
2914 if (rc)
2915 goto out;
2916
2917 data_buf = kmalloc(64, GFP_KERNEL);
2918 if (!data_buf) {
2919 rc = -ENOMEM;
2920 goto out;
2921 }
2922
2923 phase = 0;
2924 do {
2925 struct mmc_command cmd = {0};
2926 struct mmc_data data = {0};
2927 struct mmc_request mrq = {
2928 .cmd = &cmd,
2929 .data = &data
2930 };
2931 struct scatterlist sg;
2932
2933 /* set the phase in delay line hw block */
2934 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2935 if (rc)
2936 goto kfree;
2937
2938 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2939 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2940
2941 data.blksz = 64;
2942 data.blocks = 1;
2943 data.flags = MMC_DATA_READ;
2944 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2945
2946 data.sg = &sg;
2947 data.sg_len = 1;
2948 sg_init_one(&sg, data_buf, 64);
2949 memset(data_buf, 0, 64);
2950 mmc_wait_for_req(mmc, &mrq);
2951
2952 if (!cmd.error && !data.error &&
2953 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2954 /* tuning is successful with this tuning point */
2955 tuned_phases[tuned_phase_cnt++] = phase;
2956 }
2957 } while (++phase < 16);
2958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002959 if (tuned_phase_cnt) {
2960 tuned_phase_cnt--;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302961 phase = find_most_appropriate_phase(host, tuned_phases,
2962 tuned_phase_cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963 /*
2964 * Finally set the selected phase in delay
2965 * line hw block.
2966 */
2967 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2968 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302969 goto kfree;
2970 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
2971 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002972 } else {
2973 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302974 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302976 msmsdcc_dump_sdcc_state(host);
2977 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979
2980kfree:
2981 kfree(data_buf);
2982out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302983 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302984 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002985 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302986 spin_unlock_irqrestore(&host->lock, flags);
2987exit:
2988 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002990}
2991
2992static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 .enable = msmsdcc_enable,
2994 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002995 .request = msmsdcc_request,
2996 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997 .get_ro = msmsdcc_get_ro,
2998#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002999 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000#endif
3001 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3002 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003003};
3004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005static unsigned int
3006msmsdcc_slot_status(struct msmsdcc_host *host)
3007{
3008 int status;
3009 unsigned int gpio_no = host->plat->status_gpio;
3010
3011 status = gpio_request(gpio_no, "SD_HW_Detect");
3012 if (status) {
3013 pr_err("%s: %s: Failed to request GPIO %d\n",
3014 mmc_hostname(host->mmc), __func__, gpio_no);
3015 } else {
3016 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003017 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003018 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003019 if (host->plat->is_status_gpio_active_low)
3020 status = !status;
3021 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022 gpio_free(gpio_no);
3023 }
3024 return status;
3025}
3026
San Mehat9d2bd732009-09-22 16:44:22 -07003027static void
3028msmsdcc_check_status(unsigned long data)
3029{
3030 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3031 unsigned int status;
3032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003033 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003034 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003036 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 status = msmsdcc_slot_status(host);
3038
Krishna Konda941604a2012-01-10 17:46:34 -08003039 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003042 if (host->plat->status)
3043 pr_info("%s: Slot status change detected "
3044 "(%d -> %d)\n",
3045 mmc_hostname(host->mmc),
3046 host->oldstat, status);
3047 else if (host->plat->is_status_gpio_active_low)
3048 pr_info("%s: Slot status change detected "
3049 "(%d -> %d) and the card detect GPIO"
3050 " is ACTIVE_LOW\n",
3051 mmc_hostname(host->mmc),
3052 host->oldstat, status);
3053 else
3054 pr_info("%s: Slot status change detected "
3055 "(%d -> %d) and the card detect GPIO"
3056 " is ACTIVE_HIGH\n",
3057 mmc_hostname(host->mmc),
3058 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003059 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060 }
3061 host->oldstat = status;
3062 } else {
3063 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003064 }
San Mehat9d2bd732009-09-22 16:44:22 -07003065}
3066
3067static irqreturn_t
3068msmsdcc_platform_status_irq(int irq, void *dev_id)
3069{
3070 struct msmsdcc_host *host = dev_id;
3071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003072 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003073 msmsdcc_check_status((unsigned long) host);
3074 return IRQ_HANDLED;
3075}
3076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003077static irqreturn_t
3078msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3079{
3080 struct msmsdcc_host *host = dev_id;
3081
3082 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3083 spin_lock(&host->lock);
3084 if (!host->sdio_irq_disabled) {
3085 disable_irq_nosync(irq);
3086 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3087 wake_lock(&host->sdio_wlock);
3088 msmsdcc_disable_irq_wake(host);
3089 }
3090 host->sdio_irq_disabled = 1;
3091 }
3092 if (host->plat->is_sdio_al_client) {
3093 if (!host->clks_on) {
3094 msmsdcc_setup_clocks(host, true);
3095 host->clks_on = 1;
3096 }
3097 if (host->sdcc_irq_disabled) {
3098 writel_relaxed(host->mci_irqenable,
3099 host->base + MMCIMASK0);
3100 mb();
3101 enable_irq(host->core_irqres->start);
3102 host->sdcc_irq_disabled = 0;
3103 }
3104 wake_lock(&host->sdio_wlock);
3105 }
3106 spin_unlock(&host->lock);
3107
3108 return IRQ_HANDLED;
3109}
3110
San Mehat9d2bd732009-09-22 16:44:22 -07003111static void
3112msmsdcc_status_notify_cb(int card_present, void *dev_id)
3113{
3114 struct msmsdcc_host *host = dev_id;
3115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003117 card_present);
3118 msmsdcc_check_status((unsigned long) host);
3119}
3120
San Mehat9d2bd732009-09-22 16:44:22 -07003121static int
3122msmsdcc_init_dma(struct msmsdcc_host *host)
3123{
3124 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3125 host->dma.host = host;
3126 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003127 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003128
3129 if (!host->dmares)
3130 return -ENODEV;
3131
3132 host->dma.nc = dma_alloc_coherent(NULL,
3133 sizeof(struct msmsdcc_nc_dmadata),
3134 &host->dma.nc_busaddr,
3135 GFP_KERNEL);
3136 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003137 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003138 return -ENOMEM;
3139 }
3140 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3141 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3142 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3143 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3144 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003145 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003146
3147 return 0;
3148}
3149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003150#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3151/**
3152 * Allocate and Connect a SDCC peripheral's SPS endpoint
3153 *
3154 * This function allocates endpoint context and
3155 * connect it with memory endpoint by calling
3156 * appropriate SPS driver APIs.
3157 *
3158 * Also registers a SPS callback function with
3159 * SPS driver
3160 *
3161 * This function should only be called once typically
3162 * during driver probe.
3163 *
3164 * @host - Pointer to sdcc host structure
3165 * @ep - Pointer to sps endpoint data structure
3166 * @is_produce - 1 means Producer endpoint
3167 * 0 means Consumer endpoint
3168 *
3169 * @return - 0 if successful else negative value.
3170 *
3171 */
3172static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3173 struct msmsdcc_sps_ep_conn_data *ep,
3174 bool is_producer)
3175{
3176 int rc = 0;
3177 struct sps_pipe *sps_pipe_handle;
3178 struct sps_connect *sps_config = &ep->config;
3179 struct sps_register_event *sps_event = &ep->event;
3180
3181 /* Allocate endpoint context */
3182 sps_pipe_handle = sps_alloc_endpoint();
3183 if (!sps_pipe_handle) {
3184 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3185 mmc_hostname(host->mmc), is_producer);
3186 rc = -ENOMEM;
3187 goto out;
3188 }
3189
3190 /* Get default connection configuration for an endpoint */
3191 rc = sps_get_config(sps_pipe_handle, sps_config);
3192 if (rc) {
3193 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3194 " rc=%d", mmc_hostname(host->mmc),
3195 (u32)sps_pipe_handle, rc);
3196 goto get_config_err;
3197 }
3198
3199 /* Modify the default connection configuration */
3200 if (is_producer) {
3201 /*
3202 * For SDCC producer transfer, source should be
3203 * SDCC peripheral where as destination should
3204 * be system memory.
3205 */
3206 sps_config->source = host->sps.bam_handle;
3207 sps_config->destination = SPS_DEV_HANDLE_MEM;
3208 /* Producer pipe will handle this connection */
3209 sps_config->mode = SPS_MODE_SRC;
3210 sps_config->options =
3211 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3212 } else {
3213 /*
3214 * For SDCC consumer transfer, source should be
3215 * system memory where as destination should
3216 * SDCC peripheral
3217 */
3218 sps_config->source = SPS_DEV_HANDLE_MEM;
3219 sps_config->destination = host->sps.bam_handle;
3220 sps_config->mode = SPS_MODE_DEST;
3221 sps_config->options =
3222 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3223 }
3224
3225 /* Producer pipe index */
3226 sps_config->src_pipe_index = host->sps.src_pipe_index;
3227 /* Consumer pipe index */
3228 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3229 /*
3230 * This event thresold value is only significant for BAM-to-BAM
3231 * transfer. It's ignored for BAM-to-System mode transfer.
3232 */
3233 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303234
3235 /* Allocate maximum descriptor fifo size */
3236 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3237 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3239 sps_config->desc.size,
3240 &sps_config->desc.phys_base,
3241 GFP_KERNEL);
3242
Pratibhasagar V00b94332011-10-18 14:57:27 +05303243 if (!sps_config->desc.base) {
3244 rc = -ENOMEM;
3245 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3246 , mmc_hostname(host->mmc));
3247 goto get_config_err;
3248 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3250
3251 /* Establish connection between peripheral and memory endpoint */
3252 rc = sps_connect(sps_pipe_handle, sps_config);
3253 if (rc) {
3254 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3255 " rc=%d", mmc_hostname(host->mmc),
3256 (u32)sps_pipe_handle, rc);
3257 goto sps_connect_err;
3258 }
3259
3260 sps_event->mode = SPS_TRIGGER_CALLBACK;
3261 sps_event->options = SPS_O_EOT;
3262 sps_event->callback = msmsdcc_sps_complete_cb;
3263 sps_event->xfer_done = NULL;
3264 sps_event->user = (void *)host;
3265
3266 /* Register callback event for EOT (End of transfer) event. */
3267 rc = sps_register_event(sps_pipe_handle, sps_event);
3268 if (rc) {
3269 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3270 " rc=%d", mmc_hostname(host->mmc),
3271 (u32)sps_pipe_handle, rc);
3272 goto reg_event_err;
3273 }
3274 /* Now save the sps pipe handle */
3275 ep->pipe_handle = sps_pipe_handle;
3276 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3277 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3278 __func__, is_producer ? "READ" : "WRITE",
3279 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3280 goto out;
3281
3282reg_event_err:
3283 sps_disconnect(sps_pipe_handle);
3284sps_connect_err:
3285 dma_free_coherent(mmc_dev(host->mmc),
3286 sps_config->desc.size,
3287 sps_config->desc.base,
3288 sps_config->desc.phys_base);
3289get_config_err:
3290 sps_free_endpoint(sps_pipe_handle);
3291out:
3292 return rc;
3293}
3294
3295/**
3296 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3297 *
3298 * This function disconnect endpoint and deallocates
3299 * endpoint context.
3300 *
3301 * This function should only be called once typically
3302 * during driver remove.
3303 *
3304 * @host - Pointer to sdcc host structure
3305 * @ep - Pointer to sps endpoint data structure
3306 *
3307 */
3308static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3309 struct msmsdcc_sps_ep_conn_data *ep)
3310{
3311 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3312 struct sps_connect *sps_config = &ep->config;
3313 struct sps_register_event *sps_event = &ep->event;
3314
3315 sps_event->xfer_done = NULL;
3316 sps_event->callback = NULL;
3317 sps_register_event(sps_pipe_handle, sps_event);
3318 sps_disconnect(sps_pipe_handle);
3319 dma_free_coherent(mmc_dev(host->mmc),
3320 sps_config->desc.size,
3321 sps_config->desc.base,
3322 sps_config->desc.phys_base);
3323 sps_free_endpoint(sps_pipe_handle);
3324}
3325
3326/**
3327 * Reset SDCC peripheral's SPS endpoint
3328 *
3329 * This function disconnects an endpoint.
3330 *
3331 * This function should be called for reseting
3332 * SPS endpoint when data transfer error is
3333 * encountered during data transfer. This
3334 * can be considered as soft reset to endpoint.
3335 *
3336 * This function should only be called if
3337 * msmsdcc_sps_init() is already called.
3338 *
3339 * @host - Pointer to sdcc host structure
3340 * @ep - Pointer to sps endpoint data structure
3341 *
3342 * @return - 0 if successful else negative value.
3343 */
3344static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3345 struct msmsdcc_sps_ep_conn_data *ep)
3346{
3347 int rc = 0;
3348 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3349
3350 rc = sps_disconnect(sps_pipe_handle);
3351 if (rc) {
3352 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3353 " rc=%d", mmc_hostname(host->mmc), __func__,
3354 (u32)sps_pipe_handle, rc);
3355 goto out;
3356 }
3357 out:
3358 return rc;
3359}
3360
3361/**
3362 * Restore SDCC peripheral's SPS endpoint
3363 *
3364 * This function connects an endpoint.
3365 *
3366 * This function should be called for restoring
3367 * SPS endpoint after data transfer error is
3368 * encountered during data transfer. This
3369 * can be considered as soft reset to endpoint.
3370 *
3371 * This function should only be called if
3372 * msmsdcc_sps_reset_ep() is called before.
3373 *
3374 * @host - Pointer to sdcc host structure
3375 * @ep - Pointer to sps endpoint data structure
3376 *
3377 * @return - 0 if successful else negative value.
3378 */
3379static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3380 struct msmsdcc_sps_ep_conn_data *ep)
3381{
3382 int rc = 0;
3383 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3384 struct sps_connect *sps_config = &ep->config;
3385 struct sps_register_event *sps_event = &ep->event;
3386
3387 /* Establish connection between peripheral and memory endpoint */
3388 rc = sps_connect(sps_pipe_handle, sps_config);
3389 if (rc) {
3390 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3391 " rc=%d", mmc_hostname(host->mmc), __func__,
3392 (u32)sps_pipe_handle, rc);
3393 goto out;
3394 }
3395
3396 /* Register callback event for EOT (End of transfer) event. */
3397 rc = sps_register_event(sps_pipe_handle, sps_event);
3398 if (rc) {
3399 pr_err("%s: %s: sps_register_event() failed!!!"
3400 " pipe_handle=0x%x, rc=%d",
3401 mmc_hostname(host->mmc), __func__,
3402 (u32)sps_pipe_handle, rc);
3403 goto reg_event_err;
3404 }
3405 goto out;
3406
3407reg_event_err:
3408 sps_disconnect(sps_pipe_handle);
3409out:
3410 return rc;
3411}
3412
3413/**
3414 * Initialize SPS HW connected with SDCC core
3415 *
3416 * This function register BAM HW resources with
3417 * SPS driver and then initialize 2 SPS endpoints
3418 *
3419 * This function should only be called once typically
3420 * during driver probe.
3421 *
3422 * @host - Pointer to sdcc host structure
3423 *
3424 * @return - 0 if successful else negative value.
3425 *
3426 */
3427static int msmsdcc_sps_init(struct msmsdcc_host *host)
3428{
3429 int rc = 0;
3430 struct sps_bam_props bam = {0};
3431
3432 host->bam_base = ioremap(host->bam_memres->start,
3433 resource_size(host->bam_memres));
3434 if (!host->bam_base) {
3435 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3436 " size=0x%x", mmc_hostname(host->mmc),
3437 host->bam_memres->start,
3438 (host->bam_memres->end -
3439 host->bam_memres->start));
3440 rc = -ENOMEM;
3441 goto out;
3442 }
3443
3444 bam.phys_addr = host->bam_memres->start;
3445 bam.virt_addr = host->bam_base;
3446 /*
3447 * This event thresold value is only significant for BAM-to-BAM
3448 * transfer. It's ignored for BAM-to-System mode transfer.
3449 */
3450 bam.event_threshold = 0x10; /* Pipe event threshold */
3451 /*
3452 * This threshold controls when the BAM publish
3453 * the descriptor size on the sideband interface.
3454 * SPS HW will only be used when
3455 * data transfer size > MCI_FIFOSIZE (64 bytes).
3456 * PIO mode will be used when
3457 * data transfer size < MCI_FIFOSIZE (64 bytes).
3458 * So set this thresold value to 64 bytes.
3459 */
3460 bam.summing_threshold = 64;
3461 /* SPS driver wll handle the SDCC BAM IRQ */
3462 bam.irq = (u32)host->bam_irqres->start;
3463 bam.manage = SPS_BAM_MGR_LOCAL;
3464
3465 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3466 (u32)bam.phys_addr);
3467 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3468 (u32)bam.virt_addr);
3469
3470 /* Register SDCC Peripheral BAM device to SPS driver */
3471 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3472 if (rc) {
3473 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3474 mmc_hostname(host->mmc), rc);
3475 goto reg_bam_err;
3476 }
3477 pr_info("%s: BAM device registered. bam_handle=0x%x",
3478 mmc_hostname(host->mmc), host->sps.bam_handle);
3479
3480 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3481 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3482
3483 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3484 SPS_PROD_PERIPHERAL);
3485 if (rc)
3486 goto sps_reset_err;
3487 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3488 SPS_CONS_PERIPHERAL);
3489 if (rc)
3490 goto cons_conn_err;
3491
3492 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3493 mmc_hostname(host->mmc),
3494 (unsigned long long)host->bam_memres->start,
3495 (unsigned int)host->bam_irqres->start);
3496 goto out;
3497
3498cons_conn_err:
3499 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3500sps_reset_err:
3501 sps_deregister_bam_device(host->sps.bam_handle);
3502reg_bam_err:
3503 iounmap(host->bam_base);
3504out:
3505 return rc;
3506}
3507
3508/**
3509 * De-initialize SPS HW connected with SDCC core
3510 *
3511 * This function deinitialize SPS endpoints and then
3512 * deregisters BAM resources from SPS driver.
3513 *
3514 * This function should only be called once typically
3515 * during driver remove.
3516 *
3517 * @host - Pointer to sdcc host structure
3518 *
3519 */
3520static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3521{
3522 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3523 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3524 sps_deregister_bam_device(host->sps.bam_handle);
3525 iounmap(host->bam_base);
3526}
3527#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3528
3529static ssize_t
3530show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3531{
3532 struct mmc_host *mmc = dev_get_drvdata(dev);
3533 struct msmsdcc_host *host = mmc_priv(mmc);
3534 int poll;
3535 unsigned long flags;
3536
3537 spin_lock_irqsave(&host->lock, flags);
3538 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3539 spin_unlock_irqrestore(&host->lock, flags);
3540
3541 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3542}
3543
3544static ssize_t
3545set_polling(struct device *dev, struct device_attribute *attr,
3546 const char *buf, size_t count)
3547{
3548 struct mmc_host *mmc = dev_get_drvdata(dev);
3549 struct msmsdcc_host *host = mmc_priv(mmc);
3550 int value;
3551 unsigned long flags;
3552
3553 sscanf(buf, "%d", &value);
3554
3555 spin_lock_irqsave(&host->lock, flags);
3556 if (value) {
3557 mmc->caps |= MMC_CAP_NEEDS_POLL;
3558 mmc_detect_change(host->mmc, 0);
3559 } else {
3560 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3561 }
3562#ifdef CONFIG_HAS_EARLYSUSPEND
3563 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3564#endif
3565 spin_unlock_irqrestore(&host->lock, flags);
3566 return count;
3567}
3568
3569static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3570 show_polling, set_polling);
3571static struct attribute *dev_attrs[] = {
3572 &dev_attr_polling.attr,
3573 NULL,
3574};
3575static struct attribute_group dev_attr_grp = {
3576 .attrs = dev_attrs,
3577};
3578
3579#ifdef CONFIG_HAS_EARLYSUSPEND
3580static void msmsdcc_early_suspend(struct early_suspend *h)
3581{
3582 struct msmsdcc_host *host =
3583 container_of(h, struct msmsdcc_host, early_suspend);
3584 unsigned long flags;
3585
3586 spin_lock_irqsave(&host->lock, flags);
3587 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3588 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3589 spin_unlock_irqrestore(&host->lock, flags);
3590};
3591static void msmsdcc_late_resume(struct early_suspend *h)
3592{
3593 struct msmsdcc_host *host =
3594 container_of(h, struct msmsdcc_host, early_suspend);
3595 unsigned long flags;
3596
3597 if (host->polling_enabled) {
3598 spin_lock_irqsave(&host->lock, flags);
3599 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3600 mmc_detect_change(host->mmc, 0);
3601 spin_unlock_irqrestore(&host->lock, flags);
3602 }
3603};
3604#endif
3605
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303606void msmsdcc_print_regs(const char *name, void __iomem *base,
3607 unsigned int no_of_regs)
3608{
3609 unsigned int i;
3610
3611 if (!base)
3612 return;
3613 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3614 name, (u32)base);
3615 for (i = 0; i < no_of_regs; i = i + 4) {
3616 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3617 (u32)readl_relaxed(base + i*4),
3618 (u32)readl_relaxed(base + ((i+1)*4)),
3619 (u32)readl_relaxed(base + ((i+2)*4)),
3620 (u32)readl_relaxed(base + ((i+3)*4)));
3621 }
3622}
3623
3624static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3625{
3626 /* Dump current state of SDCC clocks, power and irq */
3627 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3628 (host->pwr ? "ON" : "OFF"));
3629 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3630 mmc_hostname(host->mmc),
3631 (host->clks_on ? "ON" : "OFF"),
3632 (u32)clk_get_rate(host->clk));
3633 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3634 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3635
3636 /* Now dump SDCC registers. Don't print FIFO registers */
3637 if (host->clks_on)
3638 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3639
3640 if (host->curr.data) {
3641 if (msmsdcc_check_dma_op_req(host->curr.data))
3642 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3643 else if (host->is_dma_mode)
3644 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3645 mmc_hostname(host->mmc), host->dma.busy,
3646 host->dma.channel, host->dma.crci);
3647 else if (host->is_sps_mode)
3648 pr_info("%s: SPS mode: busy=%d\n",
3649 mmc_hostname(host->mmc), host->sps.busy);
3650
3651 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3652 mmc_hostname(host->mmc), host->curr.xfer_size,
3653 host->curr.data_xfered, host->curr.xfer_remain);
3654 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3655 " wait_for_auto_prog_done=%d,"
3656 " got_auto_prog_done=%d\n",
3657 mmc_hostname(host->mmc), host->curr.got_dataend,
3658 host->prog_enable, host->curr.wait_for_auto_prog_done,
3659 host->curr.got_auto_prog_done);
3660 }
3661
3662}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3664{
3665 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3666 struct mmc_request *mrq;
3667 unsigned long flags;
3668
3669 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003670 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003671 pr_info("%s: %s: dummy CMD52 timeout\n",
3672 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003673 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674 }
3675
3676 mrq = host->curr.mrq;
3677
3678 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303679 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3680 mrq->cmd->opcode);
3681 msmsdcc_dump_sdcc_state(host);
3682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003683 if (!mrq->cmd->error)
3684 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303685 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003686 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003687 if (mrq->data && !mrq->data->error)
3688 mrq->data->error = -ETIMEDOUT;
3689 host->curr.data_xfered = 0;
3690 if (host->dma.sg && host->is_dma_mode) {
3691 msm_dmov_stop_cmd(host->dma.channel,
3692 &host->dma.hdr, 0);
3693 } else if (host->sps.sg && host->is_sps_mode) {
3694 /* Stop current SPS transfer */
3695 msmsdcc_sps_exit_curr_xfer(host);
3696 } else {
3697 msmsdcc_reset_and_restore(host);
3698 msmsdcc_stop_data(host);
3699 if (mrq->data && mrq->data->stop)
3700 msmsdcc_start_command(host,
3701 mrq->data->stop, 0);
3702 else
3703 msmsdcc_request_end(host, mrq);
3704 }
3705 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303706 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707 msmsdcc_reset_and_restore(host);
3708 msmsdcc_request_end(host, mrq);
3709 }
3710 }
3711 spin_unlock_irqrestore(&host->lock, flags);
3712}
3713
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303714static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3715{
3716 int i, ret;
3717 struct mmc_platform_data *pdata;
3718 struct device_node *np = dev->of_node;
3719 u32 bus_width = 0;
3720 u32 *clk_table;
3721 int clk_table_len;
3722 u32 *sup_voltages;
3723 int sup_volt_len;
3724
3725 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3726 if (!pdata) {
3727 dev_err(dev, "could not allocate memory for platform data\n");
3728 goto err;
3729 }
3730
3731 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3732 if (bus_width == 8) {
3733 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3734 } else if (bus_width == 4) {
3735 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3736 } else {
3737 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3738 pdata->mmc_bus_width = 0;
3739 }
3740
3741 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3742 size_t sz;
3743 sz = sup_volt_len / sizeof(*sup_voltages);
3744 if (sz > 0) {
3745 sup_voltages = devm_kzalloc(dev,
3746 sz * sizeof(*sup_voltages), GFP_KERNEL);
3747 if (!sup_voltages) {
3748 dev_err(dev, "No memory for supported voltage\n");
3749 goto err;
3750 }
3751
3752 ret = of_property_read_u32_array(np,
3753 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3754 if (ret < 0) {
3755 dev_err(dev, "error while reading voltage"
3756 "ranges %d\n", ret);
3757 goto err;
3758 }
3759 } else {
3760 dev_err(dev, "No supported voltages\n");
3761 goto err;
3762 }
3763 for (i = 0; i < sz; i += 2) {
3764 u32 mask;
3765
3766 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3767 sup_voltages[i + 1]);
3768 if (!mask)
3769 dev_err(dev, "Invalide voltage range %d\n", i);
3770 pdata->ocr_mask |= mask;
3771 }
3772 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3773 } else {
3774 dev_err(dev, "Supported voltage range not specified\n");
3775 }
3776
3777 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3778 size_t sz;
3779 sz = clk_table_len / sizeof(*clk_table);
3780
3781 if (sz > 0) {
3782 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3783 GFP_KERNEL);
3784 if (!clk_table) {
3785 dev_err(dev, "No memory for clock table\n");
3786 goto err;
3787 }
3788
3789 ret = of_property_read_u32_array(np,
3790 "qcom,sdcc-clk-rates", clk_table, sz);
3791 if (ret < 0) {
3792 dev_err(dev, "error while reading clk"
3793 "table %d\n", ret);
3794 goto err;
3795 }
3796 } else {
3797 dev_err(dev, "clk_table not specified\n");
3798 goto err;
3799 }
3800 pdata->sup_clk_table = clk_table;
3801 pdata->sup_clk_cnt = sz;
3802 } else {
3803 dev_err(dev, "Supported clock rates not specified\n");
3804 }
3805
3806 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3807 pdata->nonremovable = true;
3808 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3809 pdata->disable_cmd23 = true;
3810
3811 return pdata;
3812err:
3813 return NULL;
3814}
3815
San Mehat9d2bd732009-09-22 16:44:22 -07003816static int
3817msmsdcc_probe(struct platform_device *pdev)
3818{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303819 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003820 struct msmsdcc_host *host;
3821 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003822 unsigned long flags;
3823 struct resource *core_irqres = NULL;
3824 struct resource *bam_irqres = NULL;
3825 struct resource *core_memres = NULL;
3826 struct resource *dml_memres = NULL;
3827 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003828 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003829 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303830 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003831 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003832
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303833 if (pdev->dev.of_node) {
3834 plat = msmsdcc_populate_pdata(&pdev->dev);
3835 of_property_read_u32((&pdev->dev)->of_node,
3836 "cell-index", &pdev->id);
3837 } else {
3838 plat = pdev->dev.platform_data;
3839 }
3840
San Mehat9d2bd732009-09-22 16:44:22 -07003841 /* must have platform data */
3842 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003843 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003844 ret = -EINVAL;
3845 goto out;
3846 }
3847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003849 return -EINVAL;
3850
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303851 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3852 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3853 return -EINVAL;
3854 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855
San Mehat9d2bd732009-09-22 16:44:22 -07003856 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003857 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003858 return -ENXIO;
3859 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303860 if (pdev->dev.of_node) {
3861 /*
3862 * Device tree iomem resources are only accessible by index.
3863 * index = 0 -> SDCC register interface
3864 * index = 1 -> DML register interface
3865 * index = 2 -> BAM register interface
3866 * IRQ resources:
3867 * index = 0 -> SDCC IRQ
3868 * index = 1 -> BAM IRQ
3869 */
3870 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3871 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3872 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3873 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3874 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3875 } else {
3876 for (i = 0; i < pdev->num_resources; i++) {
3877 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3878 if (!strncmp(pdev->resource[i].name,
3879 "sdcc_dml_addr",
3880 sizeof("sdcc_dml_addr")))
3881 dml_memres = &pdev->resource[i];
3882 else if (!strncmp(pdev->resource[i].name,
3883 "sdcc_bam_addr",
3884 sizeof("sdcc_bam_addr")))
3885 bam_memres = &pdev->resource[i];
3886 else
3887 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003888
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303889 }
3890 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3891 if (!strncmp(pdev->resource[i].name,
3892 "sdcc_bam_irq",
3893 sizeof("sdcc_bam_irq")))
3894 bam_irqres = &pdev->resource[i];
3895 else
3896 core_irqres = &pdev->resource[i];
3897 }
3898 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3899 if (!strncmp(pdev->resource[i].name,
3900 "sdcc_dma_chnl",
3901 sizeof("sdcc_dma_chnl")))
3902 dmares = &pdev->resource[i];
3903 else if (!strncmp(pdev->resource[i].name,
3904 "sdcc_dma_crci",
3905 sizeof("sdcc_dma_crci")))
3906 dma_crci_res = &pdev->resource[i];
3907 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003908 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909 }
3910
3911 if (!core_irqres || !core_memres) {
3912 pr_err("%s: Invalid sdcc core resource\n", __func__);
3913 return -ENXIO;
3914 }
3915
3916 /*
3917 * Both BAM and DML memory resource should be preset.
3918 * BAM IRQ resource should also be present.
3919 */
3920 if ((bam_memres && !dml_memres) ||
3921 (!bam_memres && dml_memres) ||
3922 ((bam_memres && dml_memres) && !bam_irqres)) {
3923 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003924 return -ENXIO;
3925 }
3926
3927 /*
3928 * Setup our host structure
3929 */
San Mehat9d2bd732009-09-22 16:44:22 -07003930 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3931 if (!mmc) {
3932 ret = -ENOMEM;
3933 goto out;
3934 }
3935
3936 host = mmc_priv(mmc);
3937 host->pdev_id = pdev->id;
3938 host->plat = plat;
3939 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003940 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303941
3942 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003943 host->is_sps_mode = 1;
3944 else if (dmares)
3945 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003946
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003947 host->base = ioremap(core_memres->start,
3948 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003949 if (!host->base) {
3950 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003952 }
3953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954 host->core_irqres = core_irqres;
3955 host->bam_irqres = bam_irqres;
3956 host->core_memres = core_memres;
3957 host->dml_memres = dml_memres;
3958 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003959 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003960 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003961 spin_lock_init(&host->lock);
3962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963#ifdef CONFIG_MMC_EMBEDDED_SDIO
3964 if (plat->embedded_sdio)
3965 mmc_set_embedded_sdio_data(mmc,
3966 &plat->embedded_sdio->cis,
3967 &plat->embedded_sdio->cccr,
3968 plat->embedded_sdio->funcs,
3969 plat->embedded_sdio->num_funcs);
3970#endif
3971
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303972 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3973 (unsigned long)host);
3974
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003975 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3976 (unsigned long)host);
3977 if (host->is_dma_mode) {
3978 /* Setup DMA */
3979 ret = msmsdcc_init_dma(host);
3980 if (ret)
3981 goto ioremap_free;
3982 } else {
3983 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003984 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003985 }
3986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987 /*
3988 * Setup SDCC clock if derived from Dayatona
3989 * fabric core clock.
3990 */
3991 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003992 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003993 if (!IS_ERR(host->dfab_pclk)) {
3994 /* Set the clock rate to 64MHz for max. performance */
3995 ret = clk_set_rate(host->dfab_pclk, 64000000);
3996 if (ret)
3997 goto dfab_pclk_put;
3998 ret = clk_enable(host->dfab_pclk);
3999 if (ret)
4000 goto dfab_pclk_put;
4001 } else
4002 goto dma_free;
4003 }
4004
4005 /*
4006 * Setup main peripheral bus clock
4007 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004008 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004009 if (!IS_ERR(host->pclk)) {
4010 ret = clk_enable(host->pclk);
4011 if (ret)
4012 goto pclk_put;
4013
4014 host->pclk_rate = clk_get_rate(host->pclk);
4015 }
4016
4017 /*
4018 * Setup SDC MMC clock
4019 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004020 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004021 if (IS_ERR(host->clk)) {
4022 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004024 }
4025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4027 if (ret) {
4028 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4029 goto clk_put;
4030 }
4031
4032 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004033 if (ret)
4034 goto clk_put;
4035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304037 if (!host->clk_rate)
4038 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304039
4040 /*
4041 * Lookup the Controller Version, to identify the supported features
4042 * Version number read as 0 would indicate SDCC3 or earlier versions
4043 */
4044 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4045 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4046 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304047 /*
4048 * Set the register write delay according to min. clock frequency
4049 * supported and update later when the host->clk_rate changes.
4050 */
4051 host->reg_write_delay =
4052 (1 + ((3 * USEC_PER_SEC) /
4053 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054
4055 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304056 /* Apply Hard reset to SDCC to put it in power on default state */
4057 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004058
4059 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004060 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004062 goto clk_disable;
4063 }
4064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065
4066 /* Clocks has to be running before accessing SPS/DML HW blocks */
4067 if (host->is_sps_mode) {
4068 /* Initialize SPS */
4069 ret = msmsdcc_sps_init(host);
4070 if (ret)
4071 goto vreg_deinit;
4072 /* Initialize DML */
4073 ret = msmsdcc_dml_init(host);
4074 if (ret)
4075 goto sps_exit;
4076 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304077 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004078
San Mehat9d2bd732009-09-22 16:44:22 -07004079 /*
4080 * Setup MMC host structure
4081 */
4082 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004083 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4084 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004085 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4087 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004088
San Mehat9d2bd732009-09-22 16:44:22 -07004089 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304090 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304091
4092 /*
4093 * If we send the CMD23 before multi block write/read command
4094 * then we need not to send CMD12 at the end of the transfer.
4095 * If we don't send the CMD12 then only way to detect the PROG_DONE
4096 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4097 * controller. So let's enable the CMD23 for SDCC4 only.
4098 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304099 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304100 mmc->caps |= MMC_CAP_CMD23;
4101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 mmc->caps |= plat->uhs_caps;
4103 /*
4104 * XPC controls the maximum current in the default speed mode of SDXC
4105 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4106 * XPC=1 means 150mA (max.) and speed class is supported.
4107 */
4108 if (plat->xpc_cap)
4109 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4110 MMC_CAP_SET_XPC_180);
4111
4112 if (plat->nonremovable)
4113 mmc->caps |= MMC_CAP_NONREMOVABLE;
4114#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4115 mmc->caps |= MMC_CAP_SDIO_IRQ;
4116#endif
4117
4118 if (plat->is_sdio_al_client)
4119 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004120
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304121 mmc->max_segs = msmsdcc_get_nr_sg(host);
4122 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4123 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004124
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304125 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304126 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 writel_relaxed(0, host->base + MMCIMASK0);
4129 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4132 mb();
4133 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004135 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4136 DRIVER_NAME " (cmd)", host);
4137 if (ret)
4138 goto dml_exit;
4139
4140 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4141 DRIVER_NAME " (pio)", host);
4142 if (ret)
4143 goto irq_free;
4144
4145 /*
4146 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4147 * IRQ is un-necessarily being monitored by MPM (Modem power
4148 * management block) during idle-power collapse. The MPM will be
4149 * configured to monitor the DATA1 GPIO line with level-low trigger
4150 * and thus depending on the GPIO status, it prevents TCXO shutdown
4151 * during idle-power collapse.
4152 */
4153 disable_irq(core_irqres->start);
4154 host->sdcc_irq_disabled = 1;
4155
4156 if (plat->sdiowakeup_irq) {
4157 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4158 mmc_hostname(mmc));
4159 ret = request_irq(plat->sdiowakeup_irq,
4160 msmsdcc_platform_sdiowakeup_irq,
4161 IRQF_SHARED | IRQF_TRIGGER_LOW,
4162 DRIVER_NAME "sdiowakeup", host);
4163 if (ret) {
4164 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4165 plat->sdiowakeup_irq, ret);
4166 goto pio_irq_free;
4167 } else {
4168 spin_lock_irqsave(&host->lock, flags);
4169 if (!host->sdio_irq_disabled) {
4170 disable_irq_nosync(plat->sdiowakeup_irq);
4171 host->sdio_irq_disabled = 1;
4172 }
4173 spin_unlock_irqrestore(&host->lock, flags);
4174 }
4175 }
4176
4177 if (plat->cfg_mpm_sdiowakeup) {
4178 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4179 mmc_hostname(mmc));
4180 }
4181
4182 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4183 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004184 /*
4185 * Setup card detect change
4186 */
4187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004189 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004191 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004192 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004193
Krishna Konda941604a2012-01-10 17:46:34 -08004194 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004195 }
San Mehat9d2bd732009-09-22 16:44:22 -07004196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004197 if (plat->status_irq) {
4198 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004199 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004201 DRIVER_NAME " (slot)",
4202 host);
4203 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004204 pr_err("Unable to get slot IRQ %d (%d)\n",
4205 plat->status_irq, ret);
4206 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004207 }
4208 } else if (plat->register_status_notify) {
4209 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4210 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004211 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004212 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004213
4214 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004215
4216 ret = pm_runtime_set_active(&(pdev)->dev);
4217 if (ret < 0)
4218 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4219 __func__, ret);
4220 /*
4221 * There is no notion of suspend/resume for SD/MMC/SDIO
4222 * cards. So host can be suspended/resumed with out
4223 * worrying about its children.
4224 */
4225 pm_suspend_ignore_children(&(pdev)->dev, true);
4226
4227 /*
4228 * MMC/SD/SDIO bus suspend/resume operations are defined
4229 * only for the slots that will be used for non-removable
4230 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4231 * defined. Otherwise, they simply become card removal and
4232 * insertion events during suspend and resume respectively.
4233 * Hence, enable run-time PM only for slots for which bus
4234 * suspend/resume operations are defined.
4235 */
4236#ifdef CONFIG_MMC_UNSAFE_RESUME
4237 /*
4238 * If this capability is set, MMC core will enable/disable host
4239 * for every claim/release operation on a host. We use this
4240 * notification to increment/decrement runtime pm usage count.
4241 */
4242 mmc->caps |= MMC_CAP_DISABLE;
4243 pm_runtime_enable(&(pdev)->dev);
4244#else
4245 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4246 mmc->caps |= MMC_CAP_DISABLE;
4247 pm_runtime_enable(&(pdev)->dev);
4248 }
4249#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304250#ifndef CONFIG_PM_RUNTIME
4251 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4252#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4254 (unsigned long)host);
4255
San Mehat9d2bd732009-09-22 16:44:22 -07004256 mmc_add_host(mmc);
4257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004258#ifdef CONFIG_HAS_EARLYSUSPEND
4259 host->early_suspend.suspend = msmsdcc_early_suspend;
4260 host->early_suspend.resume = msmsdcc_late_resume;
4261 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4262 register_early_suspend(&host->early_suspend);
4263#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004264
Krishna Konda25786ec2011-07-25 16:21:36 -07004265 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4266 " dmacrcri %d\n", mmc_hostname(mmc),
4267 (unsigned long long)core_memres->start,
4268 (unsigned int) core_irqres->start,
4269 (unsigned int) plat->status_irq, host->dma.channel,
4270 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004271
4272 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4273 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4274 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4275 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4276 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4277 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4278 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4279 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4280 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4281 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4282 host->eject);
4283 pr_info("%s: Power save feature enable = %d\n",
4284 mmc_hostname(mmc), msmsdcc_pwrsave);
4285
Krishna Konda25786ec2011-07-25 16:21:36 -07004286 if (host->is_dma_mode && host->dma.channel != -1
4287 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004288 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004290 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004291 mmc_hostname(mmc), host->dma.cmd_busaddr,
4292 host->dma.cmdptr_busaddr);
4293 } else if (host->is_sps_mode) {
4294 pr_info("%s: SPS-BAM data transfer mode available\n",
4295 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004296 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004297 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004299#if defined(CONFIG_DEBUG_FS)
4300 msmsdcc_dbg_createhost(host);
4301#endif
4302 if (!plat->status_irq) {
4303 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4304 if (ret)
4305 goto platform_irq_free;
4306 }
San Mehat9d2bd732009-09-22 16:44:22 -07004307 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308
4309 platform_irq_free:
4310 del_timer_sync(&host->req_tout_timer);
4311 pm_runtime_disable(&(pdev)->dev);
4312 pm_runtime_set_suspended(&(pdev)->dev);
4313
4314 if (plat->status_irq)
4315 free_irq(plat->status_irq, host);
4316 sdiowakeup_irq_free:
4317 wake_lock_destroy(&host->sdio_suspend_wlock);
4318 if (plat->sdiowakeup_irq)
4319 free_irq(plat->sdiowakeup_irq, host);
4320 pio_irq_free:
4321 if (plat->sdiowakeup_irq)
4322 wake_lock_destroy(&host->sdio_wlock);
4323 free_irq(core_irqres->start, host);
4324 irq_free:
4325 free_irq(core_irqres->start, host);
4326 dml_exit:
4327 if (host->is_sps_mode)
4328 msmsdcc_dml_exit(host);
4329 sps_exit:
4330 if (host->is_sps_mode)
4331 msmsdcc_sps_exit(host);
4332 vreg_deinit:
4333 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004334 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004335 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004336 clk_put:
4337 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 pclk_disable:
4339 if (!IS_ERR(host->pclk))
4340 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004341 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342 if (!IS_ERR(host->pclk))
4343 clk_put(host->pclk);
4344 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4345 clk_disable(host->dfab_pclk);
4346 dfab_pclk_put:
4347 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4348 clk_put(host->dfab_pclk);
4349 dma_free:
4350 if (host->is_dma_mode) {
4351 if (host->dmares)
4352 dma_free_coherent(NULL,
4353 sizeof(struct msmsdcc_nc_dmadata),
4354 host->dma.nc, host->dma.nc_busaddr);
4355 }
4356 ioremap_free:
4357 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004358 host_free:
4359 mmc_free_host(mmc);
4360 out:
4361 return ret;
4362}
4363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004364static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004365{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4367 struct mmc_platform_data *plat;
4368 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004370 if (!mmc)
4371 return -ENXIO;
4372
4373 if (pm_runtime_suspended(&(pdev)->dev))
4374 pm_runtime_resume(&(pdev)->dev);
4375
4376 host = mmc_priv(mmc);
4377
4378 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4379 plat = host->plat;
4380
4381 if (!plat->status_irq)
4382 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4383
4384 del_timer_sync(&host->req_tout_timer);
4385 tasklet_kill(&host->dma_tlet);
4386 tasklet_kill(&host->sps.tlet);
4387 mmc_remove_host(mmc);
4388
4389 if (plat->status_irq)
4390 free_irq(plat->status_irq, host);
4391
4392 wake_lock_destroy(&host->sdio_suspend_wlock);
4393 if (plat->sdiowakeup_irq) {
4394 wake_lock_destroy(&host->sdio_wlock);
4395 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4396 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004397 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004398
4399 free_irq(host->core_irqres->start, host);
4400 free_irq(host->core_irqres->start, host);
4401
4402 clk_put(host->clk);
4403 if (!IS_ERR(host->pclk))
4404 clk_put(host->pclk);
4405 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4406 clk_put(host->dfab_pclk);
4407
4408 msmsdcc_vreg_init(host, false);
4409
4410 if (host->is_dma_mode) {
4411 if (host->dmares)
4412 dma_free_coherent(NULL,
4413 sizeof(struct msmsdcc_nc_dmadata),
4414 host->dma.nc, host->dma.nc_busaddr);
4415 }
4416
4417 if (host->is_sps_mode) {
4418 msmsdcc_dml_exit(host);
4419 msmsdcc_sps_exit(host);
4420 }
4421
4422 iounmap(host->base);
4423 mmc_free_host(mmc);
4424
4425#ifdef CONFIG_HAS_EARLYSUSPEND
4426 unregister_early_suspend(&host->early_suspend);
4427#endif
4428 pm_runtime_disable(&(pdev)->dev);
4429 pm_runtime_set_suspended(&(pdev)->dev);
4430
4431 return 0;
4432}
4433
4434#ifdef CONFIG_MSM_SDIO_AL
4435int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4436{
4437 struct msmsdcc_host *host = mmc_priv(mmc);
4438 unsigned long flags;
4439
4440 spin_lock_irqsave(&host->lock, flags);
4441 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4442 enable ? "En" : "Dis");
4443
4444 if (enable) {
4445 if (!host->sdcc_irq_disabled) {
4446 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304447 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004448 host->sdcc_irq_disabled = 1;
4449 }
4450
4451 if (host->clks_on) {
4452 msmsdcc_setup_clocks(host, false);
4453 host->clks_on = 0;
4454 }
4455
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304456 if (host->plat->sdio_lpm_gpio_setup &&
4457 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004458 spin_unlock_irqrestore(&host->lock, flags);
4459 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4460 spin_lock_irqsave(&host->lock, flags);
4461 host->sdio_gpio_lpm = 1;
4462 }
4463
4464 if (host->sdio_irq_disabled) {
4465 msmsdcc_enable_irq_wake(host);
4466 enable_irq(host->plat->sdiowakeup_irq);
4467 host->sdio_irq_disabled = 0;
4468 }
4469 } else {
4470 if (!host->sdio_irq_disabled) {
4471 disable_irq_nosync(host->plat->sdiowakeup_irq);
4472 host->sdio_irq_disabled = 1;
4473 msmsdcc_disable_irq_wake(host);
4474 }
4475
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304476 if (host->plat->sdio_lpm_gpio_setup &&
4477 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004478 spin_unlock_irqrestore(&host->lock, flags);
4479 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4480 spin_lock_irqsave(&host->lock, flags);
4481 host->sdio_gpio_lpm = 0;
4482 }
4483
4484 if (!host->clks_on) {
4485 msmsdcc_setup_clocks(host, true);
4486 host->clks_on = 1;
4487 }
4488
4489 if (host->sdcc_irq_disabled) {
4490 writel_relaxed(host->mci_irqenable,
4491 host->base + MMCIMASK0);
4492 mb();
4493 enable_irq(host->core_irqres->start);
4494 host->sdcc_irq_disabled = 0;
4495 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004496 }
4497 spin_unlock_irqrestore(&host->lock, flags);
4498 return 0;
4499}
4500#else
4501int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4502{
4503 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004504}
4505#endif
4506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004507#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004508static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004509msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004510{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511 struct mmc_host *mmc = dev_get_drvdata(dev);
4512 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004513 int rc = 0;
4514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004515 if (host->plat->is_sdio_al_client)
4516 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304517 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004518 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004519 host->sdcc_suspending = 1;
4520 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004522 /*
4523 * If the clocks are already turned off by SDIO clients (as
4524 * part of LPM), then clocks should be turned on before
4525 * calling mmc_suspend_host() because mmc_suspend_host might
4526 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304527 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528 * cards, clocks will be turned on before mmc_suspend_host
4529 * and turned off after mmc_suspend_host.
4530 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304531 if (mmc->card && mmc_card_sdio(mmc->card)) {
4532 mmc->ios.clock = host->clk_rate;
4533 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4534 }
San Mehat9d2bd732009-09-22 16:44:22 -07004535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004536 /*
4537 * MMC core thinks that host is disabled by now since
4538 * runtime suspend is scheduled after msmsdcc_disable()
4539 * is called. Thus, MMC core will try to enable the host
4540 * while suspending it. This results in a synchronous
4541 * runtime resume request while in runtime suspending
4542 * context and hence inorder to complete this resume
4543 * requet, it will wait for suspend to be complete,
4544 * but runtime suspend also can not proceed further
4545 * until the host is resumed. Thus, it leads to a hang.
4546 * Hence, increase the pm usage count before suspending
4547 * the host so that any resume requests after this will
4548 * simple become pm usage counter increment operations.
4549 */
4550 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304551 /* If there is pending detect work abort runtime suspend */
4552 if (unlikely(work_busy(&mmc->detect.work)))
4553 rc = -EAGAIN;
4554 else
4555 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004556 pm_runtime_put_noidle(dev);
4557
4558 if (!rc) {
4559 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4560 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4561 disable_irq(host->core_irqres->start);
4562 host->sdcc_irq_disabled = 1;
4563
4564 /*
4565 * If MMC core level suspend is not supported,
4566 * turn off clocks to allow deep sleep (TCXO
4567 * shutdown).
4568 */
4569 mmc->ios.clock = 0;
4570 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4571 enable_irq(host->core_irqres->start);
4572 host->sdcc_irq_disabled = 0;
4573
4574 if (host->plat->sdiowakeup_irq) {
4575 host->sdio_irq_disabled = 0;
4576 msmsdcc_enable_irq_wake(host);
4577 enable_irq(host->plat->sdiowakeup_irq);
4578 }
4579 }
4580 }
4581 host->sdcc_suspending = 0;
4582 mmc->suspend_task = NULL;
4583 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4584 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004585 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304586 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004587 return rc;
4588}
4589
4590static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004591msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004592{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 struct mmc_host *mmc = dev_get_drvdata(dev);
4594 struct msmsdcc_host *host = mmc_priv(mmc);
4595 unsigned long flags;
4596
4597 if (host->plat->is_sdio_al_client)
4598 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004599
Sahitya Tummala7661a452011-07-18 13:28:35 +05304600 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004601 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004602 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4603 if (host->sdcc_irq_disabled) {
4604 enable_irq(host->core_irqres->start);
4605 host->sdcc_irq_disabled = 0;
4606 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304607 mmc->ios.clock = host->clk_rate;
4608 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004609
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304610 spin_lock_irqsave(&host->lock, flags);
4611 writel_relaxed(host->mci_irqenable,
4612 host->base + MMCIMASK0);
4613 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004614
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304615 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4616 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004617 if (host->plat->sdiowakeup_irq) {
4618 disable_irq_nosync(
4619 host->plat->sdiowakeup_irq);
4620 msmsdcc_disable_irq_wake(host);
4621 host->sdio_irq_disabled = 1;
4622 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304623 }
San Mehat9d2bd732009-09-22 16:44:22 -07004624
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304625 spin_unlock_irqrestore(&host->lock, flags);
4626 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627
4628 mmc_resume_host(mmc);
4629
4630 /*
4631 * FIXME: Clearing of flags must be handled in clients
4632 * resume handler.
4633 */
4634 spin_lock_irqsave(&host->lock, flags);
4635 mmc->pm_flags = 0;
4636 spin_unlock_irqrestore(&host->lock, flags);
4637
4638 /*
4639 * After resuming the host wait for sometime so that
4640 * the SDIO work will be processed.
4641 */
4642 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4643 if ((host->plat->cfg_mpm_sdiowakeup ||
4644 host->plat->sdiowakeup_irq) &&
4645 wake_lock_active(&host->sdio_wlock))
4646 wake_lock_timeout(&host->sdio_wlock, 1);
4647 }
4648
4649 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004650 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304651 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004652 return 0;
4653}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004654
4655static int msmsdcc_runtime_idle(struct device *dev)
4656{
4657 struct mmc_host *mmc = dev_get_drvdata(dev);
4658 struct msmsdcc_host *host = mmc_priv(mmc);
4659
4660 if (host->plat->is_sdio_al_client)
4661 return 0;
4662
4663 /* Idle timeout is not configurable for now */
4664 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4665
4666 return -EAGAIN;
4667}
4668
4669static int msmsdcc_pm_suspend(struct device *dev)
4670{
4671 struct mmc_host *mmc = dev_get_drvdata(dev);
4672 struct msmsdcc_host *host = mmc_priv(mmc);
4673 int rc = 0;
4674
4675 if (host->plat->is_sdio_al_client)
4676 return 0;
4677
4678
4679 if (host->plat->status_irq)
4680 disable_irq(host->plat->status_irq);
4681
4682 if (!pm_runtime_suspended(dev))
4683 rc = msmsdcc_runtime_suspend(dev);
4684
4685 return rc;
4686}
4687
4688static int msmsdcc_pm_resume(struct device *dev)
4689{
4690 struct mmc_host *mmc = dev_get_drvdata(dev);
4691 struct msmsdcc_host *host = mmc_priv(mmc);
4692 int rc = 0;
4693
4694 if (host->plat->is_sdio_al_client)
4695 return 0;
4696
Sahitya Tummalafb486372011-09-02 19:01:49 +05304697 if (!pm_runtime_suspended(dev))
4698 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004699 if (host->plat->status_irq) {
4700 msmsdcc_check_status((unsigned long)host);
4701 enable_irq(host->plat->status_irq);
4702 }
4703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004704 return rc;
4705}
4706
Daniel Walker08ecfde2010-06-23 12:32:20 -07004707#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004708#define msmsdcc_runtime_suspend NULL
4709#define msmsdcc_runtime_resume NULL
4710#define msmsdcc_runtime_idle NULL
4711#define msmsdcc_pm_suspend NULL
4712#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004713#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004715static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4716 .runtime_suspend = msmsdcc_runtime_suspend,
4717 .runtime_resume = msmsdcc_runtime_resume,
4718 .runtime_idle = msmsdcc_runtime_idle,
4719 .suspend = msmsdcc_pm_suspend,
4720 .resume = msmsdcc_pm_resume,
4721};
4722
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304723static const struct of_device_id msmsdcc_dt_match[] = {
4724 {.compatible = "qcom,msm-sdcc"},
4725
4726};
4727MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4728
San Mehat9d2bd732009-09-22 16:44:22 -07004729static struct platform_driver msmsdcc_driver = {
4730 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004731 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004732 .driver = {
4733 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004734 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304735 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004736 },
4737};
4738
4739static int __init msmsdcc_init(void)
4740{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004741#if defined(CONFIG_DEBUG_FS)
4742 int ret = 0;
4743 ret = msmsdcc_dbg_init();
4744 if (ret) {
4745 pr_err("Failed to create debug fs dir \n");
4746 return ret;
4747 }
4748#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004749 return platform_driver_register(&msmsdcc_driver);
4750}
4751
4752static void __exit msmsdcc_exit(void)
4753{
4754 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004755
4756#if defined(CONFIG_DEBUG_FS)
4757 debugfs_remove(debugfs_file);
4758 debugfs_remove(debugfs_dir);
4759#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004760}
4761
4762module_init(msmsdcc_init);
4763module_exit(msmsdcc_exit);
4764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004765MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004766MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767
4768#if defined(CONFIG_DEBUG_FS)
4769
4770static int
4771msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4772{
4773 file->private_data = inode->i_private;
4774 return 0;
4775}
4776
4777static ssize_t
4778msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4779 size_t count, loff_t *ppos)
4780{
4781 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004782 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783 int max, i;
4784
4785 i = 0;
4786 max = sizeof(buf) - 1;
4787
4788 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4789 host->curr.cmd, host->curr.data);
4790 if (host->curr.cmd) {
4791 struct mmc_command *cmd = host->curr.cmd;
4792
4793 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4794 cmd->opcode, cmd->arg, cmd->flags);
4795 }
4796 if (host->curr.data) {
4797 struct mmc_data *data = host->curr.data;
4798 i += scnprintf(buf + i, max - i,
4799 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4800 data->timeout_ns, data->timeout_clks,
4801 data->blksz, data->blocks, data->error,
4802 data->flags);
4803 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4804 host->curr.xfer_size, host->curr.xfer_remain,
4805 host->curr.data_xfered, host->dma.sg);
4806 }
4807
4808 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4809}
4810
4811static const struct file_operations msmsdcc_dbg_state_ops = {
4812 .read = msmsdcc_dbg_state_read,
4813 .open = msmsdcc_dbg_state_open,
4814};
4815
4816static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4817{
4818 if (debugfs_dir) {
4819 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4820 0644, debugfs_dir, host,
4821 &msmsdcc_dbg_state_ops);
4822 }
4823}
4824
4825static int __init msmsdcc_dbg_init(void)
4826{
4827 int err;
4828
4829 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4830 if (IS_ERR(debugfs_dir)) {
4831 err = PTR_ERR(debugfs_dir);
4832 debugfs_dir = NULL;
4833 return err;
4834 }
4835
4836 return 0;
4837}
4838#endif