blob: db83404ffb877ba9a3fe85a6793a620600eeba43 [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.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 * Copyright (c) 2009-2011, 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);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530480 if (!mrq->data->stop || mrq->cmd->error ||
481 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700482 host->curr.mrq = NULL;
483 host->curr.cmd = NULL;
484 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700486 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487
San Mehat9d2bd732009-09-22 16:44:22 -0700488 mmc_request_done(host->mmc, mrq);
489 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530490 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
491 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700492 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530493 }
San Mehat9d2bd732009-09-22 16:44:22 -0700494 }
495
496out:
497 spin_unlock_irqrestore(&host->lock, flags);
498 return;
499}
500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
502/**
503 * Callback notification from SPS driver
504 *
505 * This callback function gets triggered called from
506 * SPS driver when requested SPS data transfer is
507 * completed.
508 *
509 * SPS driver invokes this callback in BAM irq context so
510 * SDCC driver schedule a tasklet for further processing
511 * this callback notification at later point of time in
512 * tasklet context and immediately returns control back
513 * to SPS driver.
514 *
515 * @nofity - Pointer to sps event notify sturcture
516 *
517 */
518static void
519msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
520{
521 struct msmsdcc_host *host =
522 (struct msmsdcc_host *)
523 ((struct sps_event_notify *)notify)->user;
524
525 host->sps.notify = *notify;
526 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
527 mmc_hostname(host->mmc), __func__, notify->event_id,
528 notify->data.transfer.iovec.addr,
529 notify->data.transfer.iovec.size,
530 notify->data.transfer.iovec.flags);
531 /* Schedule a tasklet for completing data transfer */
532 tasklet_schedule(&host->sps.tlet);
533}
534
535/**
536 * Tasklet handler for processing SPS callback event
537 *
538 * This function processing SPS event notification and
539 * checks if the SPS transfer is completed or not and
540 * then accordingly notifies status to MMC core layer.
541 *
542 * This function is called in tasklet context.
543 *
544 * @data - Pointer to sdcc driver data
545 *
546 */
547static void msmsdcc_sps_complete_tlet(unsigned long data)
548{
549 unsigned long flags;
550 int i, rc;
551 u32 data_xfered = 0;
552 struct mmc_request *mrq;
553 struct sps_iovec iovec;
554 struct sps_pipe *sps_pipe_handle;
555 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
556 struct sps_event_notify *notify = &host->sps.notify;
557
558 spin_lock_irqsave(&host->lock, flags);
559 if (host->sps.dir == DMA_FROM_DEVICE)
560 sps_pipe_handle = host->sps.prod.pipe_handle;
561 else
562 sps_pipe_handle = host->sps.cons.pipe_handle;
563 mrq = host->curr.mrq;
564
565 if (!mrq) {
566 spin_unlock_irqrestore(&host->lock, flags);
567 return;
568 }
569
570 pr_debug("%s: %s: sps event_id=%d\n",
571 mmc_hostname(host->mmc), __func__,
572 notify->event_id);
573
574 if (msmsdcc_is_dml_busy(host)) {
575 /* oops !!! this should never happen. */
576 pr_err("%s: %s: Received SPS EOT event"
577 " but DML HW is still busy !!!\n",
578 mmc_hostname(host->mmc), __func__);
579 }
580 /*
581 * Got End of transfer event!!! Check if all of the data
582 * has been transferred?
583 */
584 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
585 rc = sps_get_iovec(sps_pipe_handle, &iovec);
586 if (rc) {
587 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
588 mmc_hostname(host->mmc), __func__, rc, i);
589 break;
590 }
591 data_xfered += iovec.size;
592 }
593
594 if (data_xfered == host->curr.xfer_size) {
595 host->curr.data_xfered = host->curr.xfer_size;
596 host->curr.xfer_remain -= host->curr.xfer_size;
597 pr_debug("%s: Data xfer success. data_xfered=0x%x",
598 mmc_hostname(host->mmc),
599 host->curr.xfer_size);
600 } else {
601 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
602 " xfer_size=%d", mmc_hostname(host->mmc),
603 data_xfered, host->curr.xfer_size);
604 msmsdcc_reset_and_restore(host);
605 if (!mrq->data->error)
606 mrq->data->error = -EIO;
607 }
608
609 /* Unmap sg buffers */
610 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
611 host->sps.dir);
612
613 host->sps.sg = NULL;
614 host->sps.busy = 0;
615
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530616 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
617 (host->curr.wait_for_auto_prog_done &&
618 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 /*
620 * If we've already gotten our DATAEND / DATABLKEND
621 * for this request, then complete it through here.
622 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623
624 if (!mrq->data->error) {
625 host->curr.data_xfered = host->curr.xfer_size;
626 host->curr.xfer_remain -= host->curr.xfer_size;
627 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700628 if (host->dummy_52_needed) {
629 mrq->data->bytes_xfered = host->curr.data_xfered;
630 host->dummy_52_sent = 1;
631 msmsdcc_start_command(host, &dummy52cmd,
632 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700633 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700634 return;
635 }
636 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530637 if (!mrq->data->stop || mrq->cmd->error ||
638 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 host->curr.mrq = NULL;
640 host->curr.cmd = NULL;
641 mrq->data->bytes_xfered = host->curr.data_xfered;
642 del_timer(&host->req_tout_timer);
643 spin_unlock_irqrestore(&host->lock, flags);
644
645 mmc_request_done(host->mmc, mrq);
646 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530647 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
648 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 msmsdcc_start_command(host, mrq->data->stop, 0);
650 }
651 }
652 spin_unlock_irqrestore(&host->lock, flags);
653}
654
655/**
656 * Exit from current SPS data transfer
657 *
658 * This function exits from current SPS data transfer.
659 *
660 * This function should be called when error condition
661 * is encountered during data transfer.
662 *
663 * @host - Pointer to sdcc host structure
664 *
665 */
666static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
667{
668 struct mmc_request *mrq;
669
670 mrq = host->curr.mrq;
671 BUG_ON(!mrq);
672
673 msmsdcc_reset_and_restore(host);
674 if (!mrq->data->error)
675 mrq->data->error = -EIO;
676
677 /* Unmap sg buffers */
678 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
679 host->sps.dir);
680
681 host->sps.sg = NULL;
682 host->sps.busy = 0;
683 if (host->curr.data)
684 msmsdcc_stop_data(host);
685
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530686 if (!mrq->data->stop || mrq->cmd->error ||
687 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530689 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
690 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 msmsdcc_start_command(host, mrq->data->stop, 0);
692
693}
694#else
695static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
696static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
697static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
698#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
699
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530700static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530702static void
703msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
704 unsigned int result,
705 struct msm_dmov_errdata *err)
706{
707 struct msmsdcc_dma_data *dma_data =
708 container_of(cmd, struct msmsdcc_dma_data, hdr);
709 struct msmsdcc_host *host = dma_data->host;
710
711 dma_data->result = result;
712 if (err)
713 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
714
715 tasklet_schedule(&host->dma_tlet);
716}
717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700719{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
721 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700722 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 else
724 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700725}
726
727static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
728{
729 struct msmsdcc_nc_dmadata *nc;
730 dmov_box *box;
731 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700732 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530733 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700734 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530735 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700736
Krishna Konda25786ec2011-07-25 16:21:36 -0700737 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700739
Krishna Konda25786ec2011-07-25 16:21:36 -0700740 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
741
San Mehat9d2bd732009-09-22 16:44:22 -0700742 host->dma.sg = data->sg;
743 host->dma.num_ents = data->sg_len;
744
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530745 /* Prevent memory corruption */
746 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800747
San Mehat9d2bd732009-09-22 16:44:22 -0700748 nc = host->dma.nc;
749
San Mehat9d2bd732009-09-22 16:44:22 -0700750 if (data->flags & MMC_DATA_READ)
751 host->dma.dir = DMA_FROM_DEVICE;
752 else
753 host->dma.dir = DMA_TO_DEVICE;
754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700755 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
756 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757
758 if (n != host->dma.num_ents) {
759 pr_err("%s: Unable to map in all sg elements\n",
760 mmc_hostname(host->mmc));
761 host->dma.sg = NULL;
762 host->dma.num_ents = 0;
763 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800764 }
San Mehat9d2bd732009-09-22 16:44:22 -0700765
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530766 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
767 host->curr.user_pages = 0;
768 box = &nc->cmd[0];
769 for (i = 0; i < host->dma.num_ents; i++) {
770 len = sg_dma_len(sg);
771 offset = 0;
772
773 do {
774 /* Check if we can do DMA */
775 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
776 err = -ENOTSUPP;
777 goto unmap;
778 }
779
780 box->cmd = CMD_MODE_BOX;
781
782 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
783 len = MMC_MAX_DMA_BOX_LENGTH;
784 len -= len % data->blksz;
785 }
786 rows = (len % MCI_FIFOSIZE) ?
787 (len / MCI_FIFOSIZE) + 1 :
788 (len / MCI_FIFOSIZE);
789
790 if (data->flags & MMC_DATA_READ) {
791 box->src_row_addr = msmsdcc_fifo_addr(host);
792 box->dst_row_addr = sg_dma_address(sg) + offset;
793 box->src_dst_len = (MCI_FIFOSIZE << 16) |
794 (MCI_FIFOSIZE);
795 box->row_offset = MCI_FIFOSIZE;
796 box->num_rows = rows * ((1 << 16) + 1);
797 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
798 } else {
799 box->src_row_addr = sg_dma_address(sg) + offset;
800 box->dst_row_addr = msmsdcc_fifo_addr(host);
801 box->src_dst_len = (MCI_FIFOSIZE << 16) |
802 (MCI_FIFOSIZE);
803 box->row_offset = (MCI_FIFOSIZE << 16);
804 box->num_rows = rows * ((1 << 16) + 1);
805 box->cmd |= CMD_DST_CRCI(host->dma.crci);
806 }
807
808 offset += len;
809 len = sg_dma_len(sg) - offset;
810 box++;
811 box_cmd_cnt++;
812 } while (len);
813 sg++;
814 }
815 /* Mark last command */
816 box--;
817 box->cmd |= CMD_LC;
818
819 /* location of command block must be 64 bit aligned */
820 BUG_ON(host->dma.cmd_busaddr & 0x07);
821
822 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
823 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
824 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
825 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
826
827 /* Flush all data to memory before starting dma */
828 mb();
829
830unmap:
831 if (err) {
832 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
833 host->dma.num_ents, host->dma.dir);
834 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
835 mmc_hostname(host->mmc), err);
836 }
837
838 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700839}
840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
842/**
843 * Submits data transfer request to SPS driver
844 *
845 * This function make sg (scatter gather) data buffers
846 * DMA ready and then submits them to SPS driver for
847 * transfer.
848 *
849 * @host - Pointer to sdcc host structure
850 * @data - Pointer to mmc_data structure
851 *
852 * @return 0 if success else negative value
853 */
854static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
855 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800856{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857 int rc = 0;
858 u32 flags;
859 int i;
860 u32 addr, len, data_cnt;
861 struct scatterlist *sg = data->sg;
862 struct sps_pipe *sps_pipe_handle;
863
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530864 /* Prevent memory corruption */
865 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866
867 host->sps.sg = data->sg;
868 host->sps.num_ents = data->sg_len;
869 host->sps.xfer_req_cnt = 0;
870 if (data->flags & MMC_DATA_READ) {
871 host->sps.dir = DMA_FROM_DEVICE;
872 sps_pipe_handle = host->sps.prod.pipe_handle;
873 } else {
874 host->sps.dir = DMA_TO_DEVICE;
875 sps_pipe_handle = host->sps.cons.pipe_handle;
876 }
877
878 /* Make sg buffers DMA ready */
879 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
880 host->sps.dir);
881
882 if (rc != data->sg_len) {
883 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
884 mmc_hostname(host->mmc), rc);
885 host->sps.sg = NULL;
886 host->sps.num_ents = 0;
887 rc = -ENOMEM;
888 goto dma_map_err;
889 }
890
891 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
892 mmc_hostname(host->mmc), __func__,
893 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
894 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
895
896 for (i = 0; i < data->sg_len; i++) {
897 /*
898 * Check if this is the last buffer to transfer?
899 * If yes then set the INT and EOT flags.
900 */
901 len = sg_dma_len(sg);
902 addr = sg_dma_address(sg);
903 flags = 0;
904 while (len > 0) {
905 if (len > SPS_MAX_DESC_SIZE) {
906 data_cnt = SPS_MAX_DESC_SIZE;
907 } else {
908 data_cnt = len;
909 if (i == data->sg_len - 1)
910 flags = SPS_IOVEC_FLAG_INT |
911 SPS_IOVEC_FLAG_EOT;
912 }
913 rc = sps_transfer_one(sps_pipe_handle, addr,
914 data_cnt, host, flags);
915 if (rc) {
916 pr_err("%s: sps_transfer_one() error! rc=%d,"
917 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
918 mmc_hostname(host->mmc), rc,
919 (u32)sps_pipe_handle, (u32)sg, i);
920 goto dma_map_err;
921 }
922 addr += data_cnt;
923 len -= data_cnt;
924 host->sps.xfer_req_cnt++;
925 }
926 sg++;
927 }
928 goto out;
929
930dma_map_err:
931 /* unmap sg buffers */
932 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
933 host->sps.dir);
934out:
935 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700936}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937#else
938static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
939 struct mmc_data *data) { return 0; }
940#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700941
942static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800943msmsdcc_start_command_deferred(struct msmsdcc_host *host,
944 struct mmc_command *cmd, u32 *c)
945{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946 DBG(host, "op %02x arg %08x flags %08x\n",
947 cmd->opcode, cmd->arg, cmd->flags);
948
San Mehat56a8b5b2009-11-21 12:29:46 -0800949 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
950
951 if (cmd->flags & MMC_RSP_PRESENT) {
952 if (cmd->flags & MMC_RSP_136)
953 *c |= MCI_CPSM_LONGRSP;
954 *c |= MCI_CPSM_RESPONSE;
955 }
956
957 if (/*interrupt*/0)
958 *c |= MCI_CPSM_INTERRUPT;
959
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530960 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
961 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
962 cmd->opcode == MMC_WRITE_BLOCK ||
963 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
964 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800965 *c |= MCI_CSPM_DATCMD;
966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530968 if (host->tuning_needed) {
969 /*
970 * For open ended block read operation (without CMD23),
971 * AUTO_CMD19 bit should be set while sending the READ command.
972 * For close ended block read operation (with CMD23),
973 * AUTO_CMD19 bit should be set while sending CMD23.
974 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530975 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
976 host->curr.mrq->cmd->opcode ==
977 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530978 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530979 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
980 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530981 msmsdcc_enable_cdr_cm_sdc4_dll(host);
982 *c |= MCI_CSPM_AUTO_CMD19;
983 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700984 }
985
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530986 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530987 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530989 }
990
San Mehat56a8b5b2009-11-21 12:29:46 -0800991 if (cmd == cmd->mrq->stop)
992 *c |= MCI_CSPM_MCIABORT;
993
San Mehat56a8b5b2009-11-21 12:29:46 -0800994 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 pr_err("%s: Overlapping command requests\n",
996 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800997 }
998 host->curr.cmd = cmd;
999}
1000
1001static void
1002msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1003 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001004{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301005 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001006 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001008 unsigned int pio_irqmask = 0;
1009
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301010 BUG_ON(!data->sg);
1011 BUG_ON(!data->sg_len);
1012
San Mehat9d2bd732009-09-22 16:44:22 -07001013 host->curr.data = data;
1014 host->curr.xfer_size = data->blksz * data->blocks;
1015 host->curr.xfer_remain = host->curr.xfer_size;
1016 host->curr.data_xfered = 0;
1017 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301018 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001019
1020 memset(&host->pio, 0, sizeof(host->pio));
1021
San Mehat9d2bd732009-09-22 16:44:22 -07001022 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1023
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301024 if (host->curr.wait_for_auto_prog_done)
1025 datactrl |= MCI_AUTO_PROG_DONE;
1026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 if (!msmsdcc_check_dma_op_req(data)) {
1028 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1029 datactrl |= MCI_DPSM_DMAENABLE;
1030 } else if (host->is_sps_mode) {
1031 if (!msmsdcc_is_dml_busy(host)) {
1032 if (!msmsdcc_sps_start_xfer(host, data)) {
1033 /* Now kick start DML transfer */
1034 mb();
1035 msmsdcc_dml_start_xfer(host, data);
1036 datactrl |= MCI_DPSM_DMAENABLE;
1037 host->sps.busy = 1;
1038 }
1039 } else {
1040 /*
1041 * Can't proceed with new transfer as
1042 * previous trasnfer is already in progress.
1043 * There is no point of going into PIO mode
1044 * as well. Is this a time to do kernel panic?
1045 */
1046 pr_err("%s: %s: DML HW is busy!!!"
1047 " Can't perform new SPS transfers"
1048 " now\n", mmc_hostname(host->mmc),
1049 __func__);
1050 }
1051 }
1052 }
1053
1054 /* Is data transfer in PIO mode required? */
1055 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001056 host->pio.sg = data->sg;
1057 host->pio.sg_len = data->sg_len;
1058 host->pio.sg_off = 0;
1059
1060 if (data->flags & MMC_DATA_READ) {
1061 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1062 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1063 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1064 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1066 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001067 }
1068
1069 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301070 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001071
San Mehat56a8b5b2009-11-21 12:29:46 -08001072 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001074 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1077 /* Use ADM (Application Data Mover) HW for Data transfer */
1078 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001079 host->cmd_timeout = timeout;
1080 host->cmd_pio_irqmask = pio_irqmask;
1081 host->cmd_datactrl = datactrl;
1082 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1085 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001086 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001087
1088 if (cmd) {
1089 msmsdcc_start_command_deferred(host, cmd, &c);
1090 host->cmd_c = c;
1091 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1093 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1094 host->base + MMCIMASK0);
1095 mb();
1096 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001097 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1104 (~(MCI_IRQ_PIO))) | pio_irqmask,
1105 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301107 /*
1108 * We don't need delay after writing to DATA_CTRL register
1109 * if we are not writing to CMD register immediately after
1110 * this. As we already have delay before sending the
1111 * command, we just need mb() here.
1112 */
1113 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001114
1115 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001117 /* Daisy-chain the command if requested */
1118 msmsdcc_start_command(host, cmd, c);
1119 }
San Mehat9d2bd732009-09-22 16:44:22 -07001120 }
1121}
1122
1123static void
1124msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1125{
San Mehat56a8b5b2009-11-21 12:29:46 -08001126 msmsdcc_start_command_deferred(host, cmd, &c);
1127 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001128}
1129
1130static void
1131msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1132 unsigned int status)
1133{
1134 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1136 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1137 pr_err("%s: Data CRC error\n",
1138 mmc_hostname(host->mmc));
1139 pr_err("%s: opcode 0x%.8x\n", __func__,
1140 data->mrq->cmd->opcode);
1141 pr_err("%s: blksz %d, blocks %d\n", __func__,
1142 data->blksz, data->blocks);
1143 data->error = -EILSEQ;
1144 }
San Mehat9d2bd732009-09-22 16:44:22 -07001145 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 /* CRC is optional for the bus test commands, not all
1147 * cards respond back with CRC. However controller
1148 * waits for the CRC and times out. Hence ignore the
1149 * data timeouts during the Bustest.
1150 */
1151 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1152 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301153 pr_err("%s: CMD%d: Data timeout\n",
1154 mmc_hostname(host->mmc),
1155 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301157 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 }
San Mehat9d2bd732009-09-22 16:44:22 -07001159 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001160 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001161 data->error = -EIO;
1162 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001163 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001164 data->error = -EIO;
1165 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001166 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001168 data->error = -EIO;
1169 }
San Mehat9d2bd732009-09-22 16:44:22 -07001170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001172 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 host->dummy_52_needed = 0;
1174}
San Mehat9d2bd732009-09-22 16:44:22 -07001175
1176static int
1177msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1178{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001180 uint32_t *ptr = (uint32_t *) buffer;
1181 int count = 0;
1182
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301183 if (remain % 4)
1184 remain = ((remain >> 2) + 1) << 2;
1185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1187
1188 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001189 ptr++;
1190 count += sizeof(uint32_t);
1191
1192 remain -= sizeof(uint32_t);
1193 if (remain == 0)
1194 break;
1195 }
1196 return count;
1197}
1198
1199static int
1200msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001202{
1203 void __iomem *base = host->base;
1204 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 while (readl_relaxed(base + MMCISTATUS) &
1208 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1209 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001210
San Mehat9d2bd732009-09-22 16:44:22 -07001211 count = min(remain, maxcnt);
1212
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301213 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1214 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001215 ptr += count;
1216 remain -= count;
1217
1218 if (remain == 0)
1219 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 }
1221 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001222
1223 return ptr - buffer;
1224}
1225
San Mehat1cd22962010-02-03 12:59:29 -08001226static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001227msmsdcc_pio_irq(int irq, void *dev_id)
1228{
1229 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001231 uint32_t status;
1232
Murali Palnati36448a42011-09-02 15:06:18 +05301233 spin_lock(&host->lock);
1234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301238 (MCI_IRQ_PIO)) == 0) {
1239 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301241 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242
1243#if IRQ_DEBUG
1244 msmsdcc_print_status(host, "irq1-r", status);
1245#endif
1246
San Mehat9d2bd732009-09-22 16:44:22 -07001247 do {
1248 unsigned long flags;
1249 unsigned int remain, len;
1250 char *buffer;
1251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1253 | MCI_RXDATAAVLBL)))
1254 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001255
1256 /* Map the current scatter buffer */
1257 local_irq_save(flags);
1258 buffer = kmap_atomic(sg_page(host->pio.sg),
1259 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1260 buffer += host->pio.sg_off;
1261 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262
San Mehat9d2bd732009-09-22 16:44:22 -07001263 len = 0;
1264 if (status & MCI_RXACTIVE)
1265 len = msmsdcc_pio_read(host, buffer, remain);
1266 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001268
1269 /* Unmap the buffer */
1270 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1271 local_irq_restore(flags);
1272
1273 host->pio.sg_off += len;
1274 host->curr.xfer_remain -= len;
1275 host->curr.data_xfered += len;
1276 remain -= len;
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 if (remain) /* Done with this page? */
1279 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 if (status & MCI_RXACTIVE && host->curr.user_pages)
1282 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 if (!--host->pio.sg_len) {
1285 memset(&host->pio, 0, sizeof(host->pio));
1286 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001287 }
1288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 /* Advance to next sg */
1290 host->pio.sg++;
1291 host->pio.sg_off = 0;
1292
1293 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001294 } while (1);
1295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1297 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1298 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1299 host->base + MMCIMASK0);
1300 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301301 /*
1302 * back to back write to MASK0 register don't need
1303 * synchronization delay.
1304 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1306 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1307 }
1308 mb();
1309 } else if (!host->curr.xfer_remain) {
1310 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1311 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1312 mb();
1313 }
San Mehat9d2bd732009-09-22 16:44:22 -07001314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001316
1317 return IRQ_HANDLED;
1318}
1319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320static void
1321msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1322
1323static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1324 struct mmc_data *data)
1325{
1326 u32 loop_cnt = 0;
1327
1328 /*
1329 * For read commands with data less than fifo size, it is possible to
1330 * get DATAEND first and RXDATA_AVAIL might be set later because of
1331 * synchronization delay through the asynchronous RX FIFO. Thus, for
1332 * such cases, even after DATAEND interrupt is received software
1333 * should poll for RXDATA_AVAIL until the requested data is read out
1334 * of FIFO. This change is needed to get around this abnormal but
1335 * sometimes expected behavior of SDCC3 controller.
1336 *
1337 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1338 * after the data is loaded into RX FIFO. This would amount to less
1339 * than a microsecond and thus looping for 1000 times is good enough
1340 * for that delay.
1341 */
1342 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1343 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1344 spin_unlock(&host->lock);
1345 msmsdcc_pio_irq(1, host);
1346 spin_lock(&host->lock);
1347 }
1348 }
1349 if (loop_cnt == 1000) {
1350 pr_info("%s: Timed out while polling for Rx Data\n",
1351 mmc_hostname(host->mmc));
1352 data->error = -ETIMEDOUT;
1353 msmsdcc_reset_and_restore(host);
1354 }
1355}
1356
San Mehat9d2bd732009-09-22 16:44:22 -07001357static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1358{
1359 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001360
1361 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1363 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1364 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1365 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301368 pr_debug("%s: CMD%d: Command timeout\n",
1369 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001370 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1372 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301373 pr_err("%s: CMD%d: Command CRC error\n",
1374 mmc_hostname(host->mmc), cmd->opcode);
1375 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001376 cmd->error = -EILSEQ;
1377 }
1378
1379 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 if (host->curr.data && host->dma.sg &&
1381 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001382 msm_dmov_stop_cmd(host->dma.channel,
1383 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 else if (host->curr.data && host->sps.sg &&
1385 host->is_sps_mode){
1386 /* Stop current SPS transfer */
1387 msmsdcc_sps_exit_curr_xfer(host);
1388 }
San Mehat9d2bd732009-09-22 16:44:22 -07001389 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301390 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001391 msmsdcc_stop_data(host);
1392 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301393 } else { /* host->data == NULL */
1394 if (!cmd->error && host->prog_enable) {
1395 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301397 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301399 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301400 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301401 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001402 if (host->dummy_52_needed)
1403 host->dummy_52_needed = 0;
1404 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301406 msmsdcc_request_end(host, cmd->mrq);
1407 }
1408 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301409 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1410 if (cmd->data->flags & MMC_DATA_READ)
1411 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1412 else
1413 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301414 } else if (cmd->data) {
1415 if (!(cmd->data->flags & MMC_DATA_READ))
1416 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001417 }
1418}
1419
San Mehat9d2bd732009-09-22 16:44:22 -07001420static irqreturn_t
1421msmsdcc_irq(int irq, void *dev_id)
1422{
1423 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001424 u32 status;
1425 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001427
1428 spin_lock(&host->lock);
1429
1430 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 struct mmc_command *cmd;
1432 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 if (timer) {
1435 timer = 0;
1436 msmsdcc_delay(host);
1437 }
San Mehat865c8062009-11-13 13:42:06 -08001438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 if (!host->clks_on) {
1440 pr_debug("%s: %s: SDIO async irq received\n",
1441 mmc_hostname(host->mmc), __func__);
1442 host->mmc->ios.clock = host->clk_rate;
1443 spin_unlock(&host->lock);
1444 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1445 spin_lock(&host->lock);
1446 if (host->plat->cfg_mpm_sdiowakeup &&
1447 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1448 wake_lock(&host->sdio_wlock);
1449 /* only ansyc interrupt can come when clocks are off */
1450 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301451 if (host->clk_rate <=
1452 msmsdcc_get_min_sup_clk_rate(host))
1453 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 }
1455
1456 status = readl_relaxed(host->base + MMCISTATUS);
1457
1458 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1459 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001460 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462#if IRQ_DEBUG
1463 msmsdcc_print_status(host, "irq0-r", status);
1464#endif
1465 status &= readl_relaxed(host->base + MMCIMASK0);
1466 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301467 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301468 if (host->clk_rate <=
1469 msmsdcc_get_min_sup_clk_rate(host))
1470 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471#if IRQ_DEBUG
1472 msmsdcc_print_status(host, "irq0-p", status);
1473#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1476 if (status & MCI_SDIOINTROPE) {
1477 if (host->sdcc_suspending)
1478 wake_lock(&host->sdio_suspend_wlock);
1479 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001480 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001482 data = host->curr.data;
1483
1484 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1486 MCI_CMDTIMEOUT)) {
1487 if (status & MCI_CMDTIMEOUT)
1488 pr_debug("%s: dummy CMD52 timeout\n",
1489 mmc_hostname(host->mmc));
1490 if (status & MCI_CMDCRCFAIL)
1491 pr_debug("%s: dummy CMD52 CRC failed\n",
1492 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001493 host->dummy_52_sent = 0;
1494 host->dummy_52_needed = 0;
1495 if (data) {
1496 msmsdcc_stop_data(host);
1497 msmsdcc_request_end(host, data->mrq);
1498 }
1499 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 spin_unlock(&host->lock);
1501 return IRQ_HANDLED;
1502 }
1503 break;
1504 }
1505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 /*
1507 * Check for proper command response
1508 */
1509 cmd = host->curr.cmd;
1510 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1511 MCI_CMDTIMEOUT | MCI_PROGDONE |
1512 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1513 msmsdcc_do_cmdirq(host, status);
1514 }
1515
Sathish Ambley081d7842011-11-29 11:19:41 -08001516 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 /* Check for data errors */
1518 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1519 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1520 msmsdcc_data_err(host, data, status);
1521 host->curr.data_xfered = 0;
1522 if (host->dma.sg && host->is_dma_mode)
1523 msm_dmov_stop_cmd(host->dma.channel,
1524 &host->dma.hdr, 0);
1525 else if (host->sps.sg && host->is_sps_mode) {
1526 /* Stop current SPS transfer */
1527 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301528 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 msmsdcc_reset_and_restore(host);
1530 if (host->curr.data)
1531 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301532 if (!data->stop || (host->curr.mrq->sbc
1533 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 timer |=
1535 msmsdcc_request_end(host,
1536 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301537 else if ((host->curr.mrq->sbc
1538 && data->error) ||
1539 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 msmsdcc_start_command(host,
1541 data->stop,
1542 0);
1543 timer = 1;
1544 }
1545 }
1546 }
1547
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301548 /* Check for prog done */
1549 if (host->curr.wait_for_auto_prog_done &&
1550 (status & MCI_PROGDONE))
1551 host->curr.got_auto_prog_done = 1;
1552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 /* Check for data done */
1554 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1555 host->curr.got_dataend = 1;
1556
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301557 if (host->curr.got_dataend &&
1558 (!host->curr.wait_for_auto_prog_done ||
1559 (host->curr.wait_for_auto_prog_done &&
1560 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 /*
1562 * If DMA is still in progress, we complete
1563 * via the completion handler
1564 */
1565 if (!host->dma.busy && !host->sps.busy) {
1566 /*
1567 * There appears to be an issue in the
1568 * controller where if you request a
1569 * small block transfer (< fifo size),
1570 * you may get your DATAEND/DATABLKEND
1571 * irq without the PIO data irq.
1572 *
1573 * Check to see if theres still data
1574 * to be read, and simulate a PIO irq.
1575 */
1576 if (data->flags & MMC_DATA_READ)
1577 msmsdcc_wait_for_rxdata(host,
1578 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 if (!data->error) {
1580 host->curr.data_xfered =
1581 host->curr.xfer_size;
1582 host->curr.xfer_remain -=
1583 host->curr.xfer_size;
1584 }
1585
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001586 if (!host->dummy_52_needed) {
1587 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301588 if (!data->stop ||
1589 (host->curr.mrq->sbc
1590 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001591 msmsdcc_request_end(
1592 host,
1593 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301594 else if ((host->curr.mrq->sbc
1595 && data->error) ||
1596 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001597 msmsdcc_start_command(
1598 host,
1599 data->stop, 0);
1600 timer = 1;
1601 }
1602 } else {
1603 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001605 &dummy52cmd,
1606 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 }
1608 }
1609 }
1610 }
1611
San Mehat9d2bd732009-09-22 16:44:22 -07001612 ret = 1;
1613 } while (status);
1614
1615 spin_unlock(&host->lock);
1616
San Mehat9d2bd732009-09-22 16:44:22 -07001617 return IRQ_RETVAL(ret);
1618}
1619
1620static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1622{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301623 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301625 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301626 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1627 else
1628 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 } else {
1630 msmsdcc_start_command(host, mrq->cmd, 0);
1631 }
1632}
1633
1634static void
San Mehat9d2bd732009-09-22 16:44:22 -07001635msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1636{
1637 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 /*
1641 * Get the SDIO AL client out of LPM.
1642 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001643 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 if (host->plat->is_sdio_al_client)
1645 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001646
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301647 /* check if sps pipe reset is pending? */
1648 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1649 msmsdcc_sps_pipes_reset_and_restore(host);
1650 host->sps.pipe_reset_pending = false;
1651 }
1652
San Mehat9d2bd732009-09-22 16:44:22 -07001653 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 WARN(host->curr.mrq, "Request in progress\n");
1655 WARN(!host->pwr, "SDCC power is turned off\n");
1656 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1657 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001658
1659 if (host->eject) {
1660 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1661 mrq->cmd->error = 0;
1662 mrq->data->bytes_xfered = mrq->data->blksz *
1663 mrq->data->blocks;
1664 } else
1665 mrq->cmd->error = -ENOMEDIUM;
1666
1667 spin_unlock_irqrestore(&host->lock, flags);
1668 mmc_request_done(mmc, mrq);
1669 return;
1670 }
1671
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301672 /*
1673 * Kick the software command timeout timer here.
1674 * Timer expires in 10 secs.
1675 */
1676 mod_timer(&host->req_tout_timer,
1677 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001678
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301679 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301680 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301681 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1682 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301683 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301685 else
1686 /*
1687 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1688 * write operations using CMD53 and CMD54.
1689 * Setting this bit with CMD53 would
1690 * automatically triggers PROG_DONE interrupt
1691 * without the need of sending dummy CMD52.
1692 */
1693 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301694 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1695 host->sdcc_version) {
1696 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 }
San Mehat9d2bd732009-09-22 16:44:22 -07001698 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301699
Pratibhasagar V00b94332011-10-18 14:57:27 +05301700 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301701 mrq->sbc->mrq = mrq;
1702 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301703 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301704 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301705 msmsdcc_start_command(host, mrq->sbc, 0);
1706 } else {
1707 msmsdcc_request_start(host, mrq);
1708 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301709 } else {
1710 msmsdcc_request_start(host, mrq);
1711 }
1712
San Mehat9d2bd732009-09-22 16:44:22 -07001713 spin_unlock_irqrestore(&host->lock, flags);
1714}
1715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1717 int min_uV, int max_uV)
1718{
1719 int rc = 0;
1720
1721 if (vreg->set_voltage_sup) {
1722 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1723 if (rc) {
1724 pr_err("%s: regulator_set_voltage(%s) failed."
1725 " min_uV=%d, max_uV=%d, rc=%d\n",
1726 __func__, vreg->name, min_uV, max_uV, rc);
1727 }
1728 }
1729
1730 return rc;
1731}
1732
1733static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1734 int uA_load)
1735{
1736 int rc = 0;
1737
Krishna Kondafea60182011-11-01 16:01:34 -07001738 /* regulators that do not support regulator_set_voltage also
1739 do not support regulator_set_optimum_mode */
1740 if (vreg->set_voltage_sup) {
1741 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1742 if (rc < 0)
1743 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1744 "uA_load=%d) failed. rc=%d\n", __func__,
1745 vreg->name, uA_load, rc);
1746 else
1747 /* regulator_set_optimum_mode() can return non zero
1748 * value even for success case.
1749 */
1750 rc = 0;
1751 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752
1753 return rc;
1754}
1755
1756static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1757 struct device *dev)
1758{
1759 int rc = 0;
1760
1761 /* check if regulator is already initialized? */
1762 if (vreg->reg)
1763 goto out;
1764
1765 /* Get the regulator handle */
1766 vreg->reg = regulator_get(dev, vreg->name);
1767 if (IS_ERR(vreg->reg)) {
1768 rc = PTR_ERR(vreg->reg);
1769 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1770 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001771 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001773
1774 if (regulator_count_voltages(vreg->reg) > 0)
1775 vreg->set_voltage_sup = 1;
1776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777out:
1778 return rc;
1779}
1780
1781static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1782{
1783 if (vreg->reg)
1784 regulator_put(vreg->reg);
1785}
1786
1787/* This init function should be called only once for each SDCC slot */
1788static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1789{
1790 int rc = 0;
1791 struct msm_mmc_slot_reg_data *curr_slot;
1792 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1793 struct device *dev = mmc_dev(host->mmc);
1794
1795 curr_slot = host->plat->vreg_data;
1796 if (!curr_slot)
1797 goto out;
1798
1799 curr_vdd_reg = curr_slot->vdd_data;
1800 curr_vccq_reg = curr_slot->vccq_data;
1801 curr_vddp_reg = curr_slot->vddp_data;
1802
1803 if (is_init) {
1804 /*
1805 * Get the regulator handle from voltage regulator framework
1806 * and then try to set the voltage level for the regulator
1807 */
1808 if (curr_vdd_reg) {
1809 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1810 if (rc)
1811 goto out;
1812 }
1813 if (curr_vccq_reg) {
1814 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1815 if (rc)
1816 goto vdd_reg_deinit;
1817 }
1818 if (curr_vddp_reg) {
1819 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1820 if (rc)
1821 goto vccq_reg_deinit;
1822 }
1823 goto out;
1824 } else {
1825 /* Deregister all regulators from regulator framework */
1826 goto vddp_reg_deinit;
1827 }
1828vddp_reg_deinit:
1829 if (curr_vddp_reg)
1830 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1831vccq_reg_deinit:
1832 if (curr_vccq_reg)
1833 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1834vdd_reg_deinit:
1835 if (curr_vdd_reg)
1836 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1837out:
1838 return rc;
1839}
1840
1841static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1842{
1843 int rc = 0;
1844
Subhash Jadavanicc922692011-08-01 23:05:01 +05301845 /* Put regulator in HPM (high power mode) */
1846 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1847 if (rc < 0)
1848 goto out;
1849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 if (!vreg->is_enabled) {
1851 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301852 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1853 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854 if (rc)
1855 goto out;
1856
1857 rc = regulator_enable(vreg->reg);
1858 if (rc) {
1859 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1860 __func__, vreg->name, rc);
1861 goto out;
1862 }
1863 vreg->is_enabled = true;
1864 }
1865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866out:
1867 return rc;
1868}
1869
1870static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1871{
1872 int rc = 0;
1873
1874 /* Never disable regulator marked as always_on */
1875 if (vreg->is_enabled && !vreg->always_on) {
1876 rc = regulator_disable(vreg->reg);
1877 if (rc) {
1878 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1879 __func__, vreg->name, rc);
1880 goto out;
1881 }
1882 vreg->is_enabled = false;
1883
1884 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1885 if (rc < 0)
1886 goto out;
1887
1888 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301889 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890 if (rc)
1891 goto out;
1892 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1893 /* Put always_on regulator in LPM (low power mode) */
1894 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1895 if (rc < 0)
1896 goto out;
1897 }
1898out:
1899 return rc;
1900}
1901
1902static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1903{
1904 int rc = 0, i;
1905 struct msm_mmc_slot_reg_data *curr_slot;
1906 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1907 struct msm_mmc_reg_data *vreg_table[3];
1908
1909 curr_slot = host->plat->vreg_data;
1910 if (!curr_slot)
1911 goto out;
1912
1913 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1914 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1915 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1916
1917 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1918 if (vreg_table[i]) {
1919 if (enable)
1920 rc = msmsdcc_vreg_enable(vreg_table[i]);
1921 else
1922 rc = msmsdcc_vreg_disable(vreg_table[i]);
1923 if (rc)
1924 goto out;
1925 }
1926 }
1927out:
1928 return rc;
1929}
1930
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301931static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932{
1933 int rc = 0;
1934
1935 if (host->plat->vreg_data) {
1936 struct msm_mmc_reg_data *vddp_reg =
1937 host->plat->vreg_data->vddp_data;
1938
1939 if (vddp_reg && vddp_reg->is_enabled)
1940 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1941 }
1942
1943 return rc;
1944}
1945
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301946static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1947{
1948 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1949 int rc = 0;
1950
1951 if (curr_slot && curr_slot->vddp_data) {
1952 rc = msmsdcc_set_vddp_level(host,
1953 curr_slot->vddp_data->low_vol_level);
1954
1955 if (rc)
1956 pr_err("%s: %s: failed to change vddp level to %d",
1957 mmc_hostname(host->mmc), __func__,
1958 curr_slot->vddp_data->low_vol_level);
1959 }
1960
1961 return rc;
1962}
1963
1964static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1965{
1966 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1967 int rc = 0;
1968
1969 if (curr_slot && curr_slot->vddp_data) {
1970 rc = msmsdcc_set_vddp_level(host,
1971 curr_slot->vddp_data->high_vol_level);
1972
1973 if (rc)
1974 pr_err("%s: %s: failed to change vddp level to %d",
1975 mmc_hostname(host->mmc), __func__,
1976 curr_slot->vddp_data->high_vol_level);
1977 }
1978
1979 return rc;
1980}
1981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1983{
1984 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1985 return 1;
1986 return 0;
1987}
1988
1989static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1990{
1991 if (enable) {
1992 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1993 clk_enable(host->dfab_pclk);
1994 if (!IS_ERR(host->pclk))
1995 clk_enable(host->pclk);
1996 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301997 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301999 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 clk_disable(host->clk);
2001 if (!IS_ERR(host->pclk))
2002 clk_disable(host->pclk);
2003 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2004 clk_disable(host->dfab_pclk);
2005 }
2006}
2007
2008static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2009 unsigned int req_clk)
2010{
2011 unsigned int sel_clk = -1;
2012
2013 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2014 unsigned char cnt;
2015
2016 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2017 if (host->plat->sup_clk_table[cnt] > req_clk)
2018 break;
2019 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2020 sel_clk = host->plat->sup_clk_table[cnt];
2021 break;
2022 } else
2023 sel_clk = host->plat->sup_clk_table[cnt];
2024 }
2025 } else {
2026 if ((req_clk < host->plat->msmsdcc_fmax) &&
2027 (req_clk > host->plat->msmsdcc_fmid))
2028 sel_clk = host->plat->msmsdcc_fmid;
2029 else
2030 sel_clk = req_clk;
2031 }
2032
2033 return sel_clk;
2034}
2035
2036static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2037 struct msmsdcc_host *host)
2038{
2039 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2040 return host->plat->sup_clk_table[0];
2041 else
2042 return host->plat->msmsdcc_fmin;
2043}
2044
2045static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2046 struct msmsdcc_host *host)
2047{
2048 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2049 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2050 else
2051 return host->plat->msmsdcc_fmax;
2052}
2053
2054static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302055{
2056 struct msm_mmc_gpio_data *curr;
2057 int i, rc = 0;
2058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302060 for (i = 0; i < curr->size; i++) {
2061 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 if (curr->gpio[i].is_always_on &&
2063 curr->gpio[i].is_enabled)
2064 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302065 rc = gpio_request(curr->gpio[i].no,
2066 curr->gpio[i].name);
2067 if (rc) {
2068 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2069 mmc_hostname(host->mmc),
2070 curr->gpio[i].no,
2071 curr->gpio[i].name, rc);
2072 goto free_gpios;
2073 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002074 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302075 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076 if (curr->gpio[i].is_always_on)
2077 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302078 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302080 }
2081 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302083
2084free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302086 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087 curr->gpio[i].is_enabled = false;
2088 }
2089out:
2090 return rc;
2091}
2092
2093static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2094{
2095 struct msm_mmc_pad_data *curr;
2096 int i;
2097
2098 curr = host->plat->pin_data->pad_data;
2099 for (i = 0; i < curr->drv->size; i++) {
2100 if (enable)
2101 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2102 curr->drv->on[i].val);
2103 else
2104 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2105 curr->drv->off[i].val);
2106 }
2107
2108 for (i = 0; i < curr->pull->size; i++) {
2109 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002110 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 curr->pull->on[i].val);
2112 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002113 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002114 curr->pull->off[i].val);
2115 }
2116
2117 return 0;
2118}
2119
2120static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2121{
2122 int rc = 0;
2123
2124 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2125 return 0;
2126
2127 if (host->plat->pin_data->is_gpio)
2128 rc = msmsdcc_setup_gpio(host, enable);
2129 else
2130 rc = msmsdcc_setup_pad(host, enable);
2131
2132 if (!rc)
2133 host->plat->pin_data->cfg_sts = enable;
2134
2135 return rc;
2136}
2137
2138static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2139{
2140 unsigned int wakeup_irq;
2141
2142 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2143 host->plat->sdiowakeup_irq :
2144 host->core_irqres->start;
2145
2146 if (!host->irq_wake_enabled) {
2147 enable_irq_wake(wakeup_irq);
2148 host->irq_wake_enabled = true;
2149 }
2150}
2151
2152static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2153{
2154 unsigned int wakeup_irq;
2155
2156 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2157 host->plat->sdiowakeup_irq :
2158 host->core_irqres->start;
2159
2160 if (host->irq_wake_enabled) {
2161 disable_irq_wake(wakeup_irq);
2162 host->irq_wake_enabled = false;
2163 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302164}
2165
San Mehat9d2bd732009-09-22 16:44:22 -07002166static void
2167msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2168{
2169 struct msmsdcc_host *host = mmc_priv(mmc);
2170 u32 clk = 0, pwr = 0;
2171 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002172 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302176
San Mehat9d2bd732009-09-22 16:44:22 -07002177 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178 spin_lock_irqsave(&host->lock, flags);
2179 if (!host->clks_on) {
2180 msmsdcc_setup_clocks(host, true);
2181 host->clks_on = 1;
2182 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2183 if (!host->plat->sdiowakeup_irq) {
2184 writel_relaxed(host->mci_irqenable,
2185 host->base + MMCIMASK0);
2186 mb();
2187 if (host->plat->cfg_mpm_sdiowakeup &&
2188 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2189 host->plat->cfg_mpm_sdiowakeup(
2190 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2191 msmsdcc_disable_irq_wake(host);
2192 } else if (!(mmc->pm_flags &
2193 MMC_PM_WAKE_SDIO_IRQ)) {
2194 writel_relaxed(host->mci_irqenable,
2195 host->base + MMCIMASK0);
2196 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302197 } else {
2198 writel_relaxed(host->mci_irqenable,
2199 host->base + MMCIMASK0);
2200 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 }
San Mehat9d2bd732009-09-22 16:44:22 -07002202 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002203 spin_unlock_irqrestore(&host->lock, flags);
2204
2205 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2206 /*
2207 * For DDR50 mode, controller needs clock rate to be
2208 * double than what is required on the SD card CLK pin.
2209 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302210 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211 /*
2212 * Make sure that we don't double the clock if
2213 * doubled clock rate is already set
2214 */
2215 if (!host->ddr_doubled_clk_rate ||
2216 (host->ddr_doubled_clk_rate &&
2217 (host->ddr_doubled_clk_rate != ios->clock))) {
2218 host->ddr_doubled_clk_rate =
2219 msmsdcc_get_sup_clk_rate(
2220 host, (ios->clock * 2));
2221 clock = host->ddr_doubled_clk_rate;
2222 }
2223 } else {
2224 host->ddr_doubled_clk_rate = 0;
2225 }
2226
2227 if (clock != host->clk_rate) {
2228 rc = clk_set_rate(host->clk, clock);
2229 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302230 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231 mmc_hostname(mmc), clock);
2232 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302233 host->reg_write_delay =
2234 (1 + ((3 * USEC_PER_SEC) /
2235 (host->clk_rate ? host->clk_rate :
2236 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 }
2238 /*
2239 * give atleast 2 MCLK cycles delay for clocks
2240 * and SDCC core to stabilize
2241 */
2242 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002243 clk |= MCI_CLK_ENABLE;
2244 }
2245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246 if (ios->bus_width == MMC_BUS_WIDTH_8)
2247 clk |= MCI_CLK_WIDEBUS_8;
2248 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2249 clk |= MCI_CLK_WIDEBUS_4;
2250 else
2251 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 if (msmsdcc_is_pwrsave(host))
2254 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258 host->tuning_needed = 0;
2259 /*
2260 * Select the controller timing mode according
2261 * to current bus speed mode
2262 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302263 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 clk |= (4 << 14);
2265 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302266 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 clk |= (3 << 14);
2268 } else {
2269 clk |= (2 << 14); /* feedback clock */
2270 }
2271
2272 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2273 clk |= (2 << 23);
2274
2275 if (host->io_pad_pwr_switch)
2276 clk |= IO_PAD_PWR_SWITCH;
2277
2278 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002279 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2281 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002282
2283 switch (ios->power_mode) {
2284 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2286 if (!host->sdcc_irq_disabled) {
2287 if (host->plat->cfg_mpm_sdiowakeup)
2288 host->plat->cfg_mpm_sdiowakeup(
2289 mmc_dev(mmc), SDC_DAT1_DISABLE);
2290 disable_irq(host->core_irqres->start);
2291 host->sdcc_irq_disabled = 1;
2292 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302293 /*
2294 * As VDD pad rail is always on, set low voltage for VDD
2295 * pad rail when slot is unused (when card is not present
2296 * or during system suspend).
2297 */
2298 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002300 break;
2301 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302302 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002303 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304 if (host->sdcc_irq_disabled) {
2305 if (host->plat->cfg_mpm_sdiowakeup)
2306 host->plat->cfg_mpm_sdiowakeup(
2307 mmc_dev(mmc), SDC_DAT1_ENABLE);
2308 enable_irq(host->core_irqres->start);
2309 host->sdcc_irq_disabled = 0;
2310 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302311 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002313 break;
2314 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002316 pwr |= MCI_PWR_ON;
2317 break;
2318 }
2319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 spin_lock_irqsave(&host->lock, flags);
2321 if (!host->clks_on) {
2322 /* force the clocks to be on */
2323 msmsdcc_setup_clocks(host, true);
2324 /*
2325 * give atleast 2 MCLK cycles delay for clocks
2326 * and SDCC core to stabilize
2327 */
2328 msmsdcc_delay(host);
2329 }
2330 writel_relaxed(clk, host->base + MMCICLOCK);
2331 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002332
2333 if (host->pwr != pwr) {
2334 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302336 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002337 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338 if (!host->clks_on) {
2339 /* force the clocks to be off */
2340 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 }
2342
2343 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2344 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2345 if (!host->plat->sdiowakeup_irq) {
2346 writel_relaxed(MCI_SDIOINTMASK,
2347 host->base + MMCIMASK0);
2348 mb();
2349 if (host->plat->cfg_mpm_sdiowakeup &&
2350 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2351 host->plat->cfg_mpm_sdiowakeup(
2352 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2353 msmsdcc_enable_irq_wake(host);
2354 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2355 writel_relaxed(0, host->base + MMCIMASK0);
2356 } else {
2357 writel_relaxed(MCI_SDIOINTMASK,
2358 host->base + MMCIMASK0);
2359 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302360 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361 }
2362 msmsdcc_setup_clocks(host, false);
2363 host->clks_on = 0;
2364 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302365
2366 if (host->cmd19_tuning_in_progress)
2367 WARN(!host->clks_on,
2368 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2369
San Mehat4adbbcc2009-11-08 13:00:37 -08002370 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002371}
2372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002373int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2374{
2375 struct msmsdcc_host *host = mmc_priv(mmc);
2376 u32 clk;
2377
2378 clk = readl_relaxed(host->base + MMCICLOCK);
2379 pr_debug("Changing to pwr_save=%d", pwrsave);
2380 if (pwrsave && msmsdcc_is_pwrsave(host))
2381 clk |= MCI_CLK_PWRSAVE;
2382 else
2383 clk &= ~MCI_CLK_PWRSAVE;
2384 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302385 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386
2387 return 0;
2388}
2389
2390static int msmsdcc_get_ro(struct mmc_host *mmc)
2391{
2392 int status = -ENOSYS;
2393 struct msmsdcc_host *host = mmc_priv(mmc);
2394
2395 if (host->plat->wpswitch) {
2396 status = host->plat->wpswitch(mmc_dev(mmc));
2397 } else if (host->plat->wpswitch_gpio) {
2398 status = gpio_request(host->plat->wpswitch_gpio,
2399 "SD_WP_Switch");
2400 if (status) {
2401 pr_err("%s: %s: Failed to request GPIO %d\n",
2402 mmc_hostname(mmc), __func__,
2403 host->plat->wpswitch_gpio);
2404 } else {
2405 status = gpio_direction_input(
2406 host->plat->wpswitch_gpio);
2407 if (!status) {
2408 /*
2409 * Wait for atleast 300ms as debounce
2410 * time for GPIO input to stabilize.
2411 */
2412 msleep(300);
2413 status = gpio_get_value_cansleep(
2414 host->plat->wpswitch_gpio);
2415 status ^= !host->plat->wpswitch_polarity;
2416 }
2417 gpio_free(host->plat->wpswitch_gpio);
2418 }
2419 }
2420
2421 if (status < 0)
2422 status = -ENOSYS;
2423 pr_debug("%s: Card read-only status %d\n", __func__, status);
2424
2425 return status;
2426}
2427
2428#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002429static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2430{
2431 struct msmsdcc_host *host = mmc_priv(mmc);
2432 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002433
2434 if (enable) {
2435 spin_lock_irqsave(&host->lock, flags);
2436 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2437 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2438 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2439 spin_unlock_irqrestore(&host->lock, flags);
2440 } else {
2441 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2442 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2443 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2444 }
2445 mb();
2446}
2447#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2448
2449#ifdef CONFIG_PM_RUNTIME
2450static int msmsdcc_enable(struct mmc_host *mmc)
2451{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302452 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 struct device *dev = mmc->parent;
2454
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302455 if (dev->power.runtime_status == RPM_SUSPENDING) {
2456 if (mmc->suspend_task == current) {
2457 pm_runtime_get_noresume(dev);
2458 goto out;
2459 }
2460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302462 rc = pm_runtime_get_sync(dev);
2463
2464 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2466 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302467 return rc;
2468 }
2469out:
2470 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471}
2472
2473static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2474{
2475 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302476 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302478 if (host->plat->disable_runtime_pm)
2479 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2481 return -ENOTSUPP;
2482
2483 rc = pm_runtime_put_sync(mmc->parent);
2484
2485 if (rc < 0)
2486 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2487 __func__, rc);
2488 return rc;
2489}
2490#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302491static int msmsdcc_enable(struct mmc_host *mmc)
2492{
2493 struct msmsdcc_host *host = mmc_priv(mmc);
2494 unsigned long flags;
2495
2496 spin_lock_irqsave(&host->lock, flags);
2497 if (!host->clks_on) {
2498 msmsdcc_setup_clocks(host, true);
2499 host->clks_on = 1;
2500 }
2501 spin_unlock_irqrestore(&host->lock, flags);
2502
2503 return 0;
2504}
2505
2506static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2507{
2508 struct msmsdcc_host *host = mmc_priv(mmc);
2509 unsigned long flags;
2510
2511 if (mmc->card && mmc_card_sdio(mmc->card))
2512 return -ENOTSUPP;
2513
2514 spin_lock_irqsave(&host->lock, flags);
2515 if (host->clks_on) {
2516 msmsdcc_setup_clocks(host, false);
2517 host->clks_on = 0;
2518 }
2519 spin_unlock_irqrestore(&host->lock, flags);
2520
2521 return 0;
2522}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002523#endif
2524
2525static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2526 struct mmc_ios *ios)
2527{
2528 struct msmsdcc_host *host = mmc_priv(mmc);
2529 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302530 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531
2532 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2533 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302534 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535 goto out;
2536 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2537 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302538 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 goto out;
2540 }
San Mehat9d2bd732009-09-22 16:44:22 -07002541
2542 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543 /*
2544 * If we are here means voltage switch from high voltage to
2545 * low voltage is required
2546 */
2547
2548 /*
2549 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2550 * register until they become all zeros.
2551 */
2552 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302553 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2555 mmc_hostname(mmc), __func__);
2556 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002557 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558
2559 /* Stop SD CLK output. */
2560 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2561 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302562 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002563 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564
2565 /*
2566 * Switch VDDPX from high voltage to low voltage
2567 * to change the VDD of the SD IO pads.
2568 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302569 rc = msmsdcc_set_vddp_low_vol(host);
2570 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572
2573 spin_lock_irqsave(&host->lock, flags);
2574 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2575 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302576 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577 host->io_pad_pwr_switch = 1;
2578 spin_unlock_irqrestore(&host->lock, flags);
2579
2580 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2581 usleep_range(5000, 5500);
2582
2583 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302584 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2586 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302587 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 spin_unlock_irqrestore(&host->lock, flags);
2589
2590 /*
2591 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2592 * don't become all ones within 1 ms then a Voltage Switch
2593 * sequence has failed and a power cycle to the card is required.
2594 * Otherwise Voltage Switch sequence is completed successfully.
2595 */
2596 usleep_range(1000, 1500);
2597
2598 spin_lock_irqsave(&host->lock, flags);
2599 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2600 != (0xF << 1)) {
2601 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2602 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302603 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604 goto out_unlock;
2605 }
2606
2607out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302608 /* Enable PWRSAVE */
2609 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2610 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 spin_unlock_irqrestore(&host->lock, flags);
2612out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302613 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614}
2615
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302616static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619
2620 /* Program the MCLK value to MCLK_FREQ bit field */
2621 if (host->clk_rate <= 112000000)
2622 mclk_freq = 0;
2623 else if (host->clk_rate <= 125000000)
2624 mclk_freq = 1;
2625 else if (host->clk_rate <= 137000000)
2626 mclk_freq = 2;
2627 else if (host->clk_rate <= 150000000)
2628 mclk_freq = 3;
2629 else if (host->clk_rate <= 162000000)
2630 mclk_freq = 4;
2631 else if (host->clk_rate <= 175000000)
2632 mclk_freq = 5;
2633 else if (host->clk_rate <= 187000000)
2634 mclk_freq = 6;
2635 else if (host->clk_rate <= 200000000)
2636 mclk_freq = 7;
2637
2638 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2639 & ~(7 << 24)) | (mclk_freq << 24)),
2640 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002641}
2642
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302643/* Initialize the DLL (Programmable Delay Line ) */
2644static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302647 unsigned long flags;
2648 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302650 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 /*
2652 * Make sure that clock is always enabled when DLL
2653 * tuning is in progress. Keeping PWRSAVE ON may
2654 * turn off the clock. So let's disable the PWRSAVE
2655 * here and re-enable it once tuning is completed.
2656 */
2657 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2658 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302659
2660 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2661 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2662 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2663
2664 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2665 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2666 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2667
2668 msmsdcc_cm_sdc4_dll_set_freq(host);
2669
2670 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2671 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2672 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2673
2674 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2675 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2676 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2677
2678 /* Set DLL_EN bit to 1. */
2679 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2680 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2681
2682 /* Set CK_OUT_EN bit to 1. */
2683 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2684 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2685
2686 wait_cnt = 50;
2687 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2688 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2689 /* max. wait for 50us sec for LOCK bit to be set */
2690 if (--wait_cnt == 0) {
2691 pr_err("%s: %s: DLL failed to LOCK\n",
2692 mmc_hostname(host->mmc), __func__);
2693 rc = -ETIMEDOUT;
2694 goto out;
2695 }
2696 /* wait for 1us before polling again */
2697 udelay(1);
2698 }
2699
2700out:
2701 /* re-enable PWRSAVE */
2702 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2703 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2704 spin_unlock_irqrestore(&host->lock, flags);
2705
2706 return rc;
2707}
2708
2709static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2710 u8 poll)
2711{
2712 int rc = 0;
2713 u32 wait_cnt = 50;
2714 u8 ck_out_en = 0;
2715
2716 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2717 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2718 MCI_CK_OUT_EN);
2719
2720 while (ck_out_en != poll) {
2721 if (--wait_cnt == 0) {
2722 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2723 mmc_hostname(host->mmc), __func__, poll);
2724 rc = -ETIMEDOUT;
2725 goto out;
2726 }
2727 udelay(1);
2728
2729 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2730 MCI_CK_OUT_EN);
2731 }
2732out:
2733 return rc;
2734}
2735
2736/*
2737 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2738 * calibration sequence. This function should be called before
2739 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2740 * commands (CMD17/CMD18).
2741 *
2742 * This function gets called when host spinlock acquired.
2743 */
2744static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2745{
2746 int rc = 0;
2747 u32 config;
2748
2749 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2750 config |= MCI_CDR_EN;
2751 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2752 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2753
2754 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2755 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2756 if (rc)
2757 goto err_out;
2758
2759 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2760 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2761 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2762
2763 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2764 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2765 if (rc)
2766 goto err_out;
2767
2768 goto out;
2769
2770err_out:
2771 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2772out:
2773 return rc;
2774}
2775
2776static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2777 u8 phase)
2778{
2779 int rc = 0;
2780 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6,
2781 0x7, 0x5, 0x4, 0x8, 0x9,
2782 0xB, 0xA, 0xE, 0xF, 0xD,
2783 0xC};
2784 unsigned long flags;
2785 u32 config;
2786
2787 spin_lock_irqsave(&host->lock, flags);
2788
2789 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2790 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2791 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2792 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2793
2794 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2795 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2796 if (rc)
2797 goto err_out;
2798
2799 /*
2800 * Write the selected DLL clock output phase (0 ... 15)
2801 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2802 */
2803 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2804 & ~(0xF << 20))
2805 | (grey_coded_phase_table[phase] << 20)),
2806 host->base + MCI_DLL_CONFIG);
2807
2808 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2809 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2810 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2811
2812 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2813 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2814 if (rc)
2815 goto err_out;
2816
2817 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2818 config |= MCI_CDR_EN;
2819 config &= ~MCI_CDR_EXT_EN;
2820 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2821 goto out;
2822
2823err_out:
2824 pr_err("%s: %s: Failed to set DLL phase: %d\n",
2825 mmc_hostname(host->mmc), __func__, phase);
2826out:
2827 spin_unlock_irqrestore(&host->lock, flags);
2828 return rc;
2829}
2830
2831/*
2832 * Find out the greatest range of consecuitive selected
2833 * DLL clock output phases that can be used as sampling
2834 * setting for SD3.0 UHS-I card read operation (in SDR104
2835 * timing mode) or for eMMC4.5 card read operation (in HS200
2836 * timing mode).
2837 * Select the 3/4 of the range and configure the DLL with the
2838 * selected DLL clock output phase.
2839*/
2840
2841static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
2842 u8 *phase_table, u8 total_phases)
2843{
2844 u8 ret, temp;
2845 u8 ranges[16][16] = { {0}, {0} };
2846 u8 phases_per_row[16] = {0};
2847 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
2848 int cnt;
2849
2850 for (cnt = 0; cnt <= total_phases; cnt++) {
2851 ranges[row_index][col_index] = phase_table[cnt];
2852 phases_per_row[row_index] += 1;
2853 col_index++;
2854
2855 if ((cnt + 1) > total_phases) {
2856 continue;
2857 /* check if next phase in phase_table is consecutive or not */
2858 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2859 row_index++;
2860 col_index = 0;
2861 }
2862 }
2863
2864 for (cnt = 0; cnt <= total_phases; cnt++) {
2865 if (phases_per_row[cnt] > curr_max) {
2866 curr_max = phases_per_row[cnt];
2867 selected_row_index = cnt;
2868 }
2869 }
2870
2871 temp = ((curr_max * 3) / 4);
2872 ret = ranges[selected_row_index][temp];
2873
2874 return ret;
2875}
2876
2877static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2878{
2879 int rc = 0;
2880 struct msmsdcc_host *host = mmc_priv(mmc);
2881 unsigned long flags;
2882 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2883
2884 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2885
2886 /* Tuning is only required for SDR104 modes */
2887 if (!host->tuning_needed) {
2888 rc = 0;
2889 goto exit;
2890 }
2891
2892 spin_lock_irqsave(&host->lock, flags);
2893 WARN(!host->pwr, "SDCC power is turned off\n");
2894 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2895 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2896
2897 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302898 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302899 spin_unlock_irqrestore(&host->lock, flags);
2900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901 /* first of all reset the tuning block */
2902 rc = msmsdcc_init_cm_sdc4_dll(host);
2903 if (rc)
2904 goto out;
2905
2906 data_buf = kmalloc(64, GFP_KERNEL);
2907 if (!data_buf) {
2908 rc = -ENOMEM;
2909 goto out;
2910 }
2911
2912 phase = 0;
2913 do {
2914 struct mmc_command cmd = {0};
2915 struct mmc_data data = {0};
2916 struct mmc_request mrq = {
2917 .cmd = &cmd,
2918 .data = &data
2919 };
2920 struct scatterlist sg;
2921
2922 /* set the phase in delay line hw block */
2923 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2924 if (rc)
2925 goto kfree;
2926
2927 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2928 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2929
2930 data.blksz = 64;
2931 data.blocks = 1;
2932 data.flags = MMC_DATA_READ;
2933 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2934
2935 data.sg = &sg;
2936 data.sg_len = 1;
2937 sg_init_one(&sg, data_buf, 64);
2938 memset(data_buf, 0, 64);
2939 mmc_wait_for_req(mmc, &mrq);
2940
2941 if (!cmd.error && !data.error &&
2942 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2943 /* tuning is successful with this tuning point */
2944 tuned_phases[tuned_phase_cnt++] = phase;
2945 }
2946 } while (++phase < 16);
2947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 if (tuned_phase_cnt) {
2949 tuned_phase_cnt--;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302950 phase = find_most_appropriate_phase(host, tuned_phases,
2951 tuned_phase_cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002952 /*
2953 * Finally set the selected phase in delay
2954 * line hw block.
2955 */
2956 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2957 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302958 goto kfree;
2959 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
2960 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 } else {
2962 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302963 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302965 msmsdcc_dump_sdcc_state(host);
2966 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002967 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002968
2969kfree:
2970 kfree(data_buf);
2971out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302972 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302973 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302975 spin_unlock_irqrestore(&host->lock, flags);
2976exit:
2977 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002979}
2980
2981static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982 .enable = msmsdcc_enable,
2983 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002984 .request = msmsdcc_request,
2985 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986 .get_ro = msmsdcc_get_ro,
2987#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002988 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989#endif
2990 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2991 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002992};
2993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994static unsigned int
2995msmsdcc_slot_status(struct msmsdcc_host *host)
2996{
2997 int status;
2998 unsigned int gpio_no = host->plat->status_gpio;
2999
3000 status = gpio_request(gpio_no, "SD_HW_Detect");
3001 if (status) {
3002 pr_err("%s: %s: Failed to request GPIO %d\n",
3003 mmc_hostname(host->mmc), __func__, gpio_no);
3004 } else {
3005 status = gpio_direction_input(gpio_no);
3006 if (!status)
Krishna Konda360aa422011-12-06 18:27:41 -08003007 status = gpio_get_value_cansleep(gpio_no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008 gpio_free(gpio_no);
3009 }
3010 return status;
3011}
3012
San Mehat9d2bd732009-09-22 16:44:22 -07003013static void
3014msmsdcc_check_status(unsigned long data)
3015{
3016 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3017 unsigned int status;
3018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda360aa422011-12-06 18:27:41 -08003020 if (host->plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda360aa422011-12-06 18:27:41 -08003022 host->eject = !status;
3023 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 status = msmsdcc_slot_status(host);
3025
Krishna Konda360aa422011-12-06 18:27:41 -08003026 if (host->plat->is_status_gpio_active_low)
3027 host->eject = status;
3028 else
3029 host->eject = !status;
3030 }
3031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003033 if (host->plat->status)
3034 pr_info("%s: Slot status change detected "
3035 "(%d -> %d)\n",
3036 mmc_hostname(host->mmc),
3037 host->oldstat, status);
3038 else if (host->plat->is_status_gpio_active_low)
3039 pr_info("%s: Slot status change detected "
3040 "(%d -> %d) and the card detect GPIO"
3041 " is ACTIVE_LOW\n",
3042 mmc_hostname(host->mmc),
3043 host->oldstat, status);
3044 else
3045 pr_info("%s: Slot status change detected "
3046 "(%d -> %d) and the card detect GPIO"
3047 " is ACTIVE_HIGH\n",
3048 mmc_hostname(host->mmc),
3049 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003050 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003051 }
3052 host->oldstat = status;
3053 } else {
3054 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003055 }
San Mehat9d2bd732009-09-22 16:44:22 -07003056}
3057
3058static irqreturn_t
3059msmsdcc_platform_status_irq(int irq, void *dev_id)
3060{
3061 struct msmsdcc_host *host = dev_id;
3062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003064 msmsdcc_check_status((unsigned long) host);
3065 return IRQ_HANDLED;
3066}
3067
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068static irqreturn_t
3069msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3070{
3071 struct msmsdcc_host *host = dev_id;
3072
3073 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3074 spin_lock(&host->lock);
3075 if (!host->sdio_irq_disabled) {
3076 disable_irq_nosync(irq);
3077 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3078 wake_lock(&host->sdio_wlock);
3079 msmsdcc_disable_irq_wake(host);
3080 }
3081 host->sdio_irq_disabled = 1;
3082 }
3083 if (host->plat->is_sdio_al_client) {
3084 if (!host->clks_on) {
3085 msmsdcc_setup_clocks(host, true);
3086 host->clks_on = 1;
3087 }
3088 if (host->sdcc_irq_disabled) {
3089 writel_relaxed(host->mci_irqenable,
3090 host->base + MMCIMASK0);
3091 mb();
3092 enable_irq(host->core_irqres->start);
3093 host->sdcc_irq_disabled = 0;
3094 }
3095 wake_lock(&host->sdio_wlock);
3096 }
3097 spin_unlock(&host->lock);
3098
3099 return IRQ_HANDLED;
3100}
3101
San Mehat9d2bd732009-09-22 16:44:22 -07003102static void
3103msmsdcc_status_notify_cb(int card_present, void *dev_id)
3104{
3105 struct msmsdcc_host *host = dev_id;
3106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003108 card_present);
3109 msmsdcc_check_status((unsigned long) host);
3110}
3111
San Mehat9d2bd732009-09-22 16:44:22 -07003112static int
3113msmsdcc_init_dma(struct msmsdcc_host *host)
3114{
3115 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3116 host->dma.host = host;
3117 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003118 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003119
3120 if (!host->dmares)
3121 return -ENODEV;
3122
3123 host->dma.nc = dma_alloc_coherent(NULL,
3124 sizeof(struct msmsdcc_nc_dmadata),
3125 &host->dma.nc_busaddr,
3126 GFP_KERNEL);
3127 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003128 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003129 return -ENOMEM;
3130 }
3131 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3132 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3133 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3134 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3135 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003136 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003137
3138 return 0;
3139}
3140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003141#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3142/**
3143 * Allocate and Connect a SDCC peripheral's SPS endpoint
3144 *
3145 * This function allocates endpoint context and
3146 * connect it with memory endpoint by calling
3147 * appropriate SPS driver APIs.
3148 *
3149 * Also registers a SPS callback function with
3150 * SPS driver
3151 *
3152 * This function should only be called once typically
3153 * during driver probe.
3154 *
3155 * @host - Pointer to sdcc host structure
3156 * @ep - Pointer to sps endpoint data structure
3157 * @is_produce - 1 means Producer endpoint
3158 * 0 means Consumer endpoint
3159 *
3160 * @return - 0 if successful else negative value.
3161 *
3162 */
3163static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3164 struct msmsdcc_sps_ep_conn_data *ep,
3165 bool is_producer)
3166{
3167 int rc = 0;
3168 struct sps_pipe *sps_pipe_handle;
3169 struct sps_connect *sps_config = &ep->config;
3170 struct sps_register_event *sps_event = &ep->event;
3171
3172 /* Allocate endpoint context */
3173 sps_pipe_handle = sps_alloc_endpoint();
3174 if (!sps_pipe_handle) {
3175 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3176 mmc_hostname(host->mmc), is_producer);
3177 rc = -ENOMEM;
3178 goto out;
3179 }
3180
3181 /* Get default connection configuration for an endpoint */
3182 rc = sps_get_config(sps_pipe_handle, sps_config);
3183 if (rc) {
3184 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3185 " rc=%d", mmc_hostname(host->mmc),
3186 (u32)sps_pipe_handle, rc);
3187 goto get_config_err;
3188 }
3189
3190 /* Modify the default connection configuration */
3191 if (is_producer) {
3192 /*
3193 * For SDCC producer transfer, source should be
3194 * SDCC peripheral where as destination should
3195 * be system memory.
3196 */
3197 sps_config->source = host->sps.bam_handle;
3198 sps_config->destination = SPS_DEV_HANDLE_MEM;
3199 /* Producer pipe will handle this connection */
3200 sps_config->mode = SPS_MODE_SRC;
3201 sps_config->options =
3202 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3203 } else {
3204 /*
3205 * For SDCC consumer transfer, source should be
3206 * system memory where as destination should
3207 * SDCC peripheral
3208 */
3209 sps_config->source = SPS_DEV_HANDLE_MEM;
3210 sps_config->destination = host->sps.bam_handle;
3211 sps_config->mode = SPS_MODE_DEST;
3212 sps_config->options =
3213 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3214 }
3215
3216 /* Producer pipe index */
3217 sps_config->src_pipe_index = host->sps.src_pipe_index;
3218 /* Consumer pipe index */
3219 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3220 /*
3221 * This event thresold value is only significant for BAM-to-BAM
3222 * transfer. It's ignored for BAM-to-System mode transfer.
3223 */
3224 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303225
3226 /* Allocate maximum descriptor fifo size */
3227 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3228 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3230 sps_config->desc.size,
3231 &sps_config->desc.phys_base,
3232 GFP_KERNEL);
3233
Pratibhasagar V00b94332011-10-18 14:57:27 +05303234 if (!sps_config->desc.base) {
3235 rc = -ENOMEM;
3236 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3237 , mmc_hostname(host->mmc));
3238 goto get_config_err;
3239 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3241
3242 /* Establish connection between peripheral and memory endpoint */
3243 rc = sps_connect(sps_pipe_handle, sps_config);
3244 if (rc) {
3245 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3246 " rc=%d", mmc_hostname(host->mmc),
3247 (u32)sps_pipe_handle, rc);
3248 goto sps_connect_err;
3249 }
3250
3251 sps_event->mode = SPS_TRIGGER_CALLBACK;
3252 sps_event->options = SPS_O_EOT;
3253 sps_event->callback = msmsdcc_sps_complete_cb;
3254 sps_event->xfer_done = NULL;
3255 sps_event->user = (void *)host;
3256
3257 /* Register callback event for EOT (End of transfer) event. */
3258 rc = sps_register_event(sps_pipe_handle, sps_event);
3259 if (rc) {
3260 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3261 " rc=%d", mmc_hostname(host->mmc),
3262 (u32)sps_pipe_handle, rc);
3263 goto reg_event_err;
3264 }
3265 /* Now save the sps pipe handle */
3266 ep->pipe_handle = sps_pipe_handle;
3267 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3268 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3269 __func__, is_producer ? "READ" : "WRITE",
3270 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3271 goto out;
3272
3273reg_event_err:
3274 sps_disconnect(sps_pipe_handle);
3275sps_connect_err:
3276 dma_free_coherent(mmc_dev(host->mmc),
3277 sps_config->desc.size,
3278 sps_config->desc.base,
3279 sps_config->desc.phys_base);
3280get_config_err:
3281 sps_free_endpoint(sps_pipe_handle);
3282out:
3283 return rc;
3284}
3285
3286/**
3287 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3288 *
3289 * This function disconnect endpoint and deallocates
3290 * endpoint context.
3291 *
3292 * This function should only be called once typically
3293 * during driver remove.
3294 *
3295 * @host - Pointer to sdcc host structure
3296 * @ep - Pointer to sps endpoint data structure
3297 *
3298 */
3299static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3300 struct msmsdcc_sps_ep_conn_data *ep)
3301{
3302 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3303 struct sps_connect *sps_config = &ep->config;
3304 struct sps_register_event *sps_event = &ep->event;
3305
3306 sps_event->xfer_done = NULL;
3307 sps_event->callback = NULL;
3308 sps_register_event(sps_pipe_handle, sps_event);
3309 sps_disconnect(sps_pipe_handle);
3310 dma_free_coherent(mmc_dev(host->mmc),
3311 sps_config->desc.size,
3312 sps_config->desc.base,
3313 sps_config->desc.phys_base);
3314 sps_free_endpoint(sps_pipe_handle);
3315}
3316
3317/**
3318 * Reset SDCC peripheral's SPS endpoint
3319 *
3320 * This function disconnects an endpoint.
3321 *
3322 * This function should be called for reseting
3323 * SPS endpoint when data transfer error is
3324 * encountered during data transfer. This
3325 * can be considered as soft reset to endpoint.
3326 *
3327 * This function should only be called if
3328 * msmsdcc_sps_init() is already called.
3329 *
3330 * @host - Pointer to sdcc host structure
3331 * @ep - Pointer to sps endpoint data structure
3332 *
3333 * @return - 0 if successful else negative value.
3334 */
3335static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3336 struct msmsdcc_sps_ep_conn_data *ep)
3337{
3338 int rc = 0;
3339 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3340
3341 rc = sps_disconnect(sps_pipe_handle);
3342 if (rc) {
3343 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3344 " rc=%d", mmc_hostname(host->mmc), __func__,
3345 (u32)sps_pipe_handle, rc);
3346 goto out;
3347 }
3348 out:
3349 return rc;
3350}
3351
3352/**
3353 * Restore SDCC peripheral's SPS endpoint
3354 *
3355 * This function connects an endpoint.
3356 *
3357 * This function should be called for restoring
3358 * SPS endpoint after data transfer error is
3359 * encountered during data transfer. This
3360 * can be considered as soft reset to endpoint.
3361 *
3362 * This function should only be called if
3363 * msmsdcc_sps_reset_ep() is called before.
3364 *
3365 * @host - Pointer to sdcc host structure
3366 * @ep - Pointer to sps endpoint data structure
3367 *
3368 * @return - 0 if successful else negative value.
3369 */
3370static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3371 struct msmsdcc_sps_ep_conn_data *ep)
3372{
3373 int rc = 0;
3374 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3375 struct sps_connect *sps_config = &ep->config;
3376 struct sps_register_event *sps_event = &ep->event;
3377
3378 /* Establish connection between peripheral and memory endpoint */
3379 rc = sps_connect(sps_pipe_handle, sps_config);
3380 if (rc) {
3381 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3382 " rc=%d", mmc_hostname(host->mmc), __func__,
3383 (u32)sps_pipe_handle, rc);
3384 goto out;
3385 }
3386
3387 /* Register callback event for EOT (End of transfer) event. */
3388 rc = sps_register_event(sps_pipe_handle, sps_event);
3389 if (rc) {
3390 pr_err("%s: %s: sps_register_event() failed!!!"
3391 " pipe_handle=0x%x, rc=%d",
3392 mmc_hostname(host->mmc), __func__,
3393 (u32)sps_pipe_handle, rc);
3394 goto reg_event_err;
3395 }
3396 goto out;
3397
3398reg_event_err:
3399 sps_disconnect(sps_pipe_handle);
3400out:
3401 return rc;
3402}
3403
3404/**
3405 * Initialize SPS HW connected with SDCC core
3406 *
3407 * This function register BAM HW resources with
3408 * SPS driver and then initialize 2 SPS endpoints
3409 *
3410 * This function should only be called once typically
3411 * during driver probe.
3412 *
3413 * @host - Pointer to sdcc host structure
3414 *
3415 * @return - 0 if successful else negative value.
3416 *
3417 */
3418static int msmsdcc_sps_init(struct msmsdcc_host *host)
3419{
3420 int rc = 0;
3421 struct sps_bam_props bam = {0};
3422
3423 host->bam_base = ioremap(host->bam_memres->start,
3424 resource_size(host->bam_memres));
3425 if (!host->bam_base) {
3426 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3427 " size=0x%x", mmc_hostname(host->mmc),
3428 host->bam_memres->start,
3429 (host->bam_memres->end -
3430 host->bam_memres->start));
3431 rc = -ENOMEM;
3432 goto out;
3433 }
3434
3435 bam.phys_addr = host->bam_memres->start;
3436 bam.virt_addr = host->bam_base;
3437 /*
3438 * This event thresold value is only significant for BAM-to-BAM
3439 * transfer. It's ignored for BAM-to-System mode transfer.
3440 */
3441 bam.event_threshold = 0x10; /* Pipe event threshold */
3442 /*
3443 * This threshold controls when the BAM publish
3444 * the descriptor size on the sideband interface.
3445 * SPS HW will only be used when
3446 * data transfer size > MCI_FIFOSIZE (64 bytes).
3447 * PIO mode will be used when
3448 * data transfer size < MCI_FIFOSIZE (64 bytes).
3449 * So set this thresold value to 64 bytes.
3450 */
3451 bam.summing_threshold = 64;
3452 /* SPS driver wll handle the SDCC BAM IRQ */
3453 bam.irq = (u32)host->bam_irqres->start;
3454 bam.manage = SPS_BAM_MGR_LOCAL;
3455
3456 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3457 (u32)bam.phys_addr);
3458 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3459 (u32)bam.virt_addr);
3460
3461 /* Register SDCC Peripheral BAM device to SPS driver */
3462 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3463 if (rc) {
3464 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3465 mmc_hostname(host->mmc), rc);
3466 goto reg_bam_err;
3467 }
3468 pr_info("%s: BAM device registered. bam_handle=0x%x",
3469 mmc_hostname(host->mmc), host->sps.bam_handle);
3470
3471 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3472 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3473
3474 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3475 SPS_PROD_PERIPHERAL);
3476 if (rc)
3477 goto sps_reset_err;
3478 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3479 SPS_CONS_PERIPHERAL);
3480 if (rc)
3481 goto cons_conn_err;
3482
3483 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3484 mmc_hostname(host->mmc),
3485 (unsigned long long)host->bam_memres->start,
3486 (unsigned int)host->bam_irqres->start);
3487 goto out;
3488
3489cons_conn_err:
3490 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3491sps_reset_err:
3492 sps_deregister_bam_device(host->sps.bam_handle);
3493reg_bam_err:
3494 iounmap(host->bam_base);
3495out:
3496 return rc;
3497}
3498
3499/**
3500 * De-initialize SPS HW connected with SDCC core
3501 *
3502 * This function deinitialize SPS endpoints and then
3503 * deregisters BAM resources from SPS driver.
3504 *
3505 * This function should only be called once typically
3506 * during driver remove.
3507 *
3508 * @host - Pointer to sdcc host structure
3509 *
3510 */
3511static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3512{
3513 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3514 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3515 sps_deregister_bam_device(host->sps.bam_handle);
3516 iounmap(host->bam_base);
3517}
3518#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3519
3520static ssize_t
3521show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3522{
3523 struct mmc_host *mmc = dev_get_drvdata(dev);
3524 struct msmsdcc_host *host = mmc_priv(mmc);
3525 int poll;
3526 unsigned long flags;
3527
3528 spin_lock_irqsave(&host->lock, flags);
3529 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3530 spin_unlock_irqrestore(&host->lock, flags);
3531
3532 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3533}
3534
3535static ssize_t
3536set_polling(struct device *dev, struct device_attribute *attr,
3537 const char *buf, size_t count)
3538{
3539 struct mmc_host *mmc = dev_get_drvdata(dev);
3540 struct msmsdcc_host *host = mmc_priv(mmc);
3541 int value;
3542 unsigned long flags;
3543
3544 sscanf(buf, "%d", &value);
3545
3546 spin_lock_irqsave(&host->lock, flags);
3547 if (value) {
3548 mmc->caps |= MMC_CAP_NEEDS_POLL;
3549 mmc_detect_change(host->mmc, 0);
3550 } else {
3551 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3552 }
3553#ifdef CONFIG_HAS_EARLYSUSPEND
3554 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3555#endif
3556 spin_unlock_irqrestore(&host->lock, flags);
3557 return count;
3558}
3559
3560static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3561 show_polling, set_polling);
3562static struct attribute *dev_attrs[] = {
3563 &dev_attr_polling.attr,
3564 NULL,
3565};
3566static struct attribute_group dev_attr_grp = {
3567 .attrs = dev_attrs,
3568};
3569
3570#ifdef CONFIG_HAS_EARLYSUSPEND
3571static void msmsdcc_early_suspend(struct early_suspend *h)
3572{
3573 struct msmsdcc_host *host =
3574 container_of(h, struct msmsdcc_host, early_suspend);
3575 unsigned long flags;
3576
3577 spin_lock_irqsave(&host->lock, flags);
3578 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3579 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3580 spin_unlock_irqrestore(&host->lock, flags);
3581};
3582static void msmsdcc_late_resume(struct early_suspend *h)
3583{
3584 struct msmsdcc_host *host =
3585 container_of(h, struct msmsdcc_host, early_suspend);
3586 unsigned long flags;
3587
3588 if (host->polling_enabled) {
3589 spin_lock_irqsave(&host->lock, flags);
3590 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3591 mmc_detect_change(host->mmc, 0);
3592 spin_unlock_irqrestore(&host->lock, flags);
3593 }
3594};
3595#endif
3596
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303597void msmsdcc_print_regs(const char *name, void __iomem *base,
3598 unsigned int no_of_regs)
3599{
3600 unsigned int i;
3601
3602 if (!base)
3603 return;
3604 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3605 name, (u32)base);
3606 for (i = 0; i < no_of_regs; i = i + 4) {
3607 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3608 (u32)readl_relaxed(base + i*4),
3609 (u32)readl_relaxed(base + ((i+1)*4)),
3610 (u32)readl_relaxed(base + ((i+2)*4)),
3611 (u32)readl_relaxed(base + ((i+3)*4)));
3612 }
3613}
3614
3615static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3616{
3617 /* Dump current state of SDCC clocks, power and irq */
3618 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3619 (host->pwr ? "ON" : "OFF"));
3620 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3621 mmc_hostname(host->mmc),
3622 (host->clks_on ? "ON" : "OFF"),
3623 (u32)clk_get_rate(host->clk));
3624 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3625 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3626
3627 /* Now dump SDCC registers. Don't print FIFO registers */
3628 if (host->clks_on)
3629 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3630
3631 if (host->curr.data) {
3632 if (msmsdcc_check_dma_op_req(host->curr.data))
3633 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3634 else if (host->is_dma_mode)
3635 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3636 mmc_hostname(host->mmc), host->dma.busy,
3637 host->dma.channel, host->dma.crci);
3638 else if (host->is_sps_mode)
3639 pr_info("%s: SPS mode: busy=%d\n",
3640 mmc_hostname(host->mmc), host->sps.busy);
3641
3642 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3643 mmc_hostname(host->mmc), host->curr.xfer_size,
3644 host->curr.data_xfered, host->curr.xfer_remain);
3645 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3646 " wait_for_auto_prog_done=%d,"
3647 " got_auto_prog_done=%d\n",
3648 mmc_hostname(host->mmc), host->curr.got_dataend,
3649 host->prog_enable, host->curr.wait_for_auto_prog_done,
3650 host->curr.got_auto_prog_done);
3651 }
3652
3653}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3655{
3656 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3657 struct mmc_request *mrq;
3658 unsigned long flags;
3659
3660 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003661 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662 pr_info("%s: %s: dummy CMD52 timeout\n",
3663 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003664 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003665 }
3666
3667 mrq = host->curr.mrq;
3668
3669 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303670 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3671 mrq->cmd->opcode);
3672 msmsdcc_dump_sdcc_state(host);
3673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674 if (!mrq->cmd->error)
3675 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303676 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678 if (mrq->data && !mrq->data->error)
3679 mrq->data->error = -ETIMEDOUT;
3680 host->curr.data_xfered = 0;
3681 if (host->dma.sg && host->is_dma_mode) {
3682 msm_dmov_stop_cmd(host->dma.channel,
3683 &host->dma.hdr, 0);
3684 } else if (host->sps.sg && host->is_sps_mode) {
3685 /* Stop current SPS transfer */
3686 msmsdcc_sps_exit_curr_xfer(host);
3687 } else {
3688 msmsdcc_reset_and_restore(host);
3689 msmsdcc_stop_data(host);
3690 if (mrq->data && mrq->data->stop)
3691 msmsdcc_start_command(host,
3692 mrq->data->stop, 0);
3693 else
3694 msmsdcc_request_end(host, mrq);
3695 }
3696 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303697 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003698 msmsdcc_reset_and_restore(host);
3699 msmsdcc_request_end(host, mrq);
3700 }
3701 }
3702 spin_unlock_irqrestore(&host->lock, flags);
3703}
3704
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303705static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3706{
3707 int i, ret;
3708 struct mmc_platform_data *pdata;
3709 struct device_node *np = dev->of_node;
3710 u32 bus_width = 0;
3711 u32 *clk_table;
3712 int clk_table_len;
3713 u32 *sup_voltages;
3714 int sup_volt_len;
3715
3716 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3717 if (!pdata) {
3718 dev_err(dev, "could not allocate memory for platform data\n");
3719 goto err;
3720 }
3721
3722 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3723 if (bus_width == 8) {
3724 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3725 } else if (bus_width == 4) {
3726 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3727 } else {
3728 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3729 pdata->mmc_bus_width = 0;
3730 }
3731
3732 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3733 size_t sz;
3734 sz = sup_volt_len / sizeof(*sup_voltages);
3735 if (sz > 0) {
3736 sup_voltages = devm_kzalloc(dev,
3737 sz * sizeof(*sup_voltages), GFP_KERNEL);
3738 if (!sup_voltages) {
3739 dev_err(dev, "No memory for supported voltage\n");
3740 goto err;
3741 }
3742
3743 ret = of_property_read_u32_array(np,
3744 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3745 if (ret < 0) {
3746 dev_err(dev, "error while reading voltage"
3747 "ranges %d\n", ret);
3748 goto err;
3749 }
3750 } else {
3751 dev_err(dev, "No supported voltages\n");
3752 goto err;
3753 }
3754 for (i = 0; i < sz; i += 2) {
3755 u32 mask;
3756
3757 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3758 sup_voltages[i + 1]);
3759 if (!mask)
3760 dev_err(dev, "Invalide voltage range %d\n", i);
3761 pdata->ocr_mask |= mask;
3762 }
3763 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3764 } else {
3765 dev_err(dev, "Supported voltage range not specified\n");
3766 }
3767
3768 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3769 size_t sz;
3770 sz = clk_table_len / sizeof(*clk_table);
3771
3772 if (sz > 0) {
3773 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3774 GFP_KERNEL);
3775 if (!clk_table) {
3776 dev_err(dev, "No memory for clock table\n");
3777 goto err;
3778 }
3779
3780 ret = of_property_read_u32_array(np,
3781 "qcom,sdcc-clk-rates", clk_table, sz);
3782 if (ret < 0) {
3783 dev_err(dev, "error while reading clk"
3784 "table %d\n", ret);
3785 goto err;
3786 }
3787 } else {
3788 dev_err(dev, "clk_table not specified\n");
3789 goto err;
3790 }
3791 pdata->sup_clk_table = clk_table;
3792 pdata->sup_clk_cnt = sz;
3793 } else {
3794 dev_err(dev, "Supported clock rates not specified\n");
3795 }
3796
3797 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3798 pdata->nonremovable = true;
3799 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3800 pdata->disable_cmd23 = true;
3801
3802 return pdata;
3803err:
3804 return NULL;
3805}
3806
San Mehat9d2bd732009-09-22 16:44:22 -07003807static int
3808msmsdcc_probe(struct platform_device *pdev)
3809{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303810 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003811 struct msmsdcc_host *host;
3812 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813 unsigned long flags;
3814 struct resource *core_irqres = NULL;
3815 struct resource *bam_irqres = NULL;
3816 struct resource *core_memres = NULL;
3817 struct resource *dml_memres = NULL;
3818 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003819 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003820 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303821 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003822 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003823
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303824 if (pdev->dev.of_node) {
3825 plat = msmsdcc_populate_pdata(&pdev->dev);
3826 of_property_read_u32((&pdev->dev)->of_node,
3827 "cell-index", &pdev->id);
3828 } else {
3829 plat = pdev->dev.platform_data;
3830 }
3831
San Mehat9d2bd732009-09-22 16:44:22 -07003832 /* must have platform data */
3833 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003834 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003835 ret = -EINVAL;
3836 goto out;
3837 }
3838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003840 return -EINVAL;
3841
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303842 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3843 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3844 return -EINVAL;
3845 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846
San Mehat9d2bd732009-09-22 16:44:22 -07003847 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003848 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003849 return -ENXIO;
3850 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303851 if (pdev->dev.of_node) {
3852 /*
3853 * Device tree iomem resources are only accessible by index.
3854 * index = 0 -> SDCC register interface
3855 * index = 1 -> DML register interface
3856 * index = 2 -> BAM register interface
3857 * IRQ resources:
3858 * index = 0 -> SDCC IRQ
3859 * index = 1 -> BAM IRQ
3860 */
3861 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3862 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3863 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3864 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3865 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3866 } else {
3867 for (i = 0; i < pdev->num_resources; i++) {
3868 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3869 if (!strncmp(pdev->resource[i].name,
3870 "sdcc_dml_addr",
3871 sizeof("sdcc_dml_addr")))
3872 dml_memres = &pdev->resource[i];
3873 else if (!strncmp(pdev->resource[i].name,
3874 "sdcc_bam_addr",
3875 sizeof("sdcc_bam_addr")))
3876 bam_memres = &pdev->resource[i];
3877 else
3878 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003879
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303880 }
3881 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3882 if (!strncmp(pdev->resource[i].name,
3883 "sdcc_bam_irq",
3884 sizeof("sdcc_bam_irq")))
3885 bam_irqres = &pdev->resource[i];
3886 else
3887 core_irqres = &pdev->resource[i];
3888 }
3889 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3890 if (!strncmp(pdev->resource[i].name,
3891 "sdcc_dma_chnl",
3892 sizeof("sdcc_dma_chnl")))
3893 dmares = &pdev->resource[i];
3894 else if (!strncmp(pdev->resource[i].name,
3895 "sdcc_dma_crci",
3896 sizeof("sdcc_dma_crci")))
3897 dma_crci_res = &pdev->resource[i];
3898 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003899 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003900 }
3901
3902 if (!core_irqres || !core_memres) {
3903 pr_err("%s: Invalid sdcc core resource\n", __func__);
3904 return -ENXIO;
3905 }
3906
3907 /*
3908 * Both BAM and DML memory resource should be preset.
3909 * BAM IRQ resource should also be present.
3910 */
3911 if ((bam_memres && !dml_memres) ||
3912 (!bam_memres && dml_memres) ||
3913 ((bam_memres && dml_memres) && !bam_irqres)) {
3914 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003915 return -ENXIO;
3916 }
3917
3918 /*
3919 * Setup our host structure
3920 */
San Mehat9d2bd732009-09-22 16:44:22 -07003921 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3922 if (!mmc) {
3923 ret = -ENOMEM;
3924 goto out;
3925 }
3926
3927 host = mmc_priv(mmc);
3928 host->pdev_id = pdev->id;
3929 host->plat = plat;
3930 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003931 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303932
3933 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003934 host->is_sps_mode = 1;
3935 else if (dmares)
3936 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003937
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003938 host->base = ioremap(core_memres->start,
3939 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003940 if (!host->base) {
3941 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003943 }
3944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945 host->core_irqres = core_irqres;
3946 host->bam_irqres = bam_irqres;
3947 host->core_memres = core_memres;
3948 host->dml_memres = dml_memres;
3949 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003950 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003951 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003952 spin_lock_init(&host->lock);
3953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003954#ifdef CONFIG_MMC_EMBEDDED_SDIO
3955 if (plat->embedded_sdio)
3956 mmc_set_embedded_sdio_data(mmc,
3957 &plat->embedded_sdio->cis,
3958 &plat->embedded_sdio->cccr,
3959 plat->embedded_sdio->funcs,
3960 plat->embedded_sdio->num_funcs);
3961#endif
3962
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303963 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3964 (unsigned long)host);
3965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3967 (unsigned long)host);
3968 if (host->is_dma_mode) {
3969 /* Setup DMA */
3970 ret = msmsdcc_init_dma(host);
3971 if (ret)
3972 goto ioremap_free;
3973 } else {
3974 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003975 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003976 }
3977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003978 /*
3979 * Setup SDCC clock if derived from Dayatona
3980 * fabric core clock.
3981 */
3982 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003983 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 if (!IS_ERR(host->dfab_pclk)) {
3985 /* Set the clock rate to 64MHz for max. performance */
3986 ret = clk_set_rate(host->dfab_pclk, 64000000);
3987 if (ret)
3988 goto dfab_pclk_put;
3989 ret = clk_enable(host->dfab_pclk);
3990 if (ret)
3991 goto dfab_pclk_put;
3992 } else
3993 goto dma_free;
3994 }
3995
3996 /*
3997 * Setup main peripheral bus clock
3998 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003999 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004000 if (!IS_ERR(host->pclk)) {
4001 ret = clk_enable(host->pclk);
4002 if (ret)
4003 goto pclk_put;
4004
4005 host->pclk_rate = clk_get_rate(host->pclk);
4006 }
4007
4008 /*
4009 * Setup SDC MMC clock
4010 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004011 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004012 if (IS_ERR(host->clk)) {
4013 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004015 }
4016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004017 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4018 if (ret) {
4019 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4020 goto clk_put;
4021 }
4022
4023 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004024 if (ret)
4025 goto clk_put;
4026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004027 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304028 if (!host->clk_rate)
4029 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304030
4031 /*
4032 * Lookup the Controller Version, to identify the supported features
4033 * Version number read as 0 would indicate SDCC3 or earlier versions
4034 */
4035 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4036 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4037 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304038 /*
4039 * Set the register write delay according to min. clock frequency
4040 * supported and update later when the host->clk_rate changes.
4041 */
4042 host->reg_write_delay =
4043 (1 + ((3 * USEC_PER_SEC) /
4044 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045
4046 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304047 /* Apply Hard reset to SDCC to put it in power on default state */
4048 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004049
4050 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004051 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004053 goto clk_disable;
4054 }
4055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056
4057 /* Clocks has to be running before accessing SPS/DML HW blocks */
4058 if (host->is_sps_mode) {
4059 /* Initialize SPS */
4060 ret = msmsdcc_sps_init(host);
4061 if (ret)
4062 goto vreg_deinit;
4063 /* Initialize DML */
4064 ret = msmsdcc_dml_init(host);
4065 if (ret)
4066 goto sps_exit;
4067 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304068 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004069
San Mehat9d2bd732009-09-22 16:44:22 -07004070 /*
4071 * Setup MMC host structure
4072 */
4073 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004074 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4075 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004076 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4078 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004079
San Mehat9d2bd732009-09-22 16:44:22 -07004080 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304081 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304082
4083 /*
4084 * If we send the CMD23 before multi block write/read command
4085 * then we need not to send CMD12 at the end of the transfer.
4086 * If we don't send the CMD12 then only way to detect the PROG_DONE
4087 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4088 * controller. So let's enable the CMD23 for SDCC4 only.
4089 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304090 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304091 mmc->caps |= MMC_CAP_CMD23;
4092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004093 mmc->caps |= plat->uhs_caps;
4094 /*
4095 * XPC controls the maximum current in the default speed mode of SDXC
4096 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4097 * XPC=1 means 150mA (max.) and speed class is supported.
4098 */
4099 if (plat->xpc_cap)
4100 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4101 MMC_CAP_SET_XPC_180);
4102
4103 if (plat->nonremovable)
4104 mmc->caps |= MMC_CAP_NONREMOVABLE;
4105#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4106 mmc->caps |= MMC_CAP_SDIO_IRQ;
4107#endif
4108
4109 if (plat->is_sdio_al_client)
4110 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004111
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304112 mmc->max_segs = msmsdcc_get_nr_sg(host);
4113 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4114 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004115
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304116 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304117 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004119 writel_relaxed(0, host->base + MMCIMASK0);
4120 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4123 mb();
4124 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4127 DRIVER_NAME " (cmd)", host);
4128 if (ret)
4129 goto dml_exit;
4130
4131 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4132 DRIVER_NAME " (pio)", host);
4133 if (ret)
4134 goto irq_free;
4135
4136 /*
4137 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4138 * IRQ is un-necessarily being monitored by MPM (Modem power
4139 * management block) during idle-power collapse. The MPM will be
4140 * configured to monitor the DATA1 GPIO line with level-low trigger
4141 * and thus depending on the GPIO status, it prevents TCXO shutdown
4142 * during idle-power collapse.
4143 */
4144 disable_irq(core_irqres->start);
4145 host->sdcc_irq_disabled = 1;
4146
4147 if (plat->sdiowakeup_irq) {
4148 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4149 mmc_hostname(mmc));
4150 ret = request_irq(plat->sdiowakeup_irq,
4151 msmsdcc_platform_sdiowakeup_irq,
4152 IRQF_SHARED | IRQF_TRIGGER_LOW,
4153 DRIVER_NAME "sdiowakeup", host);
4154 if (ret) {
4155 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4156 plat->sdiowakeup_irq, ret);
4157 goto pio_irq_free;
4158 } else {
4159 spin_lock_irqsave(&host->lock, flags);
4160 if (!host->sdio_irq_disabled) {
4161 disable_irq_nosync(plat->sdiowakeup_irq);
4162 host->sdio_irq_disabled = 1;
4163 }
4164 spin_unlock_irqrestore(&host->lock, flags);
4165 }
4166 }
4167
4168 if (plat->cfg_mpm_sdiowakeup) {
4169 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4170 mmc_hostname(mmc));
4171 }
4172
4173 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4174 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004175 /*
4176 * Setup card detect change
4177 */
4178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004179 if (plat->status || plat->status_gpio) {
Krishna Konda360aa422011-12-06 18:27:41 -08004180 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004181 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda360aa422011-12-06 18:27:41 -08004182 host->eject = !host->oldstat;
4183 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004185
4186 if (host->plat->is_status_gpio_active_low)
4187 host->eject = host->oldstat;
4188 else
4189 host->eject = !host->oldstat;
4190 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004191 }
San Mehat9d2bd732009-09-22 16:44:22 -07004192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193 if (plat->status_irq) {
4194 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004195 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004197 DRIVER_NAME " (slot)",
4198 host);
4199 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 pr_err("Unable to get slot IRQ %d (%d)\n",
4201 plat->status_irq, ret);
4202 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004203 }
4204 } else if (plat->register_status_notify) {
4205 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4206 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004207 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004208 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004209
4210 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004211
4212 ret = pm_runtime_set_active(&(pdev)->dev);
4213 if (ret < 0)
4214 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4215 __func__, ret);
4216 /*
4217 * There is no notion of suspend/resume for SD/MMC/SDIO
4218 * cards. So host can be suspended/resumed with out
4219 * worrying about its children.
4220 */
4221 pm_suspend_ignore_children(&(pdev)->dev, true);
4222
4223 /*
4224 * MMC/SD/SDIO bus suspend/resume operations are defined
4225 * only for the slots that will be used for non-removable
4226 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4227 * defined. Otherwise, they simply become card removal and
4228 * insertion events during suspend and resume respectively.
4229 * Hence, enable run-time PM only for slots for which bus
4230 * suspend/resume operations are defined.
4231 */
4232#ifdef CONFIG_MMC_UNSAFE_RESUME
4233 /*
4234 * If this capability is set, MMC core will enable/disable host
4235 * for every claim/release operation on a host. We use this
4236 * notification to increment/decrement runtime pm usage count.
4237 */
4238 mmc->caps |= MMC_CAP_DISABLE;
4239 pm_runtime_enable(&(pdev)->dev);
4240#else
4241 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4242 mmc->caps |= MMC_CAP_DISABLE;
4243 pm_runtime_enable(&(pdev)->dev);
4244 }
4245#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304246#ifndef CONFIG_PM_RUNTIME
4247 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4248#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4250 (unsigned long)host);
4251
San Mehat9d2bd732009-09-22 16:44:22 -07004252 mmc_add_host(mmc);
4253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004254#ifdef CONFIG_HAS_EARLYSUSPEND
4255 host->early_suspend.suspend = msmsdcc_early_suspend;
4256 host->early_suspend.resume = msmsdcc_late_resume;
4257 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4258 register_early_suspend(&host->early_suspend);
4259#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004260
Krishna Konda25786ec2011-07-25 16:21:36 -07004261 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4262 " dmacrcri %d\n", mmc_hostname(mmc),
4263 (unsigned long long)core_memres->start,
4264 (unsigned int) core_irqres->start,
4265 (unsigned int) plat->status_irq, host->dma.channel,
4266 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267
4268 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4269 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4270 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4271 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4272 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4273 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4274 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4275 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4276 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4277 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4278 host->eject);
4279 pr_info("%s: Power save feature enable = %d\n",
4280 mmc_hostname(mmc), msmsdcc_pwrsave);
4281
Krishna Konda25786ec2011-07-25 16:21:36 -07004282 if (host->is_dma_mode && host->dma.channel != -1
4283 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004284 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004285 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004286 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287 mmc_hostname(mmc), host->dma.cmd_busaddr,
4288 host->dma.cmdptr_busaddr);
4289 } else if (host->is_sps_mode) {
4290 pr_info("%s: SPS-BAM data transfer mode available\n",
4291 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004292 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004293 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004295#if defined(CONFIG_DEBUG_FS)
4296 msmsdcc_dbg_createhost(host);
4297#endif
4298 if (!plat->status_irq) {
4299 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4300 if (ret)
4301 goto platform_irq_free;
4302 }
San Mehat9d2bd732009-09-22 16:44:22 -07004303 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304
4305 platform_irq_free:
4306 del_timer_sync(&host->req_tout_timer);
4307 pm_runtime_disable(&(pdev)->dev);
4308 pm_runtime_set_suspended(&(pdev)->dev);
4309
4310 if (plat->status_irq)
4311 free_irq(plat->status_irq, host);
4312 sdiowakeup_irq_free:
4313 wake_lock_destroy(&host->sdio_suspend_wlock);
4314 if (plat->sdiowakeup_irq)
4315 free_irq(plat->sdiowakeup_irq, host);
4316 pio_irq_free:
4317 if (plat->sdiowakeup_irq)
4318 wake_lock_destroy(&host->sdio_wlock);
4319 free_irq(core_irqres->start, host);
4320 irq_free:
4321 free_irq(core_irqres->start, host);
4322 dml_exit:
4323 if (host->is_sps_mode)
4324 msmsdcc_dml_exit(host);
4325 sps_exit:
4326 if (host->is_sps_mode)
4327 msmsdcc_sps_exit(host);
4328 vreg_deinit:
4329 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004330 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004331 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004332 clk_put:
4333 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334 pclk_disable:
4335 if (!IS_ERR(host->pclk))
4336 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004337 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 if (!IS_ERR(host->pclk))
4339 clk_put(host->pclk);
4340 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4341 clk_disable(host->dfab_pclk);
4342 dfab_pclk_put:
4343 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4344 clk_put(host->dfab_pclk);
4345 dma_free:
4346 if (host->is_dma_mode) {
4347 if (host->dmares)
4348 dma_free_coherent(NULL,
4349 sizeof(struct msmsdcc_nc_dmadata),
4350 host->dma.nc, host->dma.nc_busaddr);
4351 }
4352 ioremap_free:
4353 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004354 host_free:
4355 mmc_free_host(mmc);
4356 out:
4357 return ret;
4358}
4359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004361{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4363 struct mmc_platform_data *plat;
4364 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366 if (!mmc)
4367 return -ENXIO;
4368
4369 if (pm_runtime_suspended(&(pdev)->dev))
4370 pm_runtime_resume(&(pdev)->dev);
4371
4372 host = mmc_priv(mmc);
4373
4374 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4375 plat = host->plat;
4376
4377 if (!plat->status_irq)
4378 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4379
4380 del_timer_sync(&host->req_tout_timer);
4381 tasklet_kill(&host->dma_tlet);
4382 tasklet_kill(&host->sps.tlet);
4383 mmc_remove_host(mmc);
4384
4385 if (plat->status_irq)
4386 free_irq(plat->status_irq, host);
4387
4388 wake_lock_destroy(&host->sdio_suspend_wlock);
4389 if (plat->sdiowakeup_irq) {
4390 wake_lock_destroy(&host->sdio_wlock);
4391 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4392 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004393 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004394
4395 free_irq(host->core_irqres->start, host);
4396 free_irq(host->core_irqres->start, host);
4397
4398 clk_put(host->clk);
4399 if (!IS_ERR(host->pclk))
4400 clk_put(host->pclk);
4401 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4402 clk_put(host->dfab_pclk);
4403
4404 msmsdcc_vreg_init(host, false);
4405
4406 if (host->is_dma_mode) {
4407 if (host->dmares)
4408 dma_free_coherent(NULL,
4409 sizeof(struct msmsdcc_nc_dmadata),
4410 host->dma.nc, host->dma.nc_busaddr);
4411 }
4412
4413 if (host->is_sps_mode) {
4414 msmsdcc_dml_exit(host);
4415 msmsdcc_sps_exit(host);
4416 }
4417
4418 iounmap(host->base);
4419 mmc_free_host(mmc);
4420
4421#ifdef CONFIG_HAS_EARLYSUSPEND
4422 unregister_early_suspend(&host->early_suspend);
4423#endif
4424 pm_runtime_disable(&(pdev)->dev);
4425 pm_runtime_set_suspended(&(pdev)->dev);
4426
4427 return 0;
4428}
4429
4430#ifdef CONFIG_MSM_SDIO_AL
4431int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4432{
4433 struct msmsdcc_host *host = mmc_priv(mmc);
4434 unsigned long flags;
4435
4436 spin_lock_irqsave(&host->lock, flags);
4437 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4438 enable ? "En" : "Dis");
4439
4440 if (enable) {
4441 if (!host->sdcc_irq_disabled) {
4442 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304443 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004444 host->sdcc_irq_disabled = 1;
4445 }
4446
4447 if (host->clks_on) {
4448 msmsdcc_setup_clocks(host, false);
4449 host->clks_on = 0;
4450 }
4451
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304452 if (host->plat->sdio_lpm_gpio_setup &&
4453 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004454 spin_unlock_irqrestore(&host->lock, flags);
4455 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4456 spin_lock_irqsave(&host->lock, flags);
4457 host->sdio_gpio_lpm = 1;
4458 }
4459
4460 if (host->sdio_irq_disabled) {
4461 msmsdcc_enable_irq_wake(host);
4462 enable_irq(host->plat->sdiowakeup_irq);
4463 host->sdio_irq_disabled = 0;
4464 }
4465 } else {
4466 if (!host->sdio_irq_disabled) {
4467 disable_irq_nosync(host->plat->sdiowakeup_irq);
4468 host->sdio_irq_disabled = 1;
4469 msmsdcc_disable_irq_wake(host);
4470 }
4471
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304472 if (host->plat->sdio_lpm_gpio_setup &&
4473 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004474 spin_unlock_irqrestore(&host->lock, flags);
4475 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4476 spin_lock_irqsave(&host->lock, flags);
4477 host->sdio_gpio_lpm = 0;
4478 }
4479
4480 if (!host->clks_on) {
4481 msmsdcc_setup_clocks(host, true);
4482 host->clks_on = 1;
4483 }
4484
4485 if (host->sdcc_irq_disabled) {
4486 writel_relaxed(host->mci_irqenable,
4487 host->base + MMCIMASK0);
4488 mb();
4489 enable_irq(host->core_irqres->start);
4490 host->sdcc_irq_disabled = 0;
4491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492 }
4493 spin_unlock_irqrestore(&host->lock, flags);
4494 return 0;
4495}
4496#else
4497int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4498{
4499 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004500}
4501#endif
4502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004504static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004506{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004507 struct mmc_host *mmc = dev_get_drvdata(dev);
4508 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004509 int rc = 0;
4510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004511 if (host->plat->is_sdio_al_client)
4512 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304513 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004514 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004515 host->sdcc_suspending = 1;
4516 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004518 /*
4519 * If the clocks are already turned off by SDIO clients (as
4520 * part of LPM), then clocks should be turned on before
4521 * calling mmc_suspend_host() because mmc_suspend_host might
4522 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304523 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 * cards, clocks will be turned on before mmc_suspend_host
4525 * and turned off after mmc_suspend_host.
4526 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304527 if (mmc->card && mmc_card_sdio(mmc->card)) {
4528 mmc->ios.clock = host->clk_rate;
4529 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4530 }
San Mehat9d2bd732009-09-22 16:44:22 -07004531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004532 /*
4533 * MMC core thinks that host is disabled by now since
4534 * runtime suspend is scheduled after msmsdcc_disable()
4535 * is called. Thus, MMC core will try to enable the host
4536 * while suspending it. This results in a synchronous
4537 * runtime resume request while in runtime suspending
4538 * context and hence inorder to complete this resume
4539 * requet, it will wait for suspend to be complete,
4540 * but runtime suspend also can not proceed further
4541 * until the host is resumed. Thus, it leads to a hang.
4542 * Hence, increase the pm usage count before suspending
4543 * the host so that any resume requests after this will
4544 * simple become pm usage counter increment operations.
4545 */
4546 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304547 /* If there is pending detect work abort runtime suspend */
4548 if (unlikely(work_busy(&mmc->detect.work)))
4549 rc = -EAGAIN;
4550 else
4551 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 pm_runtime_put_noidle(dev);
4553
4554 if (!rc) {
4555 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4556 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4557 disable_irq(host->core_irqres->start);
4558 host->sdcc_irq_disabled = 1;
4559
4560 /*
4561 * If MMC core level suspend is not supported,
4562 * turn off clocks to allow deep sleep (TCXO
4563 * shutdown).
4564 */
4565 mmc->ios.clock = 0;
4566 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4567 enable_irq(host->core_irqres->start);
4568 host->sdcc_irq_disabled = 0;
4569
4570 if (host->plat->sdiowakeup_irq) {
4571 host->sdio_irq_disabled = 0;
4572 msmsdcc_enable_irq_wake(host);
4573 enable_irq(host->plat->sdiowakeup_irq);
4574 }
4575 }
4576 }
4577 host->sdcc_suspending = 0;
4578 mmc->suspend_task = NULL;
4579 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4580 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004581 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304582 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004583 return rc;
4584}
4585
4586static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004587msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004588{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 struct mmc_host *mmc = dev_get_drvdata(dev);
4590 struct msmsdcc_host *host = mmc_priv(mmc);
4591 unsigned long flags;
4592
4593 if (host->plat->is_sdio_al_client)
4594 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004595
Sahitya Tummala7661a452011-07-18 13:28:35 +05304596 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004597 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004598 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4599 if (host->sdcc_irq_disabled) {
4600 enable_irq(host->core_irqres->start);
4601 host->sdcc_irq_disabled = 0;
4602 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304603 mmc->ios.clock = host->clk_rate;
4604 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004605
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304606 spin_lock_irqsave(&host->lock, flags);
4607 writel_relaxed(host->mci_irqenable,
4608 host->base + MMCIMASK0);
4609 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004610
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304611 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4612 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 if (host->plat->sdiowakeup_irq) {
4614 disable_irq_nosync(
4615 host->plat->sdiowakeup_irq);
4616 msmsdcc_disable_irq_wake(host);
4617 host->sdio_irq_disabled = 1;
4618 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304619 }
San Mehat9d2bd732009-09-22 16:44:22 -07004620
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304621 spin_unlock_irqrestore(&host->lock, flags);
4622 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004623
4624 mmc_resume_host(mmc);
4625
4626 /*
4627 * FIXME: Clearing of flags must be handled in clients
4628 * resume handler.
4629 */
4630 spin_lock_irqsave(&host->lock, flags);
4631 mmc->pm_flags = 0;
4632 spin_unlock_irqrestore(&host->lock, flags);
4633
4634 /*
4635 * After resuming the host wait for sometime so that
4636 * the SDIO work will be processed.
4637 */
4638 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4639 if ((host->plat->cfg_mpm_sdiowakeup ||
4640 host->plat->sdiowakeup_irq) &&
4641 wake_lock_active(&host->sdio_wlock))
4642 wake_lock_timeout(&host->sdio_wlock, 1);
4643 }
4644
4645 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004646 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304647 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004648 return 0;
4649}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004650
4651static int msmsdcc_runtime_idle(struct device *dev)
4652{
4653 struct mmc_host *mmc = dev_get_drvdata(dev);
4654 struct msmsdcc_host *host = mmc_priv(mmc);
4655
4656 if (host->plat->is_sdio_al_client)
4657 return 0;
4658
4659 /* Idle timeout is not configurable for now */
4660 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4661
4662 return -EAGAIN;
4663}
4664
4665static int msmsdcc_pm_suspend(struct device *dev)
4666{
4667 struct mmc_host *mmc = dev_get_drvdata(dev);
4668 struct msmsdcc_host *host = mmc_priv(mmc);
4669 int rc = 0;
4670
4671 if (host->plat->is_sdio_al_client)
4672 return 0;
4673
4674
4675 if (host->plat->status_irq)
4676 disable_irq(host->plat->status_irq);
4677
4678 if (!pm_runtime_suspended(dev))
4679 rc = msmsdcc_runtime_suspend(dev);
4680
4681 return rc;
4682}
4683
4684static int msmsdcc_pm_resume(struct device *dev)
4685{
4686 struct mmc_host *mmc = dev_get_drvdata(dev);
4687 struct msmsdcc_host *host = mmc_priv(mmc);
4688 int rc = 0;
4689
4690 if (host->plat->is_sdio_al_client)
4691 return 0;
4692
Sahitya Tummalafb486372011-09-02 19:01:49 +05304693 if (!pm_runtime_suspended(dev))
4694 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695 if (host->plat->status_irq) {
4696 msmsdcc_check_status((unsigned long)host);
4697 enable_irq(host->plat->status_irq);
4698 }
4699
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004700 return rc;
4701}
4702
Daniel Walker08ecfde2010-06-23 12:32:20 -07004703#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004704#define msmsdcc_runtime_suspend NULL
4705#define msmsdcc_runtime_resume NULL
4706#define msmsdcc_runtime_idle NULL
4707#define msmsdcc_pm_suspend NULL
4708#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004709#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004711static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4712 .runtime_suspend = msmsdcc_runtime_suspend,
4713 .runtime_resume = msmsdcc_runtime_resume,
4714 .runtime_idle = msmsdcc_runtime_idle,
4715 .suspend = msmsdcc_pm_suspend,
4716 .resume = msmsdcc_pm_resume,
4717};
4718
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304719static const struct of_device_id msmsdcc_dt_match[] = {
4720 {.compatible = "qcom,msm-sdcc"},
4721
4722};
4723MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4724
San Mehat9d2bd732009-09-22 16:44:22 -07004725static struct platform_driver msmsdcc_driver = {
4726 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004727 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004728 .driver = {
4729 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004730 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304731 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004732 },
4733};
4734
4735static int __init msmsdcc_init(void)
4736{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737#if defined(CONFIG_DEBUG_FS)
4738 int ret = 0;
4739 ret = msmsdcc_dbg_init();
4740 if (ret) {
4741 pr_err("Failed to create debug fs dir \n");
4742 return ret;
4743 }
4744#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004745 return platform_driver_register(&msmsdcc_driver);
4746}
4747
4748static void __exit msmsdcc_exit(void)
4749{
4750 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751
4752#if defined(CONFIG_DEBUG_FS)
4753 debugfs_remove(debugfs_file);
4754 debugfs_remove(debugfs_dir);
4755#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004756}
4757
4758module_init(msmsdcc_init);
4759module_exit(msmsdcc_exit);
4760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004761MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004762MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004763
4764#if defined(CONFIG_DEBUG_FS)
4765
4766static int
4767msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4768{
4769 file->private_data = inode->i_private;
4770 return 0;
4771}
4772
4773static ssize_t
4774msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4775 size_t count, loff_t *ppos)
4776{
4777 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004778 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004779 int max, i;
4780
4781 i = 0;
4782 max = sizeof(buf) - 1;
4783
4784 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4785 host->curr.cmd, host->curr.data);
4786 if (host->curr.cmd) {
4787 struct mmc_command *cmd = host->curr.cmd;
4788
4789 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4790 cmd->opcode, cmd->arg, cmd->flags);
4791 }
4792 if (host->curr.data) {
4793 struct mmc_data *data = host->curr.data;
4794 i += scnprintf(buf + i, max - i,
4795 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4796 data->timeout_ns, data->timeout_clks,
4797 data->blksz, data->blocks, data->error,
4798 data->flags);
4799 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4800 host->curr.xfer_size, host->curr.xfer_remain,
4801 host->curr.data_xfered, host->dma.sg);
4802 }
4803
4804 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4805}
4806
4807static const struct file_operations msmsdcc_dbg_state_ops = {
4808 .read = msmsdcc_dbg_state_read,
4809 .open = msmsdcc_dbg_state_open,
4810};
4811
4812static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4813{
4814 if (debugfs_dir) {
4815 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4816 0644, debugfs_dir, host,
4817 &msmsdcc_dbg_state_ops);
4818 }
4819}
4820
4821static int __init msmsdcc_dbg_init(void)
4822{
4823 int err;
4824
4825 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4826 if (IS_ERR(debugfs_dir)) {
4827 err = PTR_ERR(debugfs_dir);
4828 debugfs_dir = NULL;
4829 return err;
4830 }
4831
4832 return 0;
4833}
4834#endif