blob: cdfe10ee1bde49ad441cc38de672b32a9feba3d9 [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);
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301268 /* len might have aligned to 32bits above */
1269 if (len > remain)
1270 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001271
1272 /* Unmap the buffer */
1273 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1274 local_irq_restore(flags);
1275
1276 host->pio.sg_off += len;
1277 host->curr.xfer_remain -= len;
1278 host->curr.data_xfered += len;
1279 remain -= len;
1280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 if (remain) /* Done with this page? */
1282 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 if (status & MCI_RXACTIVE && host->curr.user_pages)
1285 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 if (!--host->pio.sg_len) {
1288 memset(&host->pio, 0, sizeof(host->pio));
1289 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001290 }
1291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 /* Advance to next sg */
1293 host->pio.sg++;
1294 host->pio.sg_off = 0;
1295
1296 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001297 } while (1);
1298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1300 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1301 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1302 host->base + MMCIMASK0);
1303 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301304 /*
1305 * back to back write to MASK0 register don't need
1306 * synchronization delay.
1307 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1309 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1310 }
1311 mb();
1312 } else if (!host->curr.xfer_remain) {
1313 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1314 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1315 mb();
1316 }
San Mehat9d2bd732009-09-22 16:44:22 -07001317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001319
1320 return IRQ_HANDLED;
1321}
1322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323static void
1324msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1325
1326static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1327 struct mmc_data *data)
1328{
1329 u32 loop_cnt = 0;
1330
1331 /*
1332 * For read commands with data less than fifo size, it is possible to
1333 * get DATAEND first and RXDATA_AVAIL might be set later because of
1334 * synchronization delay through the asynchronous RX FIFO. Thus, for
1335 * such cases, even after DATAEND interrupt is received software
1336 * should poll for RXDATA_AVAIL until the requested data is read out
1337 * of FIFO. This change is needed to get around this abnormal but
1338 * sometimes expected behavior of SDCC3 controller.
1339 *
1340 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1341 * after the data is loaded into RX FIFO. This would amount to less
1342 * than a microsecond and thus looping for 1000 times is good enough
1343 * for that delay.
1344 */
1345 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1346 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1347 spin_unlock(&host->lock);
1348 msmsdcc_pio_irq(1, host);
1349 spin_lock(&host->lock);
1350 }
1351 }
1352 if (loop_cnt == 1000) {
1353 pr_info("%s: Timed out while polling for Rx Data\n",
1354 mmc_hostname(host->mmc));
1355 data->error = -ETIMEDOUT;
1356 msmsdcc_reset_and_restore(host);
1357 }
1358}
1359
San Mehat9d2bd732009-09-22 16:44:22 -07001360static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1361{
1362 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001363
1364 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1366 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1367 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1368 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301371 pr_debug("%s: CMD%d: Command timeout\n",
1372 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001373 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1375 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301376 pr_err("%s: CMD%d: Command CRC error\n",
1377 mmc_hostname(host->mmc), cmd->opcode);
1378 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001379 cmd->error = -EILSEQ;
1380 }
1381
1382 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001383 if (host->curr.data && host->dma.sg &&
1384 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001385 msm_dmov_stop_cmd(host->dma.channel,
1386 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 else if (host->curr.data && host->sps.sg &&
1388 host->is_sps_mode){
1389 /* Stop current SPS transfer */
1390 msmsdcc_sps_exit_curr_xfer(host);
1391 }
San Mehat9d2bd732009-09-22 16:44:22 -07001392 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301393 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001394 msmsdcc_stop_data(host);
1395 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301396 } else { /* host->data == NULL */
1397 if (!cmd->error && host->prog_enable) {
1398 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301400 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301402 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301403 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301404 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001405 if (host->dummy_52_needed)
1406 host->dummy_52_needed = 0;
1407 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301409 msmsdcc_request_end(host, cmd->mrq);
1410 }
1411 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301412 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1413 if (cmd->data->flags & MMC_DATA_READ)
1414 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1415 else
1416 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301417 } else if (cmd->data) {
1418 if (!(cmd->data->flags & MMC_DATA_READ))
1419 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001420 }
1421}
1422
San Mehat9d2bd732009-09-22 16:44:22 -07001423static irqreturn_t
1424msmsdcc_irq(int irq, void *dev_id)
1425{
1426 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001427 u32 status;
1428 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001430
1431 spin_lock(&host->lock);
1432
1433 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 struct mmc_command *cmd;
1435 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 if (timer) {
1438 timer = 0;
1439 msmsdcc_delay(host);
1440 }
San Mehat865c8062009-11-13 13:42:06 -08001441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 if (!host->clks_on) {
1443 pr_debug("%s: %s: SDIO async irq received\n",
1444 mmc_hostname(host->mmc), __func__);
1445 host->mmc->ios.clock = host->clk_rate;
1446 spin_unlock(&host->lock);
1447 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1448 spin_lock(&host->lock);
1449 if (host->plat->cfg_mpm_sdiowakeup &&
1450 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1451 wake_lock(&host->sdio_wlock);
1452 /* only ansyc interrupt can come when clocks are off */
1453 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301454 if (host->clk_rate <=
1455 msmsdcc_get_min_sup_clk_rate(host))
1456 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 }
1458
1459 status = readl_relaxed(host->base + MMCISTATUS);
1460
1461 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1462 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001463 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465#if IRQ_DEBUG
1466 msmsdcc_print_status(host, "irq0-r", status);
1467#endif
1468 status &= readl_relaxed(host->base + MMCIMASK0);
1469 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301470 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301471 if (host->clk_rate <=
1472 msmsdcc_get_min_sup_clk_rate(host))
1473 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474#if IRQ_DEBUG
1475 msmsdcc_print_status(host, "irq0-p", status);
1476#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1479 if (status & MCI_SDIOINTROPE) {
1480 if (host->sdcc_suspending)
1481 wake_lock(&host->sdio_suspend_wlock);
1482 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001483 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001485 data = host->curr.data;
1486
1487 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1489 MCI_CMDTIMEOUT)) {
1490 if (status & MCI_CMDTIMEOUT)
1491 pr_debug("%s: dummy CMD52 timeout\n",
1492 mmc_hostname(host->mmc));
1493 if (status & MCI_CMDCRCFAIL)
1494 pr_debug("%s: dummy CMD52 CRC failed\n",
1495 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001496 host->dummy_52_sent = 0;
1497 host->dummy_52_needed = 0;
1498 if (data) {
1499 msmsdcc_stop_data(host);
1500 msmsdcc_request_end(host, data->mrq);
1501 }
1502 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 spin_unlock(&host->lock);
1504 return IRQ_HANDLED;
1505 }
1506 break;
1507 }
1508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 /*
1510 * Check for proper command response
1511 */
1512 cmd = host->curr.cmd;
1513 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1514 MCI_CMDTIMEOUT | MCI_PROGDONE |
1515 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1516 msmsdcc_do_cmdirq(host, status);
1517 }
1518
Sathish Ambley081d7842011-11-29 11:19:41 -08001519 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 /* Check for data errors */
1521 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1522 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1523 msmsdcc_data_err(host, data, status);
1524 host->curr.data_xfered = 0;
1525 if (host->dma.sg && host->is_dma_mode)
1526 msm_dmov_stop_cmd(host->dma.channel,
1527 &host->dma.hdr, 0);
1528 else if (host->sps.sg && host->is_sps_mode) {
1529 /* Stop current SPS transfer */
1530 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301531 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 msmsdcc_reset_and_restore(host);
1533 if (host->curr.data)
1534 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301535 if (!data->stop || (host->curr.mrq->sbc
1536 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 timer |=
1538 msmsdcc_request_end(host,
1539 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301540 else if ((host->curr.mrq->sbc
1541 && data->error) ||
1542 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 msmsdcc_start_command(host,
1544 data->stop,
1545 0);
1546 timer = 1;
1547 }
1548 }
1549 }
1550
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301551 /* Check for prog done */
1552 if (host->curr.wait_for_auto_prog_done &&
1553 (status & MCI_PROGDONE))
1554 host->curr.got_auto_prog_done = 1;
1555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 /* Check for data done */
1557 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1558 host->curr.got_dataend = 1;
1559
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301560 if (host->curr.got_dataend &&
1561 (!host->curr.wait_for_auto_prog_done ||
1562 (host->curr.wait_for_auto_prog_done &&
1563 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 /*
1565 * If DMA is still in progress, we complete
1566 * via the completion handler
1567 */
1568 if (!host->dma.busy && !host->sps.busy) {
1569 /*
1570 * There appears to be an issue in the
1571 * controller where if you request a
1572 * small block transfer (< fifo size),
1573 * you may get your DATAEND/DATABLKEND
1574 * irq without the PIO data irq.
1575 *
1576 * Check to see if theres still data
1577 * to be read, and simulate a PIO irq.
1578 */
1579 if (data->flags & MMC_DATA_READ)
1580 msmsdcc_wait_for_rxdata(host,
1581 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 if (!data->error) {
1583 host->curr.data_xfered =
1584 host->curr.xfer_size;
1585 host->curr.xfer_remain -=
1586 host->curr.xfer_size;
1587 }
1588
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001589 if (!host->dummy_52_needed) {
1590 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301591 if (!data->stop ||
1592 (host->curr.mrq->sbc
1593 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001594 msmsdcc_request_end(
1595 host,
1596 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301597 else if ((host->curr.mrq->sbc
1598 && data->error) ||
1599 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001600 msmsdcc_start_command(
1601 host,
1602 data->stop, 0);
1603 timer = 1;
1604 }
1605 } else {
1606 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001608 &dummy52cmd,
1609 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 }
1611 }
1612 }
1613 }
1614
San Mehat9d2bd732009-09-22 16:44:22 -07001615 ret = 1;
1616 } while (status);
1617
1618 spin_unlock(&host->lock);
1619
San Mehat9d2bd732009-09-22 16:44:22 -07001620 return IRQ_RETVAL(ret);
1621}
1622
1623static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1625{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301626 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301628 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301629 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1630 else
1631 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 } else {
1633 msmsdcc_start_command(host, mrq->cmd, 0);
1634 }
1635}
1636
1637static void
San Mehat9d2bd732009-09-22 16:44:22 -07001638msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1639{
1640 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 /*
1644 * Get the SDIO AL client out of LPM.
1645 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001646 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647 if (host->plat->is_sdio_al_client)
1648 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001649
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301650 /* check if sps pipe reset is pending? */
1651 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1652 msmsdcc_sps_pipes_reset_and_restore(host);
1653 host->sps.pipe_reset_pending = false;
1654 }
1655
San Mehat9d2bd732009-09-22 16:44:22 -07001656 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 WARN(host->curr.mrq, "Request in progress\n");
1658 WARN(!host->pwr, "SDCC power is turned off\n");
1659 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1660 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001661
1662 if (host->eject) {
1663 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1664 mrq->cmd->error = 0;
1665 mrq->data->bytes_xfered = mrq->data->blksz *
1666 mrq->data->blocks;
1667 } else
1668 mrq->cmd->error = -ENOMEDIUM;
1669
1670 spin_unlock_irqrestore(&host->lock, flags);
1671 mmc_request_done(mmc, mrq);
1672 return;
1673 }
1674
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301675 /*
1676 * Kick the software command timeout timer here.
1677 * Timer expires in 10 secs.
1678 */
1679 mod_timer(&host->req_tout_timer,
1680 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001681
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301682 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301683 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301684 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1685 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301686 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301688 else
1689 /*
1690 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1691 * write operations using CMD53 and CMD54.
1692 * Setting this bit with CMD53 would
1693 * automatically triggers PROG_DONE interrupt
1694 * without the need of sending dummy CMD52.
1695 */
1696 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301697 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1698 host->sdcc_version) {
1699 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 }
San Mehat9d2bd732009-09-22 16:44:22 -07001701 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301702
Pratibhasagar V00b94332011-10-18 14:57:27 +05301703 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301704 mrq->sbc->mrq = mrq;
1705 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301706 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301707 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301708 msmsdcc_start_command(host, mrq->sbc, 0);
1709 } else {
1710 msmsdcc_request_start(host, mrq);
1711 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301712 } else {
1713 msmsdcc_request_start(host, mrq);
1714 }
1715
San Mehat9d2bd732009-09-22 16:44:22 -07001716 spin_unlock_irqrestore(&host->lock, flags);
1717}
1718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1720 int min_uV, int max_uV)
1721{
1722 int rc = 0;
1723
1724 if (vreg->set_voltage_sup) {
1725 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1726 if (rc) {
1727 pr_err("%s: regulator_set_voltage(%s) failed."
1728 " min_uV=%d, max_uV=%d, rc=%d\n",
1729 __func__, vreg->name, min_uV, max_uV, rc);
1730 }
1731 }
1732
1733 return rc;
1734}
1735
1736static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1737 int uA_load)
1738{
1739 int rc = 0;
1740
Krishna Kondafea60182011-11-01 16:01:34 -07001741 /* regulators that do not support regulator_set_voltage also
1742 do not support regulator_set_optimum_mode */
1743 if (vreg->set_voltage_sup) {
1744 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1745 if (rc < 0)
1746 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1747 "uA_load=%d) failed. rc=%d\n", __func__,
1748 vreg->name, uA_load, rc);
1749 else
1750 /* regulator_set_optimum_mode() can return non zero
1751 * value even for success case.
1752 */
1753 rc = 0;
1754 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755
1756 return rc;
1757}
1758
1759static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1760 struct device *dev)
1761{
1762 int rc = 0;
1763
1764 /* check if regulator is already initialized? */
1765 if (vreg->reg)
1766 goto out;
1767
1768 /* Get the regulator handle */
1769 vreg->reg = regulator_get(dev, vreg->name);
1770 if (IS_ERR(vreg->reg)) {
1771 rc = PTR_ERR(vreg->reg);
1772 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1773 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001774 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001776
1777 if (regulator_count_voltages(vreg->reg) > 0)
1778 vreg->set_voltage_sup = 1;
1779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780out:
1781 return rc;
1782}
1783
1784static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1785{
1786 if (vreg->reg)
1787 regulator_put(vreg->reg);
1788}
1789
1790/* This init function should be called only once for each SDCC slot */
1791static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1792{
1793 int rc = 0;
1794 struct msm_mmc_slot_reg_data *curr_slot;
1795 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1796 struct device *dev = mmc_dev(host->mmc);
1797
1798 curr_slot = host->plat->vreg_data;
1799 if (!curr_slot)
1800 goto out;
1801
1802 curr_vdd_reg = curr_slot->vdd_data;
1803 curr_vccq_reg = curr_slot->vccq_data;
1804 curr_vddp_reg = curr_slot->vddp_data;
1805
1806 if (is_init) {
1807 /*
1808 * Get the regulator handle from voltage regulator framework
1809 * and then try to set the voltage level for the regulator
1810 */
1811 if (curr_vdd_reg) {
1812 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1813 if (rc)
1814 goto out;
1815 }
1816 if (curr_vccq_reg) {
1817 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1818 if (rc)
1819 goto vdd_reg_deinit;
1820 }
1821 if (curr_vddp_reg) {
1822 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1823 if (rc)
1824 goto vccq_reg_deinit;
1825 }
1826 goto out;
1827 } else {
1828 /* Deregister all regulators from regulator framework */
1829 goto vddp_reg_deinit;
1830 }
1831vddp_reg_deinit:
1832 if (curr_vddp_reg)
1833 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1834vccq_reg_deinit:
1835 if (curr_vccq_reg)
1836 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1837vdd_reg_deinit:
1838 if (curr_vdd_reg)
1839 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1840out:
1841 return rc;
1842}
1843
1844static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1845{
1846 int rc = 0;
1847
Subhash Jadavanicc922692011-08-01 23:05:01 +05301848 /* Put regulator in HPM (high power mode) */
1849 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1850 if (rc < 0)
1851 goto out;
1852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 if (!vreg->is_enabled) {
1854 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301855 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1856 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 if (rc)
1858 goto out;
1859
1860 rc = regulator_enable(vreg->reg);
1861 if (rc) {
1862 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1863 __func__, vreg->name, rc);
1864 goto out;
1865 }
1866 vreg->is_enabled = true;
1867 }
1868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869out:
1870 return rc;
1871}
1872
1873static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1874{
1875 int rc = 0;
1876
1877 /* Never disable regulator marked as always_on */
1878 if (vreg->is_enabled && !vreg->always_on) {
1879 rc = regulator_disable(vreg->reg);
1880 if (rc) {
1881 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1882 __func__, vreg->name, rc);
1883 goto out;
1884 }
1885 vreg->is_enabled = false;
1886
1887 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1888 if (rc < 0)
1889 goto out;
1890
1891 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301892 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893 if (rc)
1894 goto out;
1895 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1896 /* Put always_on regulator in LPM (low power mode) */
1897 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1898 if (rc < 0)
1899 goto out;
1900 }
1901out:
1902 return rc;
1903}
1904
1905static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1906{
1907 int rc = 0, i;
1908 struct msm_mmc_slot_reg_data *curr_slot;
1909 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1910 struct msm_mmc_reg_data *vreg_table[3];
1911
1912 curr_slot = host->plat->vreg_data;
1913 if (!curr_slot)
1914 goto out;
1915
1916 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1917 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1918 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1919
1920 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1921 if (vreg_table[i]) {
1922 if (enable)
1923 rc = msmsdcc_vreg_enable(vreg_table[i]);
1924 else
1925 rc = msmsdcc_vreg_disable(vreg_table[i]);
1926 if (rc)
1927 goto out;
1928 }
1929 }
1930out:
1931 return rc;
1932}
1933
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301934static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935{
1936 int rc = 0;
1937
1938 if (host->plat->vreg_data) {
1939 struct msm_mmc_reg_data *vddp_reg =
1940 host->plat->vreg_data->vddp_data;
1941
1942 if (vddp_reg && vddp_reg->is_enabled)
1943 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1944 }
1945
1946 return rc;
1947}
1948
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301949static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1950{
1951 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1952 int rc = 0;
1953
1954 if (curr_slot && curr_slot->vddp_data) {
1955 rc = msmsdcc_set_vddp_level(host,
1956 curr_slot->vddp_data->low_vol_level);
1957
1958 if (rc)
1959 pr_err("%s: %s: failed to change vddp level to %d",
1960 mmc_hostname(host->mmc), __func__,
1961 curr_slot->vddp_data->low_vol_level);
1962 }
1963
1964 return rc;
1965}
1966
1967static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1968{
1969 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1970 int rc = 0;
1971
1972 if (curr_slot && curr_slot->vddp_data) {
1973 rc = msmsdcc_set_vddp_level(host,
1974 curr_slot->vddp_data->high_vol_level);
1975
1976 if (rc)
1977 pr_err("%s: %s: failed to change vddp level to %d",
1978 mmc_hostname(host->mmc), __func__,
1979 curr_slot->vddp_data->high_vol_level);
1980 }
1981
1982 return rc;
1983}
1984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1986{
1987 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1988 return 1;
1989 return 0;
1990}
1991
1992static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1993{
1994 if (enable) {
1995 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1996 clk_enable(host->dfab_pclk);
1997 if (!IS_ERR(host->pclk))
1998 clk_enable(host->pclk);
1999 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302000 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302002 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003 clk_disable(host->clk);
2004 if (!IS_ERR(host->pclk))
2005 clk_disable(host->pclk);
2006 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2007 clk_disable(host->dfab_pclk);
2008 }
2009}
2010
2011static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2012 unsigned int req_clk)
2013{
2014 unsigned int sel_clk = -1;
2015
2016 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2017 unsigned char cnt;
2018
2019 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2020 if (host->plat->sup_clk_table[cnt] > req_clk)
2021 break;
2022 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2023 sel_clk = host->plat->sup_clk_table[cnt];
2024 break;
2025 } else
2026 sel_clk = host->plat->sup_clk_table[cnt];
2027 }
2028 } else {
2029 if ((req_clk < host->plat->msmsdcc_fmax) &&
2030 (req_clk > host->plat->msmsdcc_fmid))
2031 sel_clk = host->plat->msmsdcc_fmid;
2032 else
2033 sel_clk = req_clk;
2034 }
2035
2036 return sel_clk;
2037}
2038
2039static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2040 struct msmsdcc_host *host)
2041{
2042 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2043 return host->plat->sup_clk_table[0];
2044 else
2045 return host->plat->msmsdcc_fmin;
2046}
2047
2048static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2049 struct msmsdcc_host *host)
2050{
2051 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2052 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2053 else
2054 return host->plat->msmsdcc_fmax;
2055}
2056
2057static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302058{
2059 struct msm_mmc_gpio_data *curr;
2060 int i, rc = 0;
2061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302063 for (i = 0; i < curr->size; i++) {
2064 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 if (curr->gpio[i].is_always_on &&
2066 curr->gpio[i].is_enabled)
2067 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302068 rc = gpio_request(curr->gpio[i].no,
2069 curr->gpio[i].name);
2070 if (rc) {
2071 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2072 mmc_hostname(host->mmc),
2073 curr->gpio[i].no,
2074 curr->gpio[i].name, rc);
2075 goto free_gpios;
2076 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302078 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 if (curr->gpio[i].is_always_on)
2080 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302081 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302083 }
2084 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302086
2087free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302089 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090 curr->gpio[i].is_enabled = false;
2091 }
2092out:
2093 return rc;
2094}
2095
2096static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2097{
2098 struct msm_mmc_pad_data *curr;
2099 int i;
2100
2101 curr = host->plat->pin_data->pad_data;
2102 for (i = 0; i < curr->drv->size; i++) {
2103 if (enable)
2104 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2105 curr->drv->on[i].val);
2106 else
2107 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2108 curr->drv->off[i].val);
2109 }
2110
2111 for (i = 0; i < curr->pull->size; i++) {
2112 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002113 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002114 curr->pull->on[i].val);
2115 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002116 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117 curr->pull->off[i].val);
2118 }
2119
2120 return 0;
2121}
2122
2123static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2124{
2125 int rc = 0;
2126
2127 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2128 return 0;
2129
2130 if (host->plat->pin_data->is_gpio)
2131 rc = msmsdcc_setup_gpio(host, enable);
2132 else
2133 rc = msmsdcc_setup_pad(host, enable);
2134
2135 if (!rc)
2136 host->plat->pin_data->cfg_sts = enable;
2137
2138 return rc;
2139}
2140
2141static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2142{
2143 unsigned int wakeup_irq;
2144
2145 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2146 host->plat->sdiowakeup_irq :
2147 host->core_irqres->start;
2148
2149 if (!host->irq_wake_enabled) {
2150 enable_irq_wake(wakeup_irq);
2151 host->irq_wake_enabled = true;
2152 }
2153}
2154
2155static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2156{
2157 unsigned int wakeup_irq;
2158
2159 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2160 host->plat->sdiowakeup_irq :
2161 host->core_irqres->start;
2162
2163 if (host->irq_wake_enabled) {
2164 disable_irq_wake(wakeup_irq);
2165 host->irq_wake_enabled = false;
2166 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302167}
2168
San Mehat9d2bd732009-09-22 16:44:22 -07002169static void
2170msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2171{
2172 struct msmsdcc_host *host = mmc_priv(mmc);
2173 u32 clk = 0, pwr = 0;
2174 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002175 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302179
San Mehat9d2bd732009-09-22 16:44:22 -07002180 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181 spin_lock_irqsave(&host->lock, flags);
2182 if (!host->clks_on) {
2183 msmsdcc_setup_clocks(host, true);
2184 host->clks_on = 1;
2185 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2186 if (!host->plat->sdiowakeup_irq) {
2187 writel_relaxed(host->mci_irqenable,
2188 host->base + MMCIMASK0);
2189 mb();
2190 if (host->plat->cfg_mpm_sdiowakeup &&
2191 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2192 host->plat->cfg_mpm_sdiowakeup(
2193 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2194 msmsdcc_disable_irq_wake(host);
2195 } else if (!(mmc->pm_flags &
2196 MMC_PM_WAKE_SDIO_IRQ)) {
2197 writel_relaxed(host->mci_irqenable,
2198 host->base + MMCIMASK0);
2199 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302200 } else {
2201 writel_relaxed(host->mci_irqenable,
2202 host->base + MMCIMASK0);
2203 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 }
San Mehat9d2bd732009-09-22 16:44:22 -07002205 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 spin_unlock_irqrestore(&host->lock, flags);
2207
2208 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2209 /*
2210 * For DDR50 mode, controller needs clock rate to be
2211 * double than what is required on the SD card CLK pin.
2212 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302213 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002214 /*
2215 * Make sure that we don't double the clock if
2216 * doubled clock rate is already set
2217 */
2218 if (!host->ddr_doubled_clk_rate ||
2219 (host->ddr_doubled_clk_rate &&
2220 (host->ddr_doubled_clk_rate != ios->clock))) {
2221 host->ddr_doubled_clk_rate =
2222 msmsdcc_get_sup_clk_rate(
2223 host, (ios->clock * 2));
2224 clock = host->ddr_doubled_clk_rate;
2225 }
2226 } else {
2227 host->ddr_doubled_clk_rate = 0;
2228 }
2229
2230 if (clock != host->clk_rate) {
2231 rc = clk_set_rate(host->clk, clock);
2232 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302233 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234 mmc_hostname(mmc), clock);
2235 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302236 host->reg_write_delay =
2237 (1 + ((3 * USEC_PER_SEC) /
2238 (host->clk_rate ? host->clk_rate :
2239 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240 }
2241 /*
2242 * give atleast 2 MCLK cycles delay for clocks
2243 * and SDCC core to stabilize
2244 */
2245 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002246 clk |= MCI_CLK_ENABLE;
2247 }
2248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 if (ios->bus_width == MMC_BUS_WIDTH_8)
2250 clk |= MCI_CLK_WIDEBUS_8;
2251 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2252 clk |= MCI_CLK_WIDEBUS_4;
2253 else
2254 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 if (msmsdcc_is_pwrsave(host))
2257 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 host->tuning_needed = 0;
2262 /*
2263 * Select the controller timing mode according
2264 * to current bus speed mode
2265 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302266 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 clk |= (4 << 14);
2268 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302269 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 clk |= (3 << 14);
2271 } else {
2272 clk |= (2 << 14); /* feedback clock */
2273 }
2274
2275 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2276 clk |= (2 << 23);
2277
2278 if (host->io_pad_pwr_switch)
2279 clk |= IO_PAD_PWR_SWITCH;
2280
2281 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002282 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2284 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002285
2286 switch (ios->power_mode) {
2287 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2289 if (!host->sdcc_irq_disabled) {
2290 if (host->plat->cfg_mpm_sdiowakeup)
2291 host->plat->cfg_mpm_sdiowakeup(
2292 mmc_dev(mmc), SDC_DAT1_DISABLE);
2293 disable_irq(host->core_irqres->start);
2294 host->sdcc_irq_disabled = 1;
2295 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302296 /*
2297 * As VDD pad rail is always on, set low voltage for VDD
2298 * pad rail when slot is unused (when card is not present
2299 * or during system suspend).
2300 */
2301 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002303 break;
2304 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302305 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002306 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307 if (host->sdcc_irq_disabled) {
2308 if (host->plat->cfg_mpm_sdiowakeup)
2309 host->plat->cfg_mpm_sdiowakeup(
2310 mmc_dev(mmc), SDC_DAT1_ENABLE);
2311 enable_irq(host->core_irqres->start);
2312 host->sdcc_irq_disabled = 0;
2313 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302314 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002316 break;
2317 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002318 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002319 pwr |= MCI_PWR_ON;
2320 break;
2321 }
2322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 spin_lock_irqsave(&host->lock, flags);
2324 if (!host->clks_on) {
2325 /* force the clocks to be on */
2326 msmsdcc_setup_clocks(host, true);
2327 /*
2328 * give atleast 2 MCLK cycles delay for clocks
2329 * and SDCC core to stabilize
2330 */
2331 msmsdcc_delay(host);
2332 }
2333 writel_relaxed(clk, host->base + MMCICLOCK);
2334 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002335
2336 if (host->pwr != pwr) {
2337 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302339 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002340 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 if (!host->clks_on) {
2342 /* force the clocks to be off */
2343 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344 }
2345
2346 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2347 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2348 if (!host->plat->sdiowakeup_irq) {
2349 writel_relaxed(MCI_SDIOINTMASK,
2350 host->base + MMCIMASK0);
2351 mb();
2352 if (host->plat->cfg_mpm_sdiowakeup &&
2353 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2354 host->plat->cfg_mpm_sdiowakeup(
2355 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2356 msmsdcc_enable_irq_wake(host);
2357 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2358 writel_relaxed(0, host->base + MMCIMASK0);
2359 } else {
2360 writel_relaxed(MCI_SDIOINTMASK,
2361 host->base + MMCIMASK0);
2362 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302363 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 }
2365 msmsdcc_setup_clocks(host, false);
2366 host->clks_on = 0;
2367 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302368
2369 if (host->cmd19_tuning_in_progress)
2370 WARN(!host->clks_on,
2371 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2372
San Mehat4adbbcc2009-11-08 13:00:37 -08002373 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002374}
2375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2377{
2378 struct msmsdcc_host *host = mmc_priv(mmc);
2379 u32 clk;
2380
2381 clk = readl_relaxed(host->base + MMCICLOCK);
2382 pr_debug("Changing to pwr_save=%d", pwrsave);
2383 if (pwrsave && msmsdcc_is_pwrsave(host))
2384 clk |= MCI_CLK_PWRSAVE;
2385 else
2386 clk &= ~MCI_CLK_PWRSAVE;
2387 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302388 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002389
2390 return 0;
2391}
2392
2393static int msmsdcc_get_ro(struct mmc_host *mmc)
2394{
2395 int status = -ENOSYS;
2396 struct msmsdcc_host *host = mmc_priv(mmc);
2397
2398 if (host->plat->wpswitch) {
2399 status = host->plat->wpswitch(mmc_dev(mmc));
2400 } else if (host->plat->wpswitch_gpio) {
2401 status = gpio_request(host->plat->wpswitch_gpio,
2402 "SD_WP_Switch");
2403 if (status) {
2404 pr_err("%s: %s: Failed to request GPIO %d\n",
2405 mmc_hostname(mmc), __func__,
2406 host->plat->wpswitch_gpio);
2407 } else {
2408 status = gpio_direction_input(
2409 host->plat->wpswitch_gpio);
2410 if (!status) {
2411 /*
2412 * Wait for atleast 300ms as debounce
2413 * time for GPIO input to stabilize.
2414 */
2415 msleep(300);
2416 status = gpio_get_value_cansleep(
2417 host->plat->wpswitch_gpio);
2418 status ^= !host->plat->wpswitch_polarity;
2419 }
2420 gpio_free(host->plat->wpswitch_gpio);
2421 }
2422 }
2423
2424 if (status < 0)
2425 status = -ENOSYS;
2426 pr_debug("%s: Card read-only status %d\n", __func__, status);
2427
2428 return status;
2429}
2430
2431#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002432static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2433{
2434 struct msmsdcc_host *host = mmc_priv(mmc);
2435 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436
2437 if (enable) {
2438 spin_lock_irqsave(&host->lock, flags);
2439 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2440 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2441 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2442 spin_unlock_irqrestore(&host->lock, flags);
2443 } else {
2444 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2445 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2446 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2447 }
2448 mb();
2449}
2450#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2451
2452#ifdef CONFIG_PM_RUNTIME
2453static int msmsdcc_enable(struct mmc_host *mmc)
2454{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302455 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 struct device *dev = mmc->parent;
2457
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302458 if (dev->power.runtime_status == RPM_SUSPENDING) {
2459 if (mmc->suspend_task == current) {
2460 pm_runtime_get_noresume(dev);
2461 goto out;
2462 }
2463 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302465 rc = pm_runtime_get_sync(dev);
2466
2467 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2469 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302470 return rc;
2471 }
2472out:
2473 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002474}
2475
2476static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2477{
2478 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302479 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302481 if (host->plat->disable_runtime_pm)
2482 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2484 return -ENOTSUPP;
2485
2486 rc = pm_runtime_put_sync(mmc->parent);
2487
2488 if (rc < 0)
2489 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2490 __func__, rc);
2491 return rc;
2492}
2493#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302494static int msmsdcc_enable(struct mmc_host *mmc)
2495{
2496 struct msmsdcc_host *host = mmc_priv(mmc);
2497 unsigned long flags;
2498
2499 spin_lock_irqsave(&host->lock, flags);
2500 if (!host->clks_on) {
2501 msmsdcc_setup_clocks(host, true);
2502 host->clks_on = 1;
2503 }
2504 spin_unlock_irqrestore(&host->lock, flags);
2505
2506 return 0;
2507}
2508
2509static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2510{
2511 struct msmsdcc_host *host = mmc_priv(mmc);
2512 unsigned long flags;
2513
2514 if (mmc->card && mmc_card_sdio(mmc->card))
2515 return -ENOTSUPP;
2516
2517 spin_lock_irqsave(&host->lock, flags);
2518 if (host->clks_on) {
2519 msmsdcc_setup_clocks(host, false);
2520 host->clks_on = 0;
2521 }
2522 spin_unlock_irqrestore(&host->lock, flags);
2523
2524 return 0;
2525}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526#endif
2527
2528static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2529 struct mmc_ios *ios)
2530{
2531 struct msmsdcc_host *host = mmc_priv(mmc);
2532 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302533 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534
2535 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2536 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302537 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 goto out;
2539 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2540 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302541 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 goto out;
2543 }
San Mehat9d2bd732009-09-22 16:44:22 -07002544
2545 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 /*
2547 * If we are here means voltage switch from high voltage to
2548 * low voltage is required
2549 */
2550
2551 /*
2552 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2553 * register until they become all zeros.
2554 */
2555 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302556 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2558 mmc_hostname(mmc), __func__);
2559 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002560 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561
2562 /* Stop SD CLK output. */
2563 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2564 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302565 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002566 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567
2568 /*
2569 * Switch VDDPX from high voltage to low voltage
2570 * to change the VDD of the SD IO pads.
2571 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302572 rc = msmsdcc_set_vddp_low_vol(host);
2573 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002574 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575
2576 spin_lock_irqsave(&host->lock, flags);
2577 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2578 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302579 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002580 host->io_pad_pwr_switch = 1;
2581 spin_unlock_irqrestore(&host->lock, flags);
2582
2583 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2584 usleep_range(5000, 5500);
2585
2586 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302587 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2589 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302590 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002591 spin_unlock_irqrestore(&host->lock, flags);
2592
2593 /*
2594 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2595 * don't become all ones within 1 ms then a Voltage Switch
2596 * sequence has failed and a power cycle to the card is required.
2597 * Otherwise Voltage Switch sequence is completed successfully.
2598 */
2599 usleep_range(1000, 1500);
2600
2601 spin_lock_irqsave(&host->lock, flags);
2602 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2603 != (0xF << 1)) {
2604 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2605 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302606 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607 goto out_unlock;
2608 }
2609
2610out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302611 /* Enable PWRSAVE */
2612 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2613 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 spin_unlock_irqrestore(&host->lock, flags);
2615out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302616 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617}
2618
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302619static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622
2623 /* Program the MCLK value to MCLK_FREQ bit field */
2624 if (host->clk_rate <= 112000000)
2625 mclk_freq = 0;
2626 else if (host->clk_rate <= 125000000)
2627 mclk_freq = 1;
2628 else if (host->clk_rate <= 137000000)
2629 mclk_freq = 2;
2630 else if (host->clk_rate <= 150000000)
2631 mclk_freq = 3;
2632 else if (host->clk_rate <= 162000000)
2633 mclk_freq = 4;
2634 else if (host->clk_rate <= 175000000)
2635 mclk_freq = 5;
2636 else if (host->clk_rate <= 187000000)
2637 mclk_freq = 6;
2638 else if (host->clk_rate <= 200000000)
2639 mclk_freq = 7;
2640
2641 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2642 & ~(7 << 24)) | (mclk_freq << 24)),
2643 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644}
2645
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302646/* Initialize the DLL (Programmable Delay Line ) */
2647static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002648{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302650 unsigned long flags;
2651 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302653 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 /*
2655 * Make sure that clock is always enabled when DLL
2656 * tuning is in progress. Keeping PWRSAVE ON may
2657 * turn off the clock. So let's disable the PWRSAVE
2658 * here and re-enable it once tuning is completed.
2659 */
2660 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2661 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302662
2663 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2664 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2665 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2666
2667 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2668 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2669 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2670
2671 msmsdcc_cm_sdc4_dll_set_freq(host);
2672
2673 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2674 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2675 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2676
2677 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2678 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2679 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2680
2681 /* Set DLL_EN bit to 1. */
2682 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2683 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2684
2685 /* Set CK_OUT_EN bit to 1. */
2686 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2687 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2688
2689 wait_cnt = 50;
2690 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2691 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2692 /* max. wait for 50us sec for LOCK bit to be set */
2693 if (--wait_cnt == 0) {
2694 pr_err("%s: %s: DLL failed to LOCK\n",
2695 mmc_hostname(host->mmc), __func__);
2696 rc = -ETIMEDOUT;
2697 goto out;
2698 }
2699 /* wait for 1us before polling again */
2700 udelay(1);
2701 }
2702
2703out:
2704 /* re-enable PWRSAVE */
2705 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2706 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2707 spin_unlock_irqrestore(&host->lock, flags);
2708
2709 return rc;
2710}
2711
2712static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2713 u8 poll)
2714{
2715 int rc = 0;
2716 u32 wait_cnt = 50;
2717 u8 ck_out_en = 0;
2718
2719 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2720 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2721 MCI_CK_OUT_EN);
2722
2723 while (ck_out_en != poll) {
2724 if (--wait_cnt == 0) {
2725 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2726 mmc_hostname(host->mmc), __func__, poll);
2727 rc = -ETIMEDOUT;
2728 goto out;
2729 }
2730 udelay(1);
2731
2732 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2733 MCI_CK_OUT_EN);
2734 }
2735out:
2736 return rc;
2737}
2738
2739/*
2740 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2741 * calibration sequence. This function should be called before
2742 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2743 * commands (CMD17/CMD18).
2744 *
2745 * This function gets called when host spinlock acquired.
2746 */
2747static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2748{
2749 int rc = 0;
2750 u32 config;
2751
2752 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2753 config |= MCI_CDR_EN;
2754 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2755 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2756
2757 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2758 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2759 if (rc)
2760 goto err_out;
2761
2762 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2763 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2764 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2765
2766 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2767 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2768 if (rc)
2769 goto err_out;
2770
2771 goto out;
2772
2773err_out:
2774 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2775out:
2776 return rc;
2777}
2778
2779static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2780 u8 phase)
2781{
2782 int rc = 0;
2783 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6,
2784 0x7, 0x5, 0x4, 0x8, 0x9,
2785 0xB, 0xA, 0xE, 0xF, 0xD,
2786 0xC};
2787 unsigned long flags;
2788 u32 config;
2789
2790 spin_lock_irqsave(&host->lock, flags);
2791
2792 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2793 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2794 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2795 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2796
2797 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2798 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2799 if (rc)
2800 goto err_out;
2801
2802 /*
2803 * Write the selected DLL clock output phase (0 ... 15)
2804 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2805 */
2806 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2807 & ~(0xF << 20))
2808 | (grey_coded_phase_table[phase] << 20)),
2809 host->base + MCI_DLL_CONFIG);
2810
2811 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2812 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2813 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2814
2815 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2816 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2817 if (rc)
2818 goto err_out;
2819
2820 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2821 config |= MCI_CDR_EN;
2822 config &= ~MCI_CDR_EXT_EN;
2823 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2824 goto out;
2825
2826err_out:
2827 pr_err("%s: %s: Failed to set DLL phase: %d\n",
2828 mmc_hostname(host->mmc), __func__, phase);
2829out:
2830 spin_unlock_irqrestore(&host->lock, flags);
2831 return rc;
2832}
2833
2834/*
2835 * Find out the greatest range of consecuitive selected
2836 * DLL clock output phases that can be used as sampling
2837 * setting for SD3.0 UHS-I card read operation (in SDR104
2838 * timing mode) or for eMMC4.5 card read operation (in HS200
2839 * timing mode).
2840 * Select the 3/4 of the range and configure the DLL with the
2841 * selected DLL clock output phase.
2842*/
2843
2844static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
2845 u8 *phase_table, u8 total_phases)
2846{
2847 u8 ret, temp;
2848 u8 ranges[16][16] = { {0}, {0} };
2849 u8 phases_per_row[16] = {0};
2850 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
2851 int cnt;
2852
2853 for (cnt = 0; cnt <= total_phases; cnt++) {
2854 ranges[row_index][col_index] = phase_table[cnt];
2855 phases_per_row[row_index] += 1;
2856 col_index++;
2857
2858 if ((cnt + 1) > total_phases) {
2859 continue;
2860 /* check if next phase in phase_table is consecutive or not */
2861 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2862 row_index++;
2863 col_index = 0;
2864 }
2865 }
2866
2867 for (cnt = 0; cnt <= total_phases; cnt++) {
2868 if (phases_per_row[cnt] > curr_max) {
2869 curr_max = phases_per_row[cnt];
2870 selected_row_index = cnt;
2871 }
2872 }
2873
2874 temp = ((curr_max * 3) / 4);
2875 ret = ranges[selected_row_index][temp];
2876
2877 return ret;
2878}
2879
2880static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2881{
2882 int rc = 0;
2883 struct msmsdcc_host *host = mmc_priv(mmc);
2884 unsigned long flags;
2885 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2886
2887 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2888
2889 /* Tuning is only required for SDR104 modes */
2890 if (!host->tuning_needed) {
2891 rc = 0;
2892 goto exit;
2893 }
2894
2895 spin_lock_irqsave(&host->lock, flags);
2896 WARN(!host->pwr, "SDCC power is turned off\n");
2897 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2898 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2899
2900 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302901 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302902 spin_unlock_irqrestore(&host->lock, flags);
2903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002904 /* first of all reset the tuning block */
2905 rc = msmsdcc_init_cm_sdc4_dll(host);
2906 if (rc)
2907 goto out;
2908
2909 data_buf = kmalloc(64, GFP_KERNEL);
2910 if (!data_buf) {
2911 rc = -ENOMEM;
2912 goto out;
2913 }
2914
2915 phase = 0;
2916 do {
2917 struct mmc_command cmd = {0};
2918 struct mmc_data data = {0};
2919 struct mmc_request mrq = {
2920 .cmd = &cmd,
2921 .data = &data
2922 };
2923 struct scatterlist sg;
2924
2925 /* set the phase in delay line hw block */
2926 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2927 if (rc)
2928 goto kfree;
2929
2930 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2931 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2932
2933 data.blksz = 64;
2934 data.blocks = 1;
2935 data.flags = MMC_DATA_READ;
2936 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2937
2938 data.sg = &sg;
2939 data.sg_len = 1;
2940 sg_init_one(&sg, data_buf, 64);
2941 memset(data_buf, 0, 64);
2942 mmc_wait_for_req(mmc, &mrq);
2943
2944 if (!cmd.error && !data.error &&
2945 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2946 /* tuning is successful with this tuning point */
2947 tuned_phases[tuned_phase_cnt++] = phase;
2948 }
2949 } while (++phase < 16);
2950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002951 if (tuned_phase_cnt) {
2952 tuned_phase_cnt--;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302953 phase = find_most_appropriate_phase(host, tuned_phases,
2954 tuned_phase_cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002955 /*
2956 * Finally set the selected phase in delay
2957 * line hw block.
2958 */
2959 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2960 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302961 goto kfree;
2962 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
2963 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964 } else {
2965 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302966 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002967 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302968 msmsdcc_dump_sdcc_state(host);
2969 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002970 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971
2972kfree:
2973 kfree(data_buf);
2974out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302975 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302976 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302978 spin_unlock_irqrestore(&host->lock, flags);
2979exit:
2980 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002981 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002982}
2983
2984static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002985 .enable = msmsdcc_enable,
2986 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002987 .request = msmsdcc_request,
2988 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 .get_ro = msmsdcc_get_ro,
2990#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002991 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992#endif
2993 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2994 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002995};
2996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997static unsigned int
2998msmsdcc_slot_status(struct msmsdcc_host *host)
2999{
3000 int status;
3001 unsigned int gpio_no = host->plat->status_gpio;
3002
3003 status = gpio_request(gpio_no, "SD_HW_Detect");
3004 if (status) {
3005 pr_err("%s: %s: Failed to request GPIO %d\n",
3006 mmc_hostname(host->mmc), __func__, gpio_no);
3007 } else {
3008 status = gpio_direction_input(gpio_no);
3009 if (!status)
Krishna Konda360aa422011-12-06 18:27:41 -08003010 status = gpio_get_value_cansleep(gpio_no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003011 gpio_free(gpio_no);
3012 }
3013 return status;
3014}
3015
San Mehat9d2bd732009-09-22 16:44:22 -07003016static void
3017msmsdcc_check_status(unsigned long data)
3018{
3019 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3020 unsigned int status;
3021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda360aa422011-12-06 18:27:41 -08003023 if (host->plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda360aa422011-12-06 18:27:41 -08003025 host->eject = !status;
3026 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 status = msmsdcc_slot_status(host);
3028
Krishna Konda360aa422011-12-06 18:27:41 -08003029 if (host->plat->is_status_gpio_active_low)
3030 host->eject = status;
3031 else
3032 host->eject = !status;
3033 }
3034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003036 if (host->plat->status)
3037 pr_info("%s: Slot status change detected "
3038 "(%d -> %d)\n",
3039 mmc_hostname(host->mmc),
3040 host->oldstat, status);
3041 else if (host->plat->is_status_gpio_active_low)
3042 pr_info("%s: Slot status change detected "
3043 "(%d -> %d) and the card detect GPIO"
3044 " is ACTIVE_LOW\n",
3045 mmc_hostname(host->mmc),
3046 host->oldstat, status);
3047 else
3048 pr_info("%s: Slot status change detected "
3049 "(%d -> %d) and the card detect GPIO"
3050 " is ACTIVE_HIGH\n",
3051 mmc_hostname(host->mmc),
3052 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003053 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 }
3055 host->oldstat = status;
3056 } else {
3057 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003058 }
San Mehat9d2bd732009-09-22 16:44:22 -07003059}
3060
3061static irqreturn_t
3062msmsdcc_platform_status_irq(int irq, void *dev_id)
3063{
3064 struct msmsdcc_host *host = dev_id;
3065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003067 msmsdcc_check_status((unsigned long) host);
3068 return IRQ_HANDLED;
3069}
3070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003071static irqreturn_t
3072msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3073{
3074 struct msmsdcc_host *host = dev_id;
3075
3076 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3077 spin_lock(&host->lock);
3078 if (!host->sdio_irq_disabled) {
3079 disable_irq_nosync(irq);
3080 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3081 wake_lock(&host->sdio_wlock);
3082 msmsdcc_disable_irq_wake(host);
3083 }
3084 host->sdio_irq_disabled = 1;
3085 }
3086 if (host->plat->is_sdio_al_client) {
3087 if (!host->clks_on) {
3088 msmsdcc_setup_clocks(host, true);
3089 host->clks_on = 1;
3090 }
3091 if (host->sdcc_irq_disabled) {
3092 writel_relaxed(host->mci_irqenable,
3093 host->base + MMCIMASK0);
3094 mb();
3095 enable_irq(host->core_irqres->start);
3096 host->sdcc_irq_disabled = 0;
3097 }
3098 wake_lock(&host->sdio_wlock);
3099 }
3100 spin_unlock(&host->lock);
3101
3102 return IRQ_HANDLED;
3103}
3104
San Mehat9d2bd732009-09-22 16:44:22 -07003105static void
3106msmsdcc_status_notify_cb(int card_present, void *dev_id)
3107{
3108 struct msmsdcc_host *host = dev_id;
3109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003111 card_present);
3112 msmsdcc_check_status((unsigned long) host);
3113}
3114
San Mehat9d2bd732009-09-22 16:44:22 -07003115static int
3116msmsdcc_init_dma(struct msmsdcc_host *host)
3117{
3118 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3119 host->dma.host = host;
3120 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003121 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003122
3123 if (!host->dmares)
3124 return -ENODEV;
3125
3126 host->dma.nc = dma_alloc_coherent(NULL,
3127 sizeof(struct msmsdcc_nc_dmadata),
3128 &host->dma.nc_busaddr,
3129 GFP_KERNEL);
3130 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003131 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003132 return -ENOMEM;
3133 }
3134 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3135 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3136 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3137 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3138 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003139 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003140
3141 return 0;
3142}
3143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3145/**
3146 * Allocate and Connect a SDCC peripheral's SPS endpoint
3147 *
3148 * This function allocates endpoint context and
3149 * connect it with memory endpoint by calling
3150 * appropriate SPS driver APIs.
3151 *
3152 * Also registers a SPS callback function with
3153 * SPS driver
3154 *
3155 * This function should only be called once typically
3156 * during driver probe.
3157 *
3158 * @host - Pointer to sdcc host structure
3159 * @ep - Pointer to sps endpoint data structure
3160 * @is_produce - 1 means Producer endpoint
3161 * 0 means Consumer endpoint
3162 *
3163 * @return - 0 if successful else negative value.
3164 *
3165 */
3166static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3167 struct msmsdcc_sps_ep_conn_data *ep,
3168 bool is_producer)
3169{
3170 int rc = 0;
3171 struct sps_pipe *sps_pipe_handle;
3172 struct sps_connect *sps_config = &ep->config;
3173 struct sps_register_event *sps_event = &ep->event;
3174
3175 /* Allocate endpoint context */
3176 sps_pipe_handle = sps_alloc_endpoint();
3177 if (!sps_pipe_handle) {
3178 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3179 mmc_hostname(host->mmc), is_producer);
3180 rc = -ENOMEM;
3181 goto out;
3182 }
3183
3184 /* Get default connection configuration for an endpoint */
3185 rc = sps_get_config(sps_pipe_handle, sps_config);
3186 if (rc) {
3187 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3188 " rc=%d", mmc_hostname(host->mmc),
3189 (u32)sps_pipe_handle, rc);
3190 goto get_config_err;
3191 }
3192
3193 /* Modify the default connection configuration */
3194 if (is_producer) {
3195 /*
3196 * For SDCC producer transfer, source should be
3197 * SDCC peripheral where as destination should
3198 * be system memory.
3199 */
3200 sps_config->source = host->sps.bam_handle;
3201 sps_config->destination = SPS_DEV_HANDLE_MEM;
3202 /* Producer pipe will handle this connection */
3203 sps_config->mode = SPS_MODE_SRC;
3204 sps_config->options =
3205 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3206 } else {
3207 /*
3208 * For SDCC consumer transfer, source should be
3209 * system memory where as destination should
3210 * SDCC peripheral
3211 */
3212 sps_config->source = SPS_DEV_HANDLE_MEM;
3213 sps_config->destination = host->sps.bam_handle;
3214 sps_config->mode = SPS_MODE_DEST;
3215 sps_config->options =
3216 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3217 }
3218
3219 /* Producer pipe index */
3220 sps_config->src_pipe_index = host->sps.src_pipe_index;
3221 /* Consumer pipe index */
3222 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3223 /*
3224 * This event thresold value is only significant for BAM-to-BAM
3225 * transfer. It's ignored for BAM-to-System mode transfer.
3226 */
3227 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303228
3229 /* Allocate maximum descriptor fifo size */
3230 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3231 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3233 sps_config->desc.size,
3234 &sps_config->desc.phys_base,
3235 GFP_KERNEL);
3236
Pratibhasagar V00b94332011-10-18 14:57:27 +05303237 if (!sps_config->desc.base) {
3238 rc = -ENOMEM;
3239 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3240 , mmc_hostname(host->mmc));
3241 goto get_config_err;
3242 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003243 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3244
3245 /* Establish connection between peripheral and memory endpoint */
3246 rc = sps_connect(sps_pipe_handle, sps_config);
3247 if (rc) {
3248 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3249 " rc=%d", mmc_hostname(host->mmc),
3250 (u32)sps_pipe_handle, rc);
3251 goto sps_connect_err;
3252 }
3253
3254 sps_event->mode = SPS_TRIGGER_CALLBACK;
3255 sps_event->options = SPS_O_EOT;
3256 sps_event->callback = msmsdcc_sps_complete_cb;
3257 sps_event->xfer_done = NULL;
3258 sps_event->user = (void *)host;
3259
3260 /* Register callback event for EOT (End of transfer) event. */
3261 rc = sps_register_event(sps_pipe_handle, sps_event);
3262 if (rc) {
3263 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3264 " rc=%d", mmc_hostname(host->mmc),
3265 (u32)sps_pipe_handle, rc);
3266 goto reg_event_err;
3267 }
3268 /* Now save the sps pipe handle */
3269 ep->pipe_handle = sps_pipe_handle;
3270 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3271 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3272 __func__, is_producer ? "READ" : "WRITE",
3273 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3274 goto out;
3275
3276reg_event_err:
3277 sps_disconnect(sps_pipe_handle);
3278sps_connect_err:
3279 dma_free_coherent(mmc_dev(host->mmc),
3280 sps_config->desc.size,
3281 sps_config->desc.base,
3282 sps_config->desc.phys_base);
3283get_config_err:
3284 sps_free_endpoint(sps_pipe_handle);
3285out:
3286 return rc;
3287}
3288
3289/**
3290 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3291 *
3292 * This function disconnect endpoint and deallocates
3293 * endpoint context.
3294 *
3295 * This function should only be called once typically
3296 * during driver remove.
3297 *
3298 * @host - Pointer to sdcc host structure
3299 * @ep - Pointer to sps endpoint data structure
3300 *
3301 */
3302static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3303 struct msmsdcc_sps_ep_conn_data *ep)
3304{
3305 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3306 struct sps_connect *sps_config = &ep->config;
3307 struct sps_register_event *sps_event = &ep->event;
3308
3309 sps_event->xfer_done = NULL;
3310 sps_event->callback = NULL;
3311 sps_register_event(sps_pipe_handle, sps_event);
3312 sps_disconnect(sps_pipe_handle);
3313 dma_free_coherent(mmc_dev(host->mmc),
3314 sps_config->desc.size,
3315 sps_config->desc.base,
3316 sps_config->desc.phys_base);
3317 sps_free_endpoint(sps_pipe_handle);
3318}
3319
3320/**
3321 * Reset SDCC peripheral's SPS endpoint
3322 *
3323 * This function disconnects an endpoint.
3324 *
3325 * This function should be called for reseting
3326 * SPS endpoint when data transfer error is
3327 * encountered during data transfer. This
3328 * can be considered as soft reset to endpoint.
3329 *
3330 * This function should only be called if
3331 * msmsdcc_sps_init() is already called.
3332 *
3333 * @host - Pointer to sdcc host structure
3334 * @ep - Pointer to sps endpoint data structure
3335 *
3336 * @return - 0 if successful else negative value.
3337 */
3338static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3339 struct msmsdcc_sps_ep_conn_data *ep)
3340{
3341 int rc = 0;
3342 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3343
3344 rc = sps_disconnect(sps_pipe_handle);
3345 if (rc) {
3346 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3347 " rc=%d", mmc_hostname(host->mmc), __func__,
3348 (u32)sps_pipe_handle, rc);
3349 goto out;
3350 }
3351 out:
3352 return rc;
3353}
3354
3355/**
3356 * Restore SDCC peripheral's SPS endpoint
3357 *
3358 * This function connects an endpoint.
3359 *
3360 * This function should be called for restoring
3361 * SPS endpoint after data transfer error is
3362 * encountered during data transfer. This
3363 * can be considered as soft reset to endpoint.
3364 *
3365 * This function should only be called if
3366 * msmsdcc_sps_reset_ep() is called before.
3367 *
3368 * @host - Pointer to sdcc host structure
3369 * @ep - Pointer to sps endpoint data structure
3370 *
3371 * @return - 0 if successful else negative value.
3372 */
3373static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3374 struct msmsdcc_sps_ep_conn_data *ep)
3375{
3376 int rc = 0;
3377 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3378 struct sps_connect *sps_config = &ep->config;
3379 struct sps_register_event *sps_event = &ep->event;
3380
3381 /* Establish connection between peripheral and memory endpoint */
3382 rc = sps_connect(sps_pipe_handle, sps_config);
3383 if (rc) {
3384 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3385 " rc=%d", mmc_hostname(host->mmc), __func__,
3386 (u32)sps_pipe_handle, rc);
3387 goto out;
3388 }
3389
3390 /* Register callback event for EOT (End of transfer) event. */
3391 rc = sps_register_event(sps_pipe_handle, sps_event);
3392 if (rc) {
3393 pr_err("%s: %s: sps_register_event() failed!!!"
3394 " pipe_handle=0x%x, rc=%d",
3395 mmc_hostname(host->mmc), __func__,
3396 (u32)sps_pipe_handle, rc);
3397 goto reg_event_err;
3398 }
3399 goto out;
3400
3401reg_event_err:
3402 sps_disconnect(sps_pipe_handle);
3403out:
3404 return rc;
3405}
3406
3407/**
3408 * Initialize SPS HW connected with SDCC core
3409 *
3410 * This function register BAM HW resources with
3411 * SPS driver and then initialize 2 SPS endpoints
3412 *
3413 * This function should only be called once typically
3414 * during driver probe.
3415 *
3416 * @host - Pointer to sdcc host structure
3417 *
3418 * @return - 0 if successful else negative value.
3419 *
3420 */
3421static int msmsdcc_sps_init(struct msmsdcc_host *host)
3422{
3423 int rc = 0;
3424 struct sps_bam_props bam = {0};
3425
3426 host->bam_base = ioremap(host->bam_memres->start,
3427 resource_size(host->bam_memres));
3428 if (!host->bam_base) {
3429 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3430 " size=0x%x", mmc_hostname(host->mmc),
3431 host->bam_memres->start,
3432 (host->bam_memres->end -
3433 host->bam_memres->start));
3434 rc = -ENOMEM;
3435 goto out;
3436 }
3437
3438 bam.phys_addr = host->bam_memres->start;
3439 bam.virt_addr = host->bam_base;
3440 /*
3441 * This event thresold value is only significant for BAM-to-BAM
3442 * transfer. It's ignored for BAM-to-System mode transfer.
3443 */
3444 bam.event_threshold = 0x10; /* Pipe event threshold */
3445 /*
3446 * This threshold controls when the BAM publish
3447 * the descriptor size on the sideband interface.
3448 * SPS HW will only be used when
3449 * data transfer size > MCI_FIFOSIZE (64 bytes).
3450 * PIO mode will be used when
3451 * data transfer size < MCI_FIFOSIZE (64 bytes).
3452 * So set this thresold value to 64 bytes.
3453 */
3454 bam.summing_threshold = 64;
3455 /* SPS driver wll handle the SDCC BAM IRQ */
3456 bam.irq = (u32)host->bam_irqres->start;
3457 bam.manage = SPS_BAM_MGR_LOCAL;
3458
3459 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3460 (u32)bam.phys_addr);
3461 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3462 (u32)bam.virt_addr);
3463
3464 /* Register SDCC Peripheral BAM device to SPS driver */
3465 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3466 if (rc) {
3467 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3468 mmc_hostname(host->mmc), rc);
3469 goto reg_bam_err;
3470 }
3471 pr_info("%s: BAM device registered. bam_handle=0x%x",
3472 mmc_hostname(host->mmc), host->sps.bam_handle);
3473
3474 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3475 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3476
3477 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3478 SPS_PROD_PERIPHERAL);
3479 if (rc)
3480 goto sps_reset_err;
3481 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3482 SPS_CONS_PERIPHERAL);
3483 if (rc)
3484 goto cons_conn_err;
3485
3486 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3487 mmc_hostname(host->mmc),
3488 (unsigned long long)host->bam_memres->start,
3489 (unsigned int)host->bam_irqres->start);
3490 goto out;
3491
3492cons_conn_err:
3493 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3494sps_reset_err:
3495 sps_deregister_bam_device(host->sps.bam_handle);
3496reg_bam_err:
3497 iounmap(host->bam_base);
3498out:
3499 return rc;
3500}
3501
3502/**
3503 * De-initialize SPS HW connected with SDCC core
3504 *
3505 * This function deinitialize SPS endpoints and then
3506 * deregisters BAM resources from SPS driver.
3507 *
3508 * This function should only be called once typically
3509 * during driver remove.
3510 *
3511 * @host - Pointer to sdcc host structure
3512 *
3513 */
3514static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3515{
3516 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3517 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3518 sps_deregister_bam_device(host->sps.bam_handle);
3519 iounmap(host->bam_base);
3520}
3521#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3522
3523static ssize_t
3524show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3525{
3526 struct mmc_host *mmc = dev_get_drvdata(dev);
3527 struct msmsdcc_host *host = mmc_priv(mmc);
3528 int poll;
3529 unsigned long flags;
3530
3531 spin_lock_irqsave(&host->lock, flags);
3532 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3533 spin_unlock_irqrestore(&host->lock, flags);
3534
3535 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3536}
3537
3538static ssize_t
3539set_polling(struct device *dev, struct device_attribute *attr,
3540 const char *buf, size_t count)
3541{
3542 struct mmc_host *mmc = dev_get_drvdata(dev);
3543 struct msmsdcc_host *host = mmc_priv(mmc);
3544 int value;
3545 unsigned long flags;
3546
3547 sscanf(buf, "%d", &value);
3548
3549 spin_lock_irqsave(&host->lock, flags);
3550 if (value) {
3551 mmc->caps |= MMC_CAP_NEEDS_POLL;
3552 mmc_detect_change(host->mmc, 0);
3553 } else {
3554 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3555 }
3556#ifdef CONFIG_HAS_EARLYSUSPEND
3557 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3558#endif
3559 spin_unlock_irqrestore(&host->lock, flags);
3560 return count;
3561}
3562
3563static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3564 show_polling, set_polling);
3565static struct attribute *dev_attrs[] = {
3566 &dev_attr_polling.attr,
3567 NULL,
3568};
3569static struct attribute_group dev_attr_grp = {
3570 .attrs = dev_attrs,
3571};
3572
3573#ifdef CONFIG_HAS_EARLYSUSPEND
3574static void msmsdcc_early_suspend(struct early_suspend *h)
3575{
3576 struct msmsdcc_host *host =
3577 container_of(h, struct msmsdcc_host, early_suspend);
3578 unsigned long flags;
3579
3580 spin_lock_irqsave(&host->lock, flags);
3581 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3582 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3583 spin_unlock_irqrestore(&host->lock, flags);
3584};
3585static void msmsdcc_late_resume(struct early_suspend *h)
3586{
3587 struct msmsdcc_host *host =
3588 container_of(h, struct msmsdcc_host, early_suspend);
3589 unsigned long flags;
3590
3591 if (host->polling_enabled) {
3592 spin_lock_irqsave(&host->lock, flags);
3593 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3594 mmc_detect_change(host->mmc, 0);
3595 spin_unlock_irqrestore(&host->lock, flags);
3596 }
3597};
3598#endif
3599
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303600void msmsdcc_print_regs(const char *name, void __iomem *base,
3601 unsigned int no_of_regs)
3602{
3603 unsigned int i;
3604
3605 if (!base)
3606 return;
3607 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3608 name, (u32)base);
3609 for (i = 0; i < no_of_regs; i = i + 4) {
3610 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3611 (u32)readl_relaxed(base + i*4),
3612 (u32)readl_relaxed(base + ((i+1)*4)),
3613 (u32)readl_relaxed(base + ((i+2)*4)),
3614 (u32)readl_relaxed(base + ((i+3)*4)));
3615 }
3616}
3617
3618static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3619{
3620 /* Dump current state of SDCC clocks, power and irq */
3621 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3622 (host->pwr ? "ON" : "OFF"));
3623 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3624 mmc_hostname(host->mmc),
3625 (host->clks_on ? "ON" : "OFF"),
3626 (u32)clk_get_rate(host->clk));
3627 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3628 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3629
3630 /* Now dump SDCC registers. Don't print FIFO registers */
3631 if (host->clks_on)
3632 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3633
3634 if (host->curr.data) {
3635 if (msmsdcc_check_dma_op_req(host->curr.data))
3636 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3637 else if (host->is_dma_mode)
3638 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3639 mmc_hostname(host->mmc), host->dma.busy,
3640 host->dma.channel, host->dma.crci);
3641 else if (host->is_sps_mode)
3642 pr_info("%s: SPS mode: busy=%d\n",
3643 mmc_hostname(host->mmc), host->sps.busy);
3644
3645 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3646 mmc_hostname(host->mmc), host->curr.xfer_size,
3647 host->curr.data_xfered, host->curr.xfer_remain);
3648 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3649 " wait_for_auto_prog_done=%d,"
3650 " got_auto_prog_done=%d\n",
3651 mmc_hostname(host->mmc), host->curr.got_dataend,
3652 host->prog_enable, host->curr.wait_for_auto_prog_done,
3653 host->curr.got_auto_prog_done);
3654 }
3655
3656}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003657static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3658{
3659 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3660 struct mmc_request *mrq;
3661 unsigned long flags;
3662
3663 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003664 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003665 pr_info("%s: %s: dummy CMD52 timeout\n",
3666 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003667 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668 }
3669
3670 mrq = host->curr.mrq;
3671
3672 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303673 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3674 mrq->cmd->opcode);
3675 msmsdcc_dump_sdcc_state(host);
3676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 if (!mrq->cmd->error)
3678 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303679 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003680 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003681 if (mrq->data && !mrq->data->error)
3682 mrq->data->error = -ETIMEDOUT;
3683 host->curr.data_xfered = 0;
3684 if (host->dma.sg && host->is_dma_mode) {
3685 msm_dmov_stop_cmd(host->dma.channel,
3686 &host->dma.hdr, 0);
3687 } else if (host->sps.sg && host->is_sps_mode) {
3688 /* Stop current SPS transfer */
3689 msmsdcc_sps_exit_curr_xfer(host);
3690 } else {
3691 msmsdcc_reset_and_restore(host);
3692 msmsdcc_stop_data(host);
3693 if (mrq->data && mrq->data->stop)
3694 msmsdcc_start_command(host,
3695 mrq->data->stop, 0);
3696 else
3697 msmsdcc_request_end(host, mrq);
3698 }
3699 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303700 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701 msmsdcc_reset_and_restore(host);
3702 msmsdcc_request_end(host, mrq);
3703 }
3704 }
3705 spin_unlock_irqrestore(&host->lock, flags);
3706}
3707
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303708static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3709{
3710 int i, ret;
3711 struct mmc_platform_data *pdata;
3712 struct device_node *np = dev->of_node;
3713 u32 bus_width = 0;
3714 u32 *clk_table;
3715 int clk_table_len;
3716 u32 *sup_voltages;
3717 int sup_volt_len;
3718
3719 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3720 if (!pdata) {
3721 dev_err(dev, "could not allocate memory for platform data\n");
3722 goto err;
3723 }
3724
3725 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3726 if (bus_width == 8) {
3727 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3728 } else if (bus_width == 4) {
3729 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3730 } else {
3731 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3732 pdata->mmc_bus_width = 0;
3733 }
3734
3735 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3736 size_t sz;
3737 sz = sup_volt_len / sizeof(*sup_voltages);
3738 if (sz > 0) {
3739 sup_voltages = devm_kzalloc(dev,
3740 sz * sizeof(*sup_voltages), GFP_KERNEL);
3741 if (!sup_voltages) {
3742 dev_err(dev, "No memory for supported voltage\n");
3743 goto err;
3744 }
3745
3746 ret = of_property_read_u32_array(np,
3747 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3748 if (ret < 0) {
3749 dev_err(dev, "error while reading voltage"
3750 "ranges %d\n", ret);
3751 goto err;
3752 }
3753 } else {
3754 dev_err(dev, "No supported voltages\n");
3755 goto err;
3756 }
3757 for (i = 0; i < sz; i += 2) {
3758 u32 mask;
3759
3760 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3761 sup_voltages[i + 1]);
3762 if (!mask)
3763 dev_err(dev, "Invalide voltage range %d\n", i);
3764 pdata->ocr_mask |= mask;
3765 }
3766 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3767 } else {
3768 dev_err(dev, "Supported voltage range not specified\n");
3769 }
3770
3771 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3772 size_t sz;
3773 sz = clk_table_len / sizeof(*clk_table);
3774
3775 if (sz > 0) {
3776 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3777 GFP_KERNEL);
3778 if (!clk_table) {
3779 dev_err(dev, "No memory for clock table\n");
3780 goto err;
3781 }
3782
3783 ret = of_property_read_u32_array(np,
3784 "qcom,sdcc-clk-rates", clk_table, sz);
3785 if (ret < 0) {
3786 dev_err(dev, "error while reading clk"
3787 "table %d\n", ret);
3788 goto err;
3789 }
3790 } else {
3791 dev_err(dev, "clk_table not specified\n");
3792 goto err;
3793 }
3794 pdata->sup_clk_table = clk_table;
3795 pdata->sup_clk_cnt = sz;
3796 } else {
3797 dev_err(dev, "Supported clock rates not specified\n");
3798 }
3799
3800 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3801 pdata->nonremovable = true;
3802 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3803 pdata->disable_cmd23 = true;
3804
3805 return pdata;
3806err:
3807 return NULL;
3808}
3809
San Mehat9d2bd732009-09-22 16:44:22 -07003810static int
3811msmsdcc_probe(struct platform_device *pdev)
3812{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303813 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003814 struct msmsdcc_host *host;
3815 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816 unsigned long flags;
3817 struct resource *core_irqres = NULL;
3818 struct resource *bam_irqres = NULL;
3819 struct resource *core_memres = NULL;
3820 struct resource *dml_memres = NULL;
3821 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003822 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003823 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303824 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003826
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303827 if (pdev->dev.of_node) {
3828 plat = msmsdcc_populate_pdata(&pdev->dev);
3829 of_property_read_u32((&pdev->dev)->of_node,
3830 "cell-index", &pdev->id);
3831 } else {
3832 plat = pdev->dev.platform_data;
3833 }
3834
San Mehat9d2bd732009-09-22 16:44:22 -07003835 /* must have platform data */
3836 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003837 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003838 ret = -EINVAL;
3839 goto out;
3840 }
3841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003842 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003843 return -EINVAL;
3844
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303845 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3846 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3847 return -EINVAL;
3848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003849
San Mehat9d2bd732009-09-22 16:44:22 -07003850 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003851 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003852 return -ENXIO;
3853 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303854 if (pdev->dev.of_node) {
3855 /*
3856 * Device tree iomem resources are only accessible by index.
3857 * index = 0 -> SDCC register interface
3858 * index = 1 -> DML register interface
3859 * index = 2 -> BAM register interface
3860 * IRQ resources:
3861 * index = 0 -> SDCC IRQ
3862 * index = 1 -> BAM IRQ
3863 */
3864 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3865 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3866 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3867 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3868 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3869 } else {
3870 for (i = 0; i < pdev->num_resources; i++) {
3871 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3872 if (!strncmp(pdev->resource[i].name,
3873 "sdcc_dml_addr",
3874 sizeof("sdcc_dml_addr")))
3875 dml_memres = &pdev->resource[i];
3876 else if (!strncmp(pdev->resource[i].name,
3877 "sdcc_bam_addr",
3878 sizeof("sdcc_bam_addr")))
3879 bam_memres = &pdev->resource[i];
3880 else
3881 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003882
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303883 }
3884 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3885 if (!strncmp(pdev->resource[i].name,
3886 "sdcc_bam_irq",
3887 sizeof("sdcc_bam_irq")))
3888 bam_irqres = &pdev->resource[i];
3889 else
3890 core_irqres = &pdev->resource[i];
3891 }
3892 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3893 if (!strncmp(pdev->resource[i].name,
3894 "sdcc_dma_chnl",
3895 sizeof("sdcc_dma_chnl")))
3896 dmares = &pdev->resource[i];
3897 else if (!strncmp(pdev->resource[i].name,
3898 "sdcc_dma_crci",
3899 sizeof("sdcc_dma_crci")))
3900 dma_crci_res = &pdev->resource[i];
3901 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003902 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 }
3904
3905 if (!core_irqres || !core_memres) {
3906 pr_err("%s: Invalid sdcc core resource\n", __func__);
3907 return -ENXIO;
3908 }
3909
3910 /*
3911 * Both BAM and DML memory resource should be preset.
3912 * BAM IRQ resource should also be present.
3913 */
3914 if ((bam_memres && !dml_memres) ||
3915 (!bam_memres && dml_memres) ||
3916 ((bam_memres && dml_memres) && !bam_irqres)) {
3917 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003918 return -ENXIO;
3919 }
3920
3921 /*
3922 * Setup our host structure
3923 */
San Mehat9d2bd732009-09-22 16:44:22 -07003924 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3925 if (!mmc) {
3926 ret = -ENOMEM;
3927 goto out;
3928 }
3929
3930 host = mmc_priv(mmc);
3931 host->pdev_id = pdev->id;
3932 host->plat = plat;
3933 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003934 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303935
3936 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937 host->is_sps_mode = 1;
3938 else if (dmares)
3939 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941 host->base = ioremap(core_memres->start,
3942 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003943 if (!host->base) {
3944 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003946 }
3947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 host->core_irqres = core_irqres;
3949 host->bam_irqres = bam_irqres;
3950 host->core_memres = core_memres;
3951 host->dml_memres = dml_memres;
3952 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003953 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003954 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003955 spin_lock_init(&host->lock);
3956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003957#ifdef CONFIG_MMC_EMBEDDED_SDIO
3958 if (plat->embedded_sdio)
3959 mmc_set_embedded_sdio_data(mmc,
3960 &plat->embedded_sdio->cis,
3961 &plat->embedded_sdio->cccr,
3962 plat->embedded_sdio->funcs,
3963 plat->embedded_sdio->num_funcs);
3964#endif
3965
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303966 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3967 (unsigned long)host);
3968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3970 (unsigned long)host);
3971 if (host->is_dma_mode) {
3972 /* Setup DMA */
3973 ret = msmsdcc_init_dma(host);
3974 if (ret)
3975 goto ioremap_free;
3976 } else {
3977 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003978 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003979 }
3980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981 /*
3982 * Setup SDCC clock if derived from Dayatona
3983 * fabric core clock.
3984 */
3985 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003986 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987 if (!IS_ERR(host->dfab_pclk)) {
3988 /* Set the clock rate to 64MHz for max. performance */
3989 ret = clk_set_rate(host->dfab_pclk, 64000000);
3990 if (ret)
3991 goto dfab_pclk_put;
3992 ret = clk_enable(host->dfab_pclk);
3993 if (ret)
3994 goto dfab_pclk_put;
3995 } else
3996 goto dma_free;
3997 }
3998
3999 /*
4000 * Setup main peripheral bus clock
4001 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004002 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004003 if (!IS_ERR(host->pclk)) {
4004 ret = clk_enable(host->pclk);
4005 if (ret)
4006 goto pclk_put;
4007
4008 host->pclk_rate = clk_get_rate(host->pclk);
4009 }
4010
4011 /*
4012 * Setup SDC MMC clock
4013 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004014 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004015 if (IS_ERR(host->clk)) {
4016 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004017 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004018 }
4019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004020 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4021 if (ret) {
4022 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4023 goto clk_put;
4024 }
4025
4026 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004027 if (ret)
4028 goto clk_put;
4029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304031 if (!host->clk_rate)
4032 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304033
4034 /*
4035 * Lookup the Controller Version, to identify the supported features
4036 * Version number read as 0 would indicate SDCC3 or earlier versions
4037 */
4038 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4039 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4040 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304041 /*
4042 * Set the register write delay according to min. clock frequency
4043 * supported and update later when the host->clk_rate changes.
4044 */
4045 host->reg_write_delay =
4046 (1 + ((3 * USEC_PER_SEC) /
4047 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048
4049 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304050 /* Apply Hard reset to SDCC to put it in power on default state */
4051 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052
4053 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004054 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004056 goto clk_disable;
4057 }
4058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059
4060 /* Clocks has to be running before accessing SPS/DML HW blocks */
4061 if (host->is_sps_mode) {
4062 /* Initialize SPS */
4063 ret = msmsdcc_sps_init(host);
4064 if (ret)
4065 goto vreg_deinit;
4066 /* Initialize DML */
4067 ret = msmsdcc_dml_init(host);
4068 if (ret)
4069 goto sps_exit;
4070 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304071 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004072
San Mehat9d2bd732009-09-22 16:44:22 -07004073 /*
4074 * Setup MMC host structure
4075 */
4076 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4078 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004079 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4081 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004082
San Mehat9d2bd732009-09-22 16:44:22 -07004083 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304084 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304085
4086 /*
4087 * If we send the CMD23 before multi block write/read command
4088 * then we need not to send CMD12 at the end of the transfer.
4089 * If we don't send the CMD12 then only way to detect the PROG_DONE
4090 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4091 * controller. So let's enable the CMD23 for SDCC4 only.
4092 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304093 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304094 mmc->caps |= MMC_CAP_CMD23;
4095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004096 mmc->caps |= plat->uhs_caps;
4097 /*
4098 * XPC controls the maximum current in the default speed mode of SDXC
4099 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4100 * XPC=1 means 150mA (max.) and speed class is supported.
4101 */
4102 if (plat->xpc_cap)
4103 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4104 MMC_CAP_SET_XPC_180);
4105
4106 if (plat->nonremovable)
4107 mmc->caps |= MMC_CAP_NONREMOVABLE;
4108#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4109 mmc->caps |= MMC_CAP_SDIO_IRQ;
4110#endif
4111
4112 if (plat->is_sdio_al_client)
4113 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004114
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304115 mmc->max_segs = msmsdcc_get_nr_sg(host);
4116 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4117 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004118
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304119 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304120 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122 writel_relaxed(0, host->base + MMCIMASK0);
4123 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4126 mb();
4127 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4130 DRIVER_NAME " (cmd)", host);
4131 if (ret)
4132 goto dml_exit;
4133
4134 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4135 DRIVER_NAME " (pio)", host);
4136 if (ret)
4137 goto irq_free;
4138
4139 /*
4140 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4141 * IRQ is un-necessarily being monitored by MPM (Modem power
4142 * management block) during idle-power collapse. The MPM will be
4143 * configured to monitor the DATA1 GPIO line with level-low trigger
4144 * and thus depending on the GPIO status, it prevents TCXO shutdown
4145 * during idle-power collapse.
4146 */
4147 disable_irq(core_irqres->start);
4148 host->sdcc_irq_disabled = 1;
4149
4150 if (plat->sdiowakeup_irq) {
4151 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4152 mmc_hostname(mmc));
4153 ret = request_irq(plat->sdiowakeup_irq,
4154 msmsdcc_platform_sdiowakeup_irq,
4155 IRQF_SHARED | IRQF_TRIGGER_LOW,
4156 DRIVER_NAME "sdiowakeup", host);
4157 if (ret) {
4158 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4159 plat->sdiowakeup_irq, ret);
4160 goto pio_irq_free;
4161 } else {
4162 spin_lock_irqsave(&host->lock, flags);
4163 if (!host->sdio_irq_disabled) {
4164 disable_irq_nosync(plat->sdiowakeup_irq);
4165 host->sdio_irq_disabled = 1;
4166 }
4167 spin_unlock_irqrestore(&host->lock, flags);
4168 }
4169 }
4170
4171 if (plat->cfg_mpm_sdiowakeup) {
4172 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4173 mmc_hostname(mmc));
4174 }
4175
4176 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4177 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004178 /*
4179 * Setup card detect change
4180 */
4181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004182 if (plat->status || plat->status_gpio) {
Krishna Konda360aa422011-12-06 18:27:41 -08004183 if (plat->status) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda360aa422011-12-06 18:27:41 -08004185 host->eject = !host->oldstat;
4186 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004188
4189 if (host->plat->is_status_gpio_active_low)
4190 host->eject = host->oldstat;
4191 else
4192 host->eject = !host->oldstat;
4193 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194 }
San Mehat9d2bd732009-09-22 16:44:22 -07004195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 if (plat->status_irq) {
4197 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004198 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004200 DRIVER_NAME " (slot)",
4201 host);
4202 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004203 pr_err("Unable to get slot IRQ %d (%d)\n",
4204 plat->status_irq, ret);
4205 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004206 }
4207 } else if (plat->register_status_notify) {
4208 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4209 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004210 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004211 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004212
4213 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214
4215 ret = pm_runtime_set_active(&(pdev)->dev);
4216 if (ret < 0)
4217 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4218 __func__, ret);
4219 /*
4220 * There is no notion of suspend/resume for SD/MMC/SDIO
4221 * cards. So host can be suspended/resumed with out
4222 * worrying about its children.
4223 */
4224 pm_suspend_ignore_children(&(pdev)->dev, true);
4225
4226 /*
4227 * MMC/SD/SDIO bus suspend/resume operations are defined
4228 * only for the slots that will be used for non-removable
4229 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4230 * defined. Otherwise, they simply become card removal and
4231 * insertion events during suspend and resume respectively.
4232 * Hence, enable run-time PM only for slots for which bus
4233 * suspend/resume operations are defined.
4234 */
4235#ifdef CONFIG_MMC_UNSAFE_RESUME
4236 /*
4237 * If this capability is set, MMC core will enable/disable host
4238 * for every claim/release operation on a host. We use this
4239 * notification to increment/decrement runtime pm usage count.
4240 */
4241 mmc->caps |= MMC_CAP_DISABLE;
4242 pm_runtime_enable(&(pdev)->dev);
4243#else
4244 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4245 mmc->caps |= MMC_CAP_DISABLE;
4246 pm_runtime_enable(&(pdev)->dev);
4247 }
4248#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304249#ifndef CONFIG_PM_RUNTIME
4250 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4251#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4253 (unsigned long)host);
4254
San Mehat9d2bd732009-09-22 16:44:22 -07004255 mmc_add_host(mmc);
4256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004257#ifdef CONFIG_HAS_EARLYSUSPEND
4258 host->early_suspend.suspend = msmsdcc_early_suspend;
4259 host->early_suspend.resume = msmsdcc_late_resume;
4260 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4261 register_early_suspend(&host->early_suspend);
4262#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004263
Krishna Konda25786ec2011-07-25 16:21:36 -07004264 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4265 " dmacrcri %d\n", mmc_hostname(mmc),
4266 (unsigned long long)core_memres->start,
4267 (unsigned int) core_irqres->start,
4268 (unsigned int) plat->status_irq, host->dma.channel,
4269 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004270
4271 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4272 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4273 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4274 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4275 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4276 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4277 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4278 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4279 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4280 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4281 host->eject);
4282 pr_info("%s: Power save feature enable = %d\n",
4283 mmc_hostname(mmc), msmsdcc_pwrsave);
4284
Krishna Konda25786ec2011-07-25 16:21:36 -07004285 if (host->is_dma_mode && host->dma.channel != -1
4286 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004287 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004288 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004289 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004290 mmc_hostname(mmc), host->dma.cmd_busaddr,
4291 host->dma.cmdptr_busaddr);
4292 } else if (host->is_sps_mode) {
4293 pr_info("%s: SPS-BAM data transfer mode available\n",
4294 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004295 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004296 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004298#if defined(CONFIG_DEBUG_FS)
4299 msmsdcc_dbg_createhost(host);
4300#endif
4301 if (!plat->status_irq) {
4302 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4303 if (ret)
4304 goto platform_irq_free;
4305 }
San Mehat9d2bd732009-09-22 16:44:22 -07004306 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307
4308 platform_irq_free:
4309 del_timer_sync(&host->req_tout_timer);
4310 pm_runtime_disable(&(pdev)->dev);
4311 pm_runtime_set_suspended(&(pdev)->dev);
4312
4313 if (plat->status_irq)
4314 free_irq(plat->status_irq, host);
4315 sdiowakeup_irq_free:
4316 wake_lock_destroy(&host->sdio_suspend_wlock);
4317 if (plat->sdiowakeup_irq)
4318 free_irq(plat->sdiowakeup_irq, host);
4319 pio_irq_free:
4320 if (plat->sdiowakeup_irq)
4321 wake_lock_destroy(&host->sdio_wlock);
4322 free_irq(core_irqres->start, host);
4323 irq_free:
4324 free_irq(core_irqres->start, host);
4325 dml_exit:
4326 if (host->is_sps_mode)
4327 msmsdcc_dml_exit(host);
4328 sps_exit:
4329 if (host->is_sps_mode)
4330 msmsdcc_sps_exit(host);
4331 vreg_deinit:
4332 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004333 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004335 clk_put:
4336 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337 pclk_disable:
4338 if (!IS_ERR(host->pclk))
4339 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004340 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341 if (!IS_ERR(host->pclk))
4342 clk_put(host->pclk);
4343 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4344 clk_disable(host->dfab_pclk);
4345 dfab_pclk_put:
4346 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4347 clk_put(host->dfab_pclk);
4348 dma_free:
4349 if (host->is_dma_mode) {
4350 if (host->dmares)
4351 dma_free_coherent(NULL,
4352 sizeof(struct msmsdcc_nc_dmadata),
4353 host->dma.nc, host->dma.nc_busaddr);
4354 }
4355 ioremap_free:
4356 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004357 host_free:
4358 mmc_free_host(mmc);
4359 out:
4360 return ret;
4361}
4362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004363static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004364{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4366 struct mmc_platform_data *plat;
4367 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004369 if (!mmc)
4370 return -ENXIO;
4371
4372 if (pm_runtime_suspended(&(pdev)->dev))
4373 pm_runtime_resume(&(pdev)->dev);
4374
4375 host = mmc_priv(mmc);
4376
4377 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4378 plat = host->plat;
4379
4380 if (!plat->status_irq)
4381 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4382
4383 del_timer_sync(&host->req_tout_timer);
4384 tasklet_kill(&host->dma_tlet);
4385 tasklet_kill(&host->sps.tlet);
4386 mmc_remove_host(mmc);
4387
4388 if (plat->status_irq)
4389 free_irq(plat->status_irq, host);
4390
4391 wake_lock_destroy(&host->sdio_suspend_wlock);
4392 if (plat->sdiowakeup_irq) {
4393 wake_lock_destroy(&host->sdio_wlock);
4394 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4395 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004396 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004397
4398 free_irq(host->core_irqres->start, host);
4399 free_irq(host->core_irqres->start, host);
4400
4401 clk_put(host->clk);
4402 if (!IS_ERR(host->pclk))
4403 clk_put(host->pclk);
4404 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4405 clk_put(host->dfab_pclk);
4406
4407 msmsdcc_vreg_init(host, false);
4408
4409 if (host->is_dma_mode) {
4410 if (host->dmares)
4411 dma_free_coherent(NULL,
4412 sizeof(struct msmsdcc_nc_dmadata),
4413 host->dma.nc, host->dma.nc_busaddr);
4414 }
4415
4416 if (host->is_sps_mode) {
4417 msmsdcc_dml_exit(host);
4418 msmsdcc_sps_exit(host);
4419 }
4420
4421 iounmap(host->base);
4422 mmc_free_host(mmc);
4423
4424#ifdef CONFIG_HAS_EARLYSUSPEND
4425 unregister_early_suspend(&host->early_suspend);
4426#endif
4427 pm_runtime_disable(&(pdev)->dev);
4428 pm_runtime_set_suspended(&(pdev)->dev);
4429
4430 return 0;
4431}
4432
4433#ifdef CONFIG_MSM_SDIO_AL
4434int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4435{
4436 struct msmsdcc_host *host = mmc_priv(mmc);
4437 unsigned long flags;
4438
4439 spin_lock_irqsave(&host->lock, flags);
4440 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4441 enable ? "En" : "Dis");
4442
4443 if (enable) {
4444 if (!host->sdcc_irq_disabled) {
4445 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304446 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447 host->sdcc_irq_disabled = 1;
4448 }
4449
4450 if (host->clks_on) {
4451 msmsdcc_setup_clocks(host, false);
4452 host->clks_on = 0;
4453 }
4454
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304455 if (host->plat->sdio_lpm_gpio_setup &&
4456 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004457 spin_unlock_irqrestore(&host->lock, flags);
4458 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4459 spin_lock_irqsave(&host->lock, flags);
4460 host->sdio_gpio_lpm = 1;
4461 }
4462
4463 if (host->sdio_irq_disabled) {
4464 msmsdcc_enable_irq_wake(host);
4465 enable_irq(host->plat->sdiowakeup_irq);
4466 host->sdio_irq_disabled = 0;
4467 }
4468 } else {
4469 if (!host->sdio_irq_disabled) {
4470 disable_irq_nosync(host->plat->sdiowakeup_irq);
4471 host->sdio_irq_disabled = 1;
4472 msmsdcc_disable_irq_wake(host);
4473 }
4474
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304475 if (host->plat->sdio_lpm_gpio_setup &&
4476 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004477 spin_unlock_irqrestore(&host->lock, flags);
4478 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4479 spin_lock_irqsave(&host->lock, flags);
4480 host->sdio_gpio_lpm = 0;
4481 }
4482
4483 if (!host->clks_on) {
4484 msmsdcc_setup_clocks(host, true);
4485 host->clks_on = 1;
4486 }
4487
4488 if (host->sdcc_irq_disabled) {
4489 writel_relaxed(host->mci_irqenable,
4490 host->base + MMCIMASK0);
4491 mb();
4492 enable_irq(host->core_irqres->start);
4493 host->sdcc_irq_disabled = 0;
4494 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004495 }
4496 spin_unlock_irqrestore(&host->lock, flags);
4497 return 0;
4498}
4499#else
4500int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4501{
4502 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004503}
4504#endif
4505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004506#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004507static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004509{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004510 struct mmc_host *mmc = dev_get_drvdata(dev);
4511 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004512 int rc = 0;
4513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 if (host->plat->is_sdio_al_client)
4515 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304516 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004517 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004518 host->sdcc_suspending = 1;
4519 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004521 /*
4522 * If the clocks are already turned off by SDIO clients (as
4523 * part of LPM), then clocks should be turned on before
4524 * calling mmc_suspend_host() because mmc_suspend_host might
4525 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304526 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004527 * cards, clocks will be turned on before mmc_suspend_host
4528 * and turned off after mmc_suspend_host.
4529 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304530 if (mmc->card && mmc_card_sdio(mmc->card)) {
4531 mmc->ios.clock = host->clk_rate;
4532 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4533 }
San Mehat9d2bd732009-09-22 16:44:22 -07004534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004535 /*
4536 * MMC core thinks that host is disabled by now since
4537 * runtime suspend is scheduled after msmsdcc_disable()
4538 * is called. Thus, MMC core will try to enable the host
4539 * while suspending it. This results in a synchronous
4540 * runtime resume request while in runtime suspending
4541 * context and hence inorder to complete this resume
4542 * requet, it will wait for suspend to be complete,
4543 * but runtime suspend also can not proceed further
4544 * until the host is resumed. Thus, it leads to a hang.
4545 * Hence, increase the pm usage count before suspending
4546 * the host so that any resume requests after this will
4547 * simple become pm usage counter increment operations.
4548 */
4549 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304550 /* If there is pending detect work abort runtime suspend */
4551 if (unlikely(work_busy(&mmc->detect.work)))
4552 rc = -EAGAIN;
4553 else
4554 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004555 pm_runtime_put_noidle(dev);
4556
4557 if (!rc) {
4558 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4559 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4560 disable_irq(host->core_irqres->start);
4561 host->sdcc_irq_disabled = 1;
4562
4563 /*
4564 * If MMC core level suspend is not supported,
4565 * turn off clocks to allow deep sleep (TCXO
4566 * shutdown).
4567 */
4568 mmc->ios.clock = 0;
4569 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4570 enable_irq(host->core_irqres->start);
4571 host->sdcc_irq_disabled = 0;
4572
4573 if (host->plat->sdiowakeup_irq) {
4574 host->sdio_irq_disabled = 0;
4575 msmsdcc_enable_irq_wake(host);
4576 enable_irq(host->plat->sdiowakeup_irq);
4577 }
4578 }
4579 }
4580 host->sdcc_suspending = 0;
4581 mmc->suspend_task = NULL;
4582 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4583 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004584 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304585 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004586 return rc;
4587}
4588
4589static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004590msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004591{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004592 struct mmc_host *mmc = dev_get_drvdata(dev);
4593 struct msmsdcc_host *host = mmc_priv(mmc);
4594 unsigned long flags;
4595
4596 if (host->plat->is_sdio_al_client)
4597 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004598
Sahitya Tummala7661a452011-07-18 13:28:35 +05304599 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004600 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004601 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4602 if (host->sdcc_irq_disabled) {
4603 enable_irq(host->core_irqres->start);
4604 host->sdcc_irq_disabled = 0;
4605 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304606 mmc->ios.clock = host->clk_rate;
4607 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004608
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304609 spin_lock_irqsave(&host->lock, flags);
4610 writel_relaxed(host->mci_irqenable,
4611 host->base + MMCIMASK0);
4612 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004613
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304614 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4615 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616 if (host->plat->sdiowakeup_irq) {
4617 disable_irq_nosync(
4618 host->plat->sdiowakeup_irq);
4619 msmsdcc_disable_irq_wake(host);
4620 host->sdio_irq_disabled = 1;
4621 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304622 }
San Mehat9d2bd732009-09-22 16:44:22 -07004623
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304624 spin_unlock_irqrestore(&host->lock, flags);
4625 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004626
4627 mmc_resume_host(mmc);
4628
4629 /*
4630 * FIXME: Clearing of flags must be handled in clients
4631 * resume handler.
4632 */
4633 spin_lock_irqsave(&host->lock, flags);
4634 mmc->pm_flags = 0;
4635 spin_unlock_irqrestore(&host->lock, flags);
4636
4637 /*
4638 * After resuming the host wait for sometime so that
4639 * the SDIO work will be processed.
4640 */
4641 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4642 if ((host->plat->cfg_mpm_sdiowakeup ||
4643 host->plat->sdiowakeup_irq) &&
4644 wake_lock_active(&host->sdio_wlock))
4645 wake_lock_timeout(&host->sdio_wlock, 1);
4646 }
4647
4648 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004649 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304650 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004651 return 0;
4652}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004653
4654static int msmsdcc_runtime_idle(struct device *dev)
4655{
4656 struct mmc_host *mmc = dev_get_drvdata(dev);
4657 struct msmsdcc_host *host = mmc_priv(mmc);
4658
4659 if (host->plat->is_sdio_al_client)
4660 return 0;
4661
4662 /* Idle timeout is not configurable for now */
4663 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4664
4665 return -EAGAIN;
4666}
4667
4668static int msmsdcc_pm_suspend(struct device *dev)
4669{
4670 struct mmc_host *mmc = dev_get_drvdata(dev);
4671 struct msmsdcc_host *host = mmc_priv(mmc);
4672 int rc = 0;
4673
4674 if (host->plat->is_sdio_al_client)
4675 return 0;
4676
4677
4678 if (host->plat->status_irq)
4679 disable_irq(host->plat->status_irq);
4680
4681 if (!pm_runtime_suspended(dev))
4682 rc = msmsdcc_runtime_suspend(dev);
4683
4684 return rc;
4685}
4686
4687static int msmsdcc_pm_resume(struct device *dev)
4688{
4689 struct mmc_host *mmc = dev_get_drvdata(dev);
4690 struct msmsdcc_host *host = mmc_priv(mmc);
4691 int rc = 0;
4692
4693 if (host->plat->is_sdio_al_client)
4694 return 0;
4695
Sahitya Tummalafb486372011-09-02 19:01:49 +05304696 if (!pm_runtime_suspended(dev))
4697 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698 if (host->plat->status_irq) {
4699 msmsdcc_check_status((unsigned long)host);
4700 enable_irq(host->plat->status_irq);
4701 }
4702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004703 return rc;
4704}
4705
Daniel Walker08ecfde2010-06-23 12:32:20 -07004706#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004707#define msmsdcc_runtime_suspend NULL
4708#define msmsdcc_runtime_resume NULL
4709#define msmsdcc_runtime_idle NULL
4710#define msmsdcc_pm_suspend NULL
4711#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004712#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004714static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4715 .runtime_suspend = msmsdcc_runtime_suspend,
4716 .runtime_resume = msmsdcc_runtime_resume,
4717 .runtime_idle = msmsdcc_runtime_idle,
4718 .suspend = msmsdcc_pm_suspend,
4719 .resume = msmsdcc_pm_resume,
4720};
4721
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304722static const struct of_device_id msmsdcc_dt_match[] = {
4723 {.compatible = "qcom,msm-sdcc"},
4724
4725};
4726MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4727
San Mehat9d2bd732009-09-22 16:44:22 -07004728static struct platform_driver msmsdcc_driver = {
4729 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004730 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004731 .driver = {
4732 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004733 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304734 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004735 },
4736};
4737
4738static int __init msmsdcc_init(void)
4739{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740#if defined(CONFIG_DEBUG_FS)
4741 int ret = 0;
4742 ret = msmsdcc_dbg_init();
4743 if (ret) {
4744 pr_err("Failed to create debug fs dir \n");
4745 return ret;
4746 }
4747#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004748 return platform_driver_register(&msmsdcc_driver);
4749}
4750
4751static void __exit msmsdcc_exit(void)
4752{
4753 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754
4755#if defined(CONFIG_DEBUG_FS)
4756 debugfs_remove(debugfs_file);
4757 debugfs_remove(debugfs_dir);
4758#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004759}
4760
4761module_init(msmsdcc_init);
4762module_exit(msmsdcc_exit);
4763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004765MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004766
4767#if defined(CONFIG_DEBUG_FS)
4768
4769static int
4770msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4771{
4772 file->private_data = inode->i_private;
4773 return 0;
4774}
4775
4776static ssize_t
4777msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4778 size_t count, loff_t *ppos)
4779{
4780 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004781 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782 int max, i;
4783
4784 i = 0;
4785 max = sizeof(buf) - 1;
4786
4787 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4788 host->curr.cmd, host->curr.data);
4789 if (host->curr.cmd) {
4790 struct mmc_command *cmd = host->curr.cmd;
4791
4792 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4793 cmd->opcode, cmd->arg, cmd->flags);
4794 }
4795 if (host->curr.data) {
4796 struct mmc_data *data = host->curr.data;
4797 i += scnprintf(buf + i, max - i,
4798 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4799 data->timeout_ns, data->timeout_clks,
4800 data->blksz, data->blocks, data->error,
4801 data->flags);
4802 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4803 host->curr.xfer_size, host->curr.xfer_remain,
4804 host->curr.data_xfered, host->dma.sg);
4805 }
4806
4807 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4808}
4809
4810static const struct file_operations msmsdcc_dbg_state_ops = {
4811 .read = msmsdcc_dbg_state_read,
4812 .open = msmsdcc_dbg_state_open,
4813};
4814
4815static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4816{
4817 if (debugfs_dir) {
4818 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4819 0644, debugfs_dir, host,
4820 &msmsdcc_dbg_state_ops);
4821 }
4822}
4823
4824static int __init msmsdcc_dbg_init(void)
4825{
4826 int err;
4827
4828 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4829 if (IS_ERR(debugfs_dir)) {
4830 err = PTR_ERR(debugfs_dir);
4831 debugfs_dir = NULL;
4832 return err;
4833 }
4834
4835 return 0;
4836}
4837#endif