blob: fa91b533f9a70ea82809bc4d254861127820529c [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
San Mehat9d2bd732009-09-22 16:44:22 -070079static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081static struct mmc_command dummy52cmd;
82static struct mmc_request dummy52mrq = {
83 .cmd = &dummy52cmd,
84 .data = NULL,
85 .stop = NULL,
86};
87static struct mmc_command dummy52cmd = {
88 .opcode = SD_IO_RW_DIRECT,
89 .flags = MMC_RSP_PRESENT,
90 .data = NULL,
91 .mrq = &dummy52mrq,
92};
93/*
94 * An array holding the Tuning pattern to compare with when
95 * executing a tuning cycle.
96 */
97static const u32 cmd19_tuning_block[16] = {
98 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
99 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
100 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
101 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
102};
San Mehat865c8062009-11-13 13:42:06 -0800103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104#if IRQ_DEBUG == 1
105static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
106 "dattimeout", "txunderrun", "rxoverrun",
107 "cmdrespend", "cmdsent", "dataend", NULL,
108 "datablkend", "cmdactive", "txactive",
109 "rxactive", "txhalfempty", "rxhalffull",
110 "txfifofull", "rxfifofull", "txfifoempty",
111 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
112 "sdiointr", "progdone", "atacmdcompl",
113 "sdiointrope", "ccstimeout", NULL, NULL,
114 NULL, NULL, NULL };
115
116static void
117msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800118{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
122 for (i = 0; i < 32; i++) {
123 if (status & (1 << i))
124 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800125 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800127}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128#endif
San Mehat865c8062009-11-13 13:42:06 -0800129
San Mehat9d2bd732009-09-22 16:44:22 -0700130static void
131msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
132 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530133static inline void msmsdcc_delay(struct msmsdcc_host *host);
134
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530135static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
136{
137 unsigned short ret = NR_SG;
138
139 if (host->is_sps_mode) {
140 if (NR_SG > MAX_NR_SG_SPS)
141 ret = MAX_NR_SG_SPS;
142 } else { /* DMA or PIO mode */
143 if (NR_SG > MAX_NR_SG_DMA_PIO)
144 ret = MAX_NR_SG_DMA_PIO;
145 }
146
147 return ret;
148}
149
150static inline unsigned int msmsdcc_get_max_seg_size(struct msmsdcc_host *host)
151{
152 unsigned int max_seg_size;
153
154 /*
155 * SPS BAM has limitation of max. number of descriptors.
156 * max. # of descriptors = SPS_MAX_DESCS
157 * each descriptor can point to SPS_MAX_DESC_SIZE (16KB)
158 * So (nr_sg * max_seg_size) should be limited to the
159 * max. size that all of the descriptors can point to.
160 * i.e., (nr_sg * max_seg_size) = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE).
161 */
162 if (host->is_sps_mode) {
163 max_seg_size = (SPS_MAX_DESCS * SPS_MAX_DESC_SIZE) /
164 msmsdcc_get_nr_sg(host);
165 } else { /* DMA or PIO mode */
166 max_seg_size = MMC_MAX_REQ_SIZE;
167 }
168
169 return max_seg_size;
170}
San Mehat9d2bd732009-09-22 16:44:22 -0700171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
173static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
174 struct msmsdcc_sps_ep_conn_data *ep);
175static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
176 struct msmsdcc_sps_ep_conn_data *ep);
177#else
178static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
179 struct msmsdcc_sps_ep_conn_data *ep,
180 bool is_producer) { return 0; }
181static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
182 struct msmsdcc_sps_ep_conn_data *ep) { }
183static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
184 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530185{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 return 0;
187}
188static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
189 struct msmsdcc_sps_ep_conn_data *ep)
190{
191 return 0;
192}
193static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
194static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
195#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530198 * Apply soft reset to all SDCC BAM pipes
199 *
200 * This function applies soft reset to SDCC BAM pipe.
201 *
202 * This function should be called to recover from error
203 * conditions encountered during CMD/DATA tranfsers with card.
204 *
205 * @host - Pointer to driver's host structure
206 *
207 */
208static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
209{
210 int rc;
211
212 /* Reset all SDCC BAM pipes */
213 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
214 if (rc)
215 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
216 mmc_hostname(host->mmc), rc);
217 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
218 if (rc)
219 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
220 mmc_hostname(host->mmc), rc);
221
222 /* Restore all BAM pipes connections */
223 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
224 if (rc)
225 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
226 mmc_hostname(host->mmc), rc);
227 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
228 if (rc)
229 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
230 mmc_hostname(host->mmc), rc);
231}
232
233/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 * Apply soft reset
235 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530236 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 *
238 * This function should be called to recover from error
239 * conditions encountered with CMD/DATA tranfsers with card.
240 *
241 * Soft reset should only be used with SDCC controller v4.
242 *
243 * @host - Pointer to driver's host structure
244 *
245 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530246static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 /*
249 * Reset SDCC controller's DPSM (data path state machine
250 * and CPSM (command path state machine).
251 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530253 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530255 msmsdcc_delay(host);
256}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530257
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530258static void msmsdcc_hard_reset(struct msmsdcc_host *host)
259{
260 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530261
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530262 /* Reset the controller */
263 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
264 if (ret)
265 pr_err("%s: Clock assert failed at %u Hz"
266 " with err %d\n", mmc_hostname(host->mmc),
267 host->clk_rate, ret);
268
269 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
270 if (ret)
271 pr_err("%s: Clock deassert failed at %u Hz"
272 " with err %d\n", mmc_hostname(host->mmc),
273 host->clk_rate, ret);
274
275 /* Give some delay for clock reset to propogate to controller */
276 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530277}
278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
280{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530281 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530282 if (host->is_sps_mode) {
283 /* Reset DML first */
284 msmsdcc_dml_reset(host);
285 /*
286 * delay the SPS pipe reset in thread context as
287 * sps_connect/sps_disconnect APIs can be called
288 * only from non-atomic context.
289 */
290 host->sps.pipe_reset_pending = true;
291 }
292 mb();
293 msmsdcc_soft_reset(host);
294
295 pr_debug("%s: Applied soft reset to Controller\n",
296 mmc_hostname(host->mmc));
297
298 if (host->is_sps_mode)
299 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 } else {
301 /* Give Clock reset (hard reset) to controller */
302 u32 mci_clk = 0;
303 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304
305 /* Save the controller state */
306 mci_clk = readl_relaxed(host->base + MMCICLOCK);
307 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530310 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 pr_debug("%s: Controller has been reinitialized\n",
312 mmc_hostname(host->mmc));
313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 /* Restore the contoller state */
315 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530316 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530318 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530320 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530322
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700323 if (host->dummy_52_needed)
324 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325}
326
327static int
San Mehat9d2bd732009-09-22 16:44:22 -0700328msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
329{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 int retval = 0;
331
San Mehat9d2bd732009-09-22 16:44:22 -0700332 BUG_ON(host->curr.data);
333
334 host->curr.mrq = NULL;
335 host->curr.cmd = NULL;
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 del_timer(&host->req_tout_timer);
338
San Mehat9d2bd732009-09-22 16:44:22 -0700339 if (mrq->data)
340 mrq->data->bytes_xfered = host->curr.data_xfered;
341 if (mrq->cmd->error == -ETIMEDOUT)
342 mdelay(5);
343
344 /*
345 * Need to drop the host lock here; mmc_request_done may call
346 * back into the driver...
347 */
348 spin_unlock(&host->lock);
349 mmc_request_done(host->mmc, mrq);
350 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351
352 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700353}
354
355static void
356msmsdcc_stop_data(struct msmsdcc_host *host)
357{
San Mehat9d2bd732009-09-22 16:44:22 -0700358 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530359 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530360 host->curr.wait_for_auto_prog_done = 0;
361 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700362 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
363 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700364 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700365}
366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700368{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369 return host->core_memres->start + MMCIFIFO;
370}
371
372static inline unsigned int msmsdcc_get_min_sup_clk_rate(
373 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375static inline void msmsdcc_delay(struct msmsdcc_host *host)
376{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530377 ktime_t start, diff;
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530380 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530381
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530382 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530383 (readl_relaxed(host->base + MCI_STATUS2) &
384 MCI_MCLK_REG_WR_ACTIVE)) {
385 start = ktime_get();
386 while (readl_relaxed(host->base + MCI_STATUS2) &
387 MCI_MCLK_REG_WR_ACTIVE) {
388 diff = ktime_sub(ktime_get(), start);
389 /* poll for max. 1 ms */
390 if (ktime_to_us(diff) > 1000) {
391 pr_warning("%s: previous reg. write is"
392 " still active\n",
393 mmc_hostname(host->mmc));
394 break;
395 }
396 }
397 }
San Mehat9d2bd732009-09-22 16:44:22 -0700398}
399
San Mehat56a8b5b2009-11-21 12:29:46 -0800400static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
402{
403 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530405 /*
406 * As after sending the command, we don't write any of the
407 * controller registers and just wait for the
408 * CMD_RESPOND_END/CMD_SENT/Command failure notication
409 * from Controller.
410 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800412}
413
414static void
415msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
416{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
420 writel_relaxed((unsigned int)host->curr.xfer_size,
421 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
423 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800424
San Mehat6ac9ea62009-12-02 17:24:58 -0800425 if (host->cmd_cmd) {
426 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800428 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800429}
430
San Mehat9d2bd732009-09-22 16:44:22 -0700431static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530432msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700433{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530434 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700435 unsigned long flags;
436 struct mmc_request *mrq;
437
438 spin_lock_irqsave(&host->lock, flags);
439 mrq = host->curr.mrq;
440 BUG_ON(!mrq);
441
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530442 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700443 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700444 goto out;
445 }
446
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530447 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700448 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700450 } else {
451 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700453 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530454 mmc_hostname(host->mmc), host->dma.result);
455 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700456 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530457 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530458 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 host->dma.err.flush[0], host->dma.err.flush[1],
460 host->dma.err.flush[2], host->dma.err.flush[3],
461 host->dma.err.flush[4],
462 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530463 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700464 if (!mrq->data->error)
465 mrq->data->error = -EIO;
466 }
San Mehat9d2bd732009-09-22 16:44:22 -0700467 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
468 host->dma.dir);
469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 if (host->curr.user_pages) {
471 struct scatterlist *sg = host->dma.sg;
472 int i;
473
474 for (i = 0; i < host->dma.num_ents; i++, sg++)
475 flush_dcache_page(sg_page(sg));
476 }
477
San Mehat9d2bd732009-09-22 16:44:22 -0700478 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800479 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700480
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530481 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
482 (host->curr.wait_for_auto_prog_done &&
483 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700484 /*
485 * If we've already gotten our DATAEND / DATABLKEND
486 * for this request, then complete it through here.
487 */
San Mehat9d2bd732009-09-22 16:44:22 -0700488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700490 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 host->curr.xfer_remain -= host->curr.xfer_size;
492 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700493 if (host->dummy_52_needed) {
494 mrq->data->bytes_xfered = host->curr.data_xfered;
495 host->dummy_52_sent = 1;
496 msmsdcc_start_command(host, &dummy52cmd,
497 MCI_CPSM_PROGENA);
498 goto out;
499 }
500 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530501 if (!mrq->data->stop || mrq->cmd->error ||
502 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700503 host->curr.mrq = NULL;
504 host->curr.cmd = NULL;
505 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700507 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
San Mehat9d2bd732009-09-22 16:44:22 -0700509 mmc_request_done(host->mmc, mrq);
510 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530511 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
512 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700513 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530514 }
San Mehat9d2bd732009-09-22 16:44:22 -0700515 }
516
517out:
518 spin_unlock_irqrestore(&host->lock, flags);
519 return;
520}
521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
523/**
524 * Callback notification from SPS driver
525 *
526 * This callback function gets triggered called from
527 * SPS driver when requested SPS data transfer is
528 * completed.
529 *
530 * SPS driver invokes this callback in BAM irq context so
531 * SDCC driver schedule a tasklet for further processing
532 * this callback notification at later point of time in
533 * tasklet context and immediately returns control back
534 * to SPS driver.
535 *
536 * @nofity - Pointer to sps event notify sturcture
537 *
538 */
539static void
540msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
541{
542 struct msmsdcc_host *host =
543 (struct msmsdcc_host *)
544 ((struct sps_event_notify *)notify)->user;
545
546 host->sps.notify = *notify;
547 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
548 mmc_hostname(host->mmc), __func__, notify->event_id,
549 notify->data.transfer.iovec.addr,
550 notify->data.transfer.iovec.size,
551 notify->data.transfer.iovec.flags);
552 /* Schedule a tasklet for completing data transfer */
553 tasklet_schedule(&host->sps.tlet);
554}
555
556/**
557 * Tasklet handler for processing SPS callback event
558 *
559 * This function processing SPS event notification and
560 * checks if the SPS transfer is completed or not and
561 * then accordingly notifies status to MMC core layer.
562 *
563 * This function is called in tasklet context.
564 *
565 * @data - Pointer to sdcc driver data
566 *
567 */
568static void msmsdcc_sps_complete_tlet(unsigned long data)
569{
570 unsigned long flags;
571 int i, rc;
572 u32 data_xfered = 0;
573 struct mmc_request *mrq;
574 struct sps_iovec iovec;
575 struct sps_pipe *sps_pipe_handle;
576 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
577 struct sps_event_notify *notify = &host->sps.notify;
578
579 spin_lock_irqsave(&host->lock, flags);
580 if (host->sps.dir == DMA_FROM_DEVICE)
581 sps_pipe_handle = host->sps.prod.pipe_handle;
582 else
583 sps_pipe_handle = host->sps.cons.pipe_handle;
584 mrq = host->curr.mrq;
585
586 if (!mrq) {
587 spin_unlock_irqrestore(&host->lock, flags);
588 return;
589 }
590
591 pr_debug("%s: %s: sps event_id=%d\n",
592 mmc_hostname(host->mmc), __func__,
593 notify->event_id);
594
595 if (msmsdcc_is_dml_busy(host)) {
596 /* oops !!! this should never happen. */
597 pr_err("%s: %s: Received SPS EOT event"
598 " but DML HW is still busy !!!\n",
599 mmc_hostname(host->mmc), __func__);
600 }
601 /*
602 * Got End of transfer event!!! Check if all of the data
603 * has been transferred?
604 */
605 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
606 rc = sps_get_iovec(sps_pipe_handle, &iovec);
607 if (rc) {
608 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
609 mmc_hostname(host->mmc), __func__, rc, i);
610 break;
611 }
612 data_xfered += iovec.size;
613 }
614
615 if (data_xfered == host->curr.xfer_size) {
616 host->curr.data_xfered = host->curr.xfer_size;
617 host->curr.xfer_remain -= host->curr.xfer_size;
618 pr_debug("%s: Data xfer success. data_xfered=0x%x",
619 mmc_hostname(host->mmc),
620 host->curr.xfer_size);
621 } else {
622 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
623 " xfer_size=%d", mmc_hostname(host->mmc),
624 data_xfered, host->curr.xfer_size);
625 msmsdcc_reset_and_restore(host);
626 if (!mrq->data->error)
627 mrq->data->error = -EIO;
628 }
629
630 /* Unmap sg buffers */
631 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
632 host->sps.dir);
633
634 host->sps.sg = NULL;
635 host->sps.busy = 0;
636
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530637 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
638 (host->curr.wait_for_auto_prog_done &&
639 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 /*
641 * If we've already gotten our DATAEND / DATABLKEND
642 * for this request, then complete it through here.
643 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644
645 if (!mrq->data->error) {
646 host->curr.data_xfered = host->curr.xfer_size;
647 host->curr.xfer_remain -= host->curr.xfer_size;
648 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700649 if (host->dummy_52_needed) {
650 mrq->data->bytes_xfered = host->curr.data_xfered;
651 host->dummy_52_sent = 1;
652 msmsdcc_start_command(host, &dummy52cmd,
653 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700654 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700655 return;
656 }
657 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530658 if (!mrq->data->stop || mrq->cmd->error ||
659 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660 host->curr.mrq = NULL;
661 host->curr.cmd = NULL;
662 mrq->data->bytes_xfered = host->curr.data_xfered;
663 del_timer(&host->req_tout_timer);
664 spin_unlock_irqrestore(&host->lock, flags);
665
666 mmc_request_done(host->mmc, mrq);
667 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530668 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
669 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670 msmsdcc_start_command(host, mrq->data->stop, 0);
671 }
672 }
673 spin_unlock_irqrestore(&host->lock, flags);
674}
675
676/**
677 * Exit from current SPS data transfer
678 *
679 * This function exits from current SPS data transfer.
680 *
681 * This function should be called when error condition
682 * is encountered during data transfer.
683 *
684 * @host - Pointer to sdcc host structure
685 *
686 */
687static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
688{
689 struct mmc_request *mrq;
690
691 mrq = host->curr.mrq;
692 BUG_ON(!mrq);
693
694 msmsdcc_reset_and_restore(host);
695 if (!mrq->data->error)
696 mrq->data->error = -EIO;
697
698 /* Unmap sg buffers */
699 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
700 host->sps.dir);
701
702 host->sps.sg = NULL;
703 host->sps.busy = 0;
704 if (host->curr.data)
705 msmsdcc_stop_data(host);
706
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530707 if (!mrq->data->stop || mrq->cmd->error ||
708 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530710 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
711 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712 msmsdcc_start_command(host, mrq->data->stop, 0);
713
714}
715#else
716static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
717static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
718static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
719#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
720
721static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
722
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530723static void
724msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
725 unsigned int result,
726 struct msm_dmov_errdata *err)
727{
728 struct msmsdcc_dma_data *dma_data =
729 container_of(cmd, struct msmsdcc_dma_data, hdr);
730 struct msmsdcc_host *host = dma_data->host;
731
732 dma_data->result = result;
733 if (err)
734 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
735
736 tasklet_schedule(&host->dma_tlet);
737}
738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700740{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
742 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700743 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 else
745 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700746}
747
748static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
749{
750 struct msmsdcc_nc_dmadata *nc;
751 dmov_box *box;
752 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700753 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530754 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700755 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530756 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700757
Krishna Konda25786ec2011-07-25 16:21:36 -0700758 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700759 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700760
Krishna Konda25786ec2011-07-25 16:21:36 -0700761 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
762
San Mehat9d2bd732009-09-22 16:44:22 -0700763 host->dma.sg = data->sg;
764 host->dma.num_ents = data->sg_len;
765
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530766 /* Prevent memory corruption */
767 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800768
San Mehat9d2bd732009-09-22 16:44:22 -0700769 nc = host->dma.nc;
770
San Mehat9d2bd732009-09-22 16:44:22 -0700771 if (data->flags & MMC_DATA_READ)
772 host->dma.dir = DMA_FROM_DEVICE;
773 else
774 host->dma.dir = DMA_TO_DEVICE;
775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
777 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778
779 if (n != host->dma.num_ents) {
780 pr_err("%s: Unable to map in all sg elements\n",
781 mmc_hostname(host->mmc));
782 host->dma.sg = NULL;
783 host->dma.num_ents = 0;
784 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800785 }
San Mehat9d2bd732009-09-22 16:44:22 -0700786
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530787 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
788 host->curr.user_pages = 0;
789 box = &nc->cmd[0];
790 for (i = 0; i < host->dma.num_ents; i++) {
791 len = sg_dma_len(sg);
792 offset = 0;
793
794 do {
795 /* Check if we can do DMA */
796 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
797 err = -ENOTSUPP;
798 goto unmap;
799 }
800
801 box->cmd = CMD_MODE_BOX;
802
803 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
804 len = MMC_MAX_DMA_BOX_LENGTH;
805 len -= len % data->blksz;
806 }
807 rows = (len % MCI_FIFOSIZE) ?
808 (len / MCI_FIFOSIZE) + 1 :
809 (len / MCI_FIFOSIZE);
810
811 if (data->flags & MMC_DATA_READ) {
812 box->src_row_addr = msmsdcc_fifo_addr(host);
813 box->dst_row_addr = sg_dma_address(sg) + offset;
814 box->src_dst_len = (MCI_FIFOSIZE << 16) |
815 (MCI_FIFOSIZE);
816 box->row_offset = MCI_FIFOSIZE;
817 box->num_rows = rows * ((1 << 16) + 1);
818 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
819 } else {
820 box->src_row_addr = sg_dma_address(sg) + offset;
821 box->dst_row_addr = msmsdcc_fifo_addr(host);
822 box->src_dst_len = (MCI_FIFOSIZE << 16) |
823 (MCI_FIFOSIZE);
824 box->row_offset = (MCI_FIFOSIZE << 16);
825 box->num_rows = rows * ((1 << 16) + 1);
826 box->cmd |= CMD_DST_CRCI(host->dma.crci);
827 }
828
829 offset += len;
830 len = sg_dma_len(sg) - offset;
831 box++;
832 box_cmd_cnt++;
833 } while (len);
834 sg++;
835 }
836 /* Mark last command */
837 box--;
838 box->cmd |= CMD_LC;
839
840 /* location of command block must be 64 bit aligned */
841 BUG_ON(host->dma.cmd_busaddr & 0x07);
842
843 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
844 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
845 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
846 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
847
848 /* Flush all data to memory before starting dma */
849 mb();
850
851unmap:
852 if (err) {
853 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
854 host->dma.num_ents, host->dma.dir);
855 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
856 mmc_hostname(host->mmc), err);
857 }
858
859 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700860}
861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
863/**
864 * Submits data transfer request to SPS driver
865 *
866 * This function make sg (scatter gather) data buffers
867 * DMA ready and then submits them to SPS driver for
868 * transfer.
869 *
870 * @host - Pointer to sdcc host structure
871 * @data - Pointer to mmc_data structure
872 *
873 * @return 0 if success else negative value
874 */
875static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
876 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800877{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 int rc = 0;
879 u32 flags;
880 int i;
881 u32 addr, len, data_cnt;
882 struct scatterlist *sg = data->sg;
883 struct sps_pipe *sps_pipe_handle;
884
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530885 /* Prevent memory corruption */
886 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887
888 host->sps.sg = data->sg;
889 host->sps.num_ents = data->sg_len;
890 host->sps.xfer_req_cnt = 0;
891 if (data->flags & MMC_DATA_READ) {
892 host->sps.dir = DMA_FROM_DEVICE;
893 sps_pipe_handle = host->sps.prod.pipe_handle;
894 } else {
895 host->sps.dir = DMA_TO_DEVICE;
896 sps_pipe_handle = host->sps.cons.pipe_handle;
897 }
898
899 /* Make sg buffers DMA ready */
900 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
901 host->sps.dir);
902
903 if (rc != data->sg_len) {
904 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
905 mmc_hostname(host->mmc), rc);
906 host->sps.sg = NULL;
907 host->sps.num_ents = 0;
908 rc = -ENOMEM;
909 goto dma_map_err;
910 }
911
912 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
913 mmc_hostname(host->mmc), __func__,
914 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
915 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
916
917 for (i = 0; i < data->sg_len; i++) {
918 /*
919 * Check if this is the last buffer to transfer?
920 * If yes then set the INT and EOT flags.
921 */
922 len = sg_dma_len(sg);
923 addr = sg_dma_address(sg);
924 flags = 0;
925 while (len > 0) {
926 if (len > SPS_MAX_DESC_SIZE) {
927 data_cnt = SPS_MAX_DESC_SIZE;
928 } else {
929 data_cnt = len;
930 if (i == data->sg_len - 1)
931 flags = SPS_IOVEC_FLAG_INT |
932 SPS_IOVEC_FLAG_EOT;
933 }
934 rc = sps_transfer_one(sps_pipe_handle, addr,
935 data_cnt, host, flags);
936 if (rc) {
937 pr_err("%s: sps_transfer_one() error! rc=%d,"
938 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
939 mmc_hostname(host->mmc), rc,
940 (u32)sps_pipe_handle, (u32)sg, i);
941 goto dma_map_err;
942 }
943 addr += data_cnt;
944 len -= data_cnt;
945 host->sps.xfer_req_cnt++;
946 }
947 sg++;
948 }
949 goto out;
950
951dma_map_err:
952 /* unmap sg buffers */
953 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
954 host->sps.dir);
955out:
956 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700957}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958#else
959static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
960 struct mmc_data *data) { return 0; }
961#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700962
963static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800964msmsdcc_start_command_deferred(struct msmsdcc_host *host,
965 struct mmc_command *cmd, u32 *c)
966{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 DBG(host, "op %02x arg %08x flags %08x\n",
968 cmd->opcode, cmd->arg, cmd->flags);
969
San Mehat56a8b5b2009-11-21 12:29:46 -0800970 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
971
972 if (cmd->flags & MMC_RSP_PRESENT) {
973 if (cmd->flags & MMC_RSP_136)
974 *c |= MCI_CPSM_LONGRSP;
975 *c |= MCI_CPSM_RESPONSE;
976 }
977
978 if (/*interrupt*/0)
979 *c |= MCI_CPSM_INTERRUPT;
980
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530981 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
982 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
983 cmd->opcode == MMC_WRITE_BLOCK ||
984 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
985 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800986 *c |= MCI_CSPM_DATCMD;
987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530989 if (host->tuning_needed) {
990 /*
991 * For open ended block read operation (without CMD23),
992 * AUTO_CMD19 bit should be set while sending the READ command.
993 * For close ended block read operation (with CMD23),
994 * AUTO_CMD19 bit should be set while sending CMD23.
995 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530996 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
997 host->curr.mrq->cmd->opcode ==
998 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530999 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +05301000 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
1001 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301002 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1003 *c |= MCI_CSPM_AUTO_CMD19;
1004 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 }
1006
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301007 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301008 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301010 }
1011
San Mehat56a8b5b2009-11-21 12:29:46 -08001012 if (cmd == cmd->mrq->stop)
1013 *c |= MCI_CSPM_MCIABORT;
1014
San Mehat56a8b5b2009-11-21 12:29:46 -08001015 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 pr_err("%s: Overlapping command requests\n",
1017 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001018 }
1019 host->curr.cmd = cmd;
1020}
1021
1022static void
1023msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1024 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001025{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301026 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001027 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001029 unsigned int pio_irqmask = 0;
1030
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301031 BUG_ON(!data->sg);
1032 BUG_ON(!data->sg_len);
1033
San Mehat9d2bd732009-09-22 16:44:22 -07001034 host->curr.data = data;
1035 host->curr.xfer_size = data->blksz * data->blocks;
1036 host->curr.xfer_remain = host->curr.xfer_size;
1037 host->curr.data_xfered = 0;
1038 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301039 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001040
1041 memset(&host->pio, 0, sizeof(host->pio));
1042
San Mehat9d2bd732009-09-22 16:44:22 -07001043 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1044
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301045 if (host->curr.wait_for_auto_prog_done)
1046 datactrl |= MCI_AUTO_PROG_DONE;
1047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 if (!msmsdcc_check_dma_op_req(data)) {
1049 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1050 datactrl |= MCI_DPSM_DMAENABLE;
1051 } else if (host->is_sps_mode) {
1052 if (!msmsdcc_is_dml_busy(host)) {
1053 if (!msmsdcc_sps_start_xfer(host, data)) {
1054 /* Now kick start DML transfer */
1055 mb();
1056 msmsdcc_dml_start_xfer(host, data);
1057 datactrl |= MCI_DPSM_DMAENABLE;
1058 host->sps.busy = 1;
1059 }
1060 } else {
1061 /*
1062 * Can't proceed with new transfer as
1063 * previous trasnfer is already in progress.
1064 * There is no point of going into PIO mode
1065 * as well. Is this a time to do kernel panic?
1066 */
1067 pr_err("%s: %s: DML HW is busy!!!"
1068 " Can't perform new SPS transfers"
1069 " now\n", mmc_hostname(host->mmc),
1070 __func__);
1071 }
1072 }
1073 }
1074
1075 /* Is data transfer in PIO mode required? */
1076 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001077 host->pio.sg = data->sg;
1078 host->pio.sg_len = data->sg_len;
1079 host->pio.sg_off = 0;
1080
1081 if (data->flags & MMC_DATA_READ) {
1082 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1083 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1084 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1085 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1087 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001088 }
1089
1090 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301091 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001092
San Mehat56a8b5b2009-11-21 12:29:46 -08001093 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001095 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001096
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1098 /* Use ADM (Application Data Mover) HW for Data transfer */
1099 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001100 host->cmd_timeout = timeout;
1101 host->cmd_pio_irqmask = pio_irqmask;
1102 host->cmd_datactrl = datactrl;
1103 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1106 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001107 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001108
1109 if (cmd) {
1110 msmsdcc_start_command_deferred(host, cmd, &c);
1111 host->cmd_c = c;
1112 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1114 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1115 host->base + MMCIMASK0);
1116 mb();
1117 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001118 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1125 (~(MCI_IRQ_PIO))) | pio_irqmask,
1126 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301128 /*
1129 * We don't need delay after writing to DATA_CTRL register
1130 * if we are not writing to CMD register immediately after
1131 * this. As we already have delay before sending the
1132 * command, we just need mb() here.
1133 */
1134 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001135
1136 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001138 /* Daisy-chain the command if requested */
1139 msmsdcc_start_command(host, cmd, c);
1140 }
San Mehat9d2bd732009-09-22 16:44:22 -07001141 }
1142}
1143
1144static void
1145msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1146{
San Mehat56a8b5b2009-11-21 12:29:46 -08001147 msmsdcc_start_command_deferred(host, cmd, &c);
1148 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001149}
1150
1151static void
1152msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1153 unsigned int status)
1154{
1155 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1157 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1158 pr_err("%s: Data CRC error\n",
1159 mmc_hostname(host->mmc));
1160 pr_err("%s: opcode 0x%.8x\n", __func__,
1161 data->mrq->cmd->opcode);
1162 pr_err("%s: blksz %d, blocks %d\n", __func__,
1163 data->blksz, data->blocks);
1164 data->error = -EILSEQ;
1165 }
San Mehat9d2bd732009-09-22 16:44:22 -07001166 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 /* CRC is optional for the bus test commands, not all
1168 * cards respond back with CRC. However controller
1169 * waits for the CRC and times out. Hence ignore the
1170 * data timeouts during the Bustest.
1171 */
1172 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1173 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1174 pr_err("%s: Data timeout\n",
1175 mmc_hostname(host->mmc));
1176 data->error = -ETIMEDOUT;
1177 }
San Mehat9d2bd732009-09-22 16:44:22 -07001178 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001179 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001180 data->error = -EIO;
1181 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001182 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001183 data->error = -EIO;
1184 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001185 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001187 data->error = -EIO;
1188 }
San Mehat9d2bd732009-09-22 16:44:22 -07001189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001191 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 host->dummy_52_needed = 0;
1193}
San Mehat9d2bd732009-09-22 16:44:22 -07001194
1195static int
1196msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1197{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001199 uint32_t *ptr = (uint32_t *) buffer;
1200 int count = 0;
1201
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301202 if (remain % 4)
1203 remain = ((remain >> 2) + 1) << 2;
1204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1206
1207 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001208 ptr++;
1209 count += sizeof(uint32_t);
1210
1211 remain -= sizeof(uint32_t);
1212 if (remain == 0)
1213 break;
1214 }
1215 return count;
1216}
1217
1218static int
1219msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001221{
1222 void __iomem *base = host->base;
1223 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 while (readl_relaxed(base + MMCISTATUS) &
1227 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1228 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001229
San Mehat9d2bd732009-09-22 16:44:22 -07001230 count = min(remain, maxcnt);
1231
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301232 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1233 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001234 ptr += count;
1235 remain -= count;
1236
1237 if (remain == 0)
1238 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 }
1240 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001241
1242 return ptr - buffer;
1243}
1244
San Mehat1cd22962010-02-03 12:59:29 -08001245static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001246msmsdcc_pio_irq(int irq, void *dev_id)
1247{
1248 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001250 uint32_t status;
1251
Murali Palnati36448a42011-09-02 15:06:18 +05301252 spin_lock(&host->lock);
1253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301257 (MCI_IRQ_PIO)) == 0) {
1258 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301260 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261
1262#if IRQ_DEBUG
1263 msmsdcc_print_status(host, "irq1-r", status);
1264#endif
1265
San Mehat9d2bd732009-09-22 16:44:22 -07001266 do {
1267 unsigned long flags;
1268 unsigned int remain, len;
1269 char *buffer;
1270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1272 | MCI_RXDATAAVLBL)))
1273 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001274
1275 /* Map the current scatter buffer */
1276 local_irq_save(flags);
1277 buffer = kmap_atomic(sg_page(host->pio.sg),
1278 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1279 buffer += host->pio.sg_off;
1280 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281
San Mehat9d2bd732009-09-22 16:44:22 -07001282 len = 0;
1283 if (status & MCI_RXACTIVE)
1284 len = msmsdcc_pio_read(host, buffer, remain);
1285 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001287
1288 /* Unmap the buffer */
1289 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1290 local_irq_restore(flags);
1291
1292 host->pio.sg_off += len;
1293 host->curr.xfer_remain -= len;
1294 host->curr.data_xfered += len;
1295 remain -= len;
1296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 if (remain) /* Done with this page? */
1298 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 if (status & MCI_RXACTIVE && host->curr.user_pages)
1301 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 if (!--host->pio.sg_len) {
1304 memset(&host->pio, 0, sizeof(host->pio));
1305 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001306 }
1307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 /* Advance to next sg */
1309 host->pio.sg++;
1310 host->pio.sg_off = 0;
1311
1312 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001313 } while (1);
1314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1316 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1317 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1318 host->base + MMCIMASK0);
1319 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301320 /*
1321 * back to back write to MASK0 register don't need
1322 * synchronization delay.
1323 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1325 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1326 }
1327 mb();
1328 } else if (!host->curr.xfer_remain) {
1329 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1330 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1331 mb();
1332 }
San Mehat9d2bd732009-09-22 16:44:22 -07001333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001335
1336 return IRQ_HANDLED;
1337}
1338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339static void
1340msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1341
1342static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1343 struct mmc_data *data)
1344{
1345 u32 loop_cnt = 0;
1346
1347 /*
1348 * For read commands with data less than fifo size, it is possible to
1349 * get DATAEND first and RXDATA_AVAIL might be set later because of
1350 * synchronization delay through the asynchronous RX FIFO. Thus, for
1351 * such cases, even after DATAEND interrupt is received software
1352 * should poll for RXDATA_AVAIL until the requested data is read out
1353 * of FIFO. This change is needed to get around this abnormal but
1354 * sometimes expected behavior of SDCC3 controller.
1355 *
1356 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1357 * after the data is loaded into RX FIFO. This would amount to less
1358 * than a microsecond and thus looping for 1000 times is good enough
1359 * for that delay.
1360 */
1361 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1362 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1363 spin_unlock(&host->lock);
1364 msmsdcc_pio_irq(1, host);
1365 spin_lock(&host->lock);
1366 }
1367 }
1368 if (loop_cnt == 1000) {
1369 pr_info("%s: Timed out while polling for Rx Data\n",
1370 mmc_hostname(host->mmc));
1371 data->error = -ETIMEDOUT;
1372 msmsdcc_reset_and_restore(host);
1373 }
1374}
1375
San Mehat9d2bd732009-09-22 16:44:22 -07001376static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1377{
1378 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001379
1380 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1382 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1383 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1384 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001386 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301387 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001388 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1390 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001391 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001392 cmd->error = -EILSEQ;
1393 }
1394
1395 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 if (host->curr.data && host->dma.sg &&
1397 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001398 msm_dmov_stop_cmd(host->dma.channel,
1399 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 else if (host->curr.data && host->sps.sg &&
1401 host->is_sps_mode){
1402 /* Stop current SPS transfer */
1403 msmsdcc_sps_exit_curr_xfer(host);
1404 }
San Mehat9d2bd732009-09-22 16:44:22 -07001405 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301406 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001407 msmsdcc_stop_data(host);
1408 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301409 } else { /* host->data == NULL */
1410 if (!cmd->error && host->prog_enable) {
1411 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301413 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301415 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301416 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301417 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001418 if (host->dummy_52_needed)
1419 host->dummy_52_needed = 0;
1420 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301422 msmsdcc_request_end(host, cmd->mrq);
1423 }
1424 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301425 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1426 if (cmd->data->flags & MMC_DATA_READ)
1427 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1428 else
1429 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301430 } else if (cmd->data) {
1431 if (!(cmd->data->flags & MMC_DATA_READ))
1432 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001433 }
1434}
1435
San Mehat9d2bd732009-09-22 16:44:22 -07001436static irqreturn_t
1437msmsdcc_irq(int irq, void *dev_id)
1438{
1439 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001440 u32 status;
1441 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001443
1444 spin_lock(&host->lock);
1445
1446 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 struct mmc_command *cmd;
1448 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 if (timer) {
1451 timer = 0;
1452 msmsdcc_delay(host);
1453 }
San Mehat865c8062009-11-13 13:42:06 -08001454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 if (!host->clks_on) {
1456 pr_debug("%s: %s: SDIO async irq received\n",
1457 mmc_hostname(host->mmc), __func__);
1458 host->mmc->ios.clock = host->clk_rate;
1459 spin_unlock(&host->lock);
1460 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1461 spin_lock(&host->lock);
1462 if (host->plat->cfg_mpm_sdiowakeup &&
1463 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1464 wake_lock(&host->sdio_wlock);
1465 /* only ansyc interrupt can come when clocks are off */
1466 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301467 if (host->clk_rate <=
1468 msmsdcc_get_min_sup_clk_rate(host))
1469 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 }
1471
1472 status = readl_relaxed(host->base + MMCISTATUS);
1473
1474 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1475 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001476 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478#if IRQ_DEBUG
1479 msmsdcc_print_status(host, "irq0-r", status);
1480#endif
1481 status &= readl_relaxed(host->base + MMCIMASK0);
1482 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301483 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301484 if (host->clk_rate <=
1485 msmsdcc_get_min_sup_clk_rate(host))
1486 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487#if IRQ_DEBUG
1488 msmsdcc_print_status(host, "irq0-p", status);
1489#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1492 if (status & MCI_SDIOINTROPE) {
1493 if (host->sdcc_suspending)
1494 wake_lock(&host->sdio_suspend_wlock);
1495 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001496 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001498 data = host->curr.data;
1499
1500 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1502 MCI_CMDTIMEOUT)) {
1503 if (status & MCI_CMDTIMEOUT)
1504 pr_debug("%s: dummy CMD52 timeout\n",
1505 mmc_hostname(host->mmc));
1506 if (status & MCI_CMDCRCFAIL)
1507 pr_debug("%s: dummy CMD52 CRC failed\n",
1508 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001509 host->dummy_52_sent = 0;
1510 host->dummy_52_needed = 0;
1511 if (data) {
1512 msmsdcc_stop_data(host);
1513 msmsdcc_request_end(host, data->mrq);
1514 }
1515 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 spin_unlock(&host->lock);
1517 return IRQ_HANDLED;
1518 }
1519 break;
1520 }
1521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 /*
1523 * Check for proper command response
1524 */
1525 cmd = host->curr.cmd;
1526 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1527 MCI_CMDTIMEOUT | MCI_PROGDONE |
1528 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1529 msmsdcc_do_cmdirq(host, status);
1530 }
1531
1532 if (data) {
1533 /* Check for data errors */
1534 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1535 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1536 msmsdcc_data_err(host, data, status);
1537 host->curr.data_xfered = 0;
1538 if (host->dma.sg && host->is_dma_mode)
1539 msm_dmov_stop_cmd(host->dma.channel,
1540 &host->dma.hdr, 0);
1541 else if (host->sps.sg && host->is_sps_mode) {
1542 /* Stop current SPS transfer */
1543 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301544 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 msmsdcc_reset_and_restore(host);
1546 if (host->curr.data)
1547 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301548 if (!data->stop || (host->curr.mrq->sbc
1549 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 timer |=
1551 msmsdcc_request_end(host,
1552 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301553 else if ((host->curr.mrq->sbc
1554 && data->error) ||
1555 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 msmsdcc_start_command(host,
1557 data->stop,
1558 0);
1559 timer = 1;
1560 }
1561 }
1562 }
1563
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301564 /* Check for prog done */
1565 if (host->curr.wait_for_auto_prog_done &&
1566 (status & MCI_PROGDONE))
1567 host->curr.got_auto_prog_done = 1;
1568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 /* Check for data done */
1570 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1571 host->curr.got_dataend = 1;
1572
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301573 if (host->curr.got_dataend &&
1574 (!host->curr.wait_for_auto_prog_done ||
1575 (host->curr.wait_for_auto_prog_done &&
1576 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 /*
1578 * If DMA is still in progress, we complete
1579 * via the completion handler
1580 */
1581 if (!host->dma.busy && !host->sps.busy) {
1582 /*
1583 * There appears to be an issue in the
1584 * controller where if you request a
1585 * small block transfer (< fifo size),
1586 * you may get your DATAEND/DATABLKEND
1587 * irq without the PIO data irq.
1588 *
1589 * Check to see if theres still data
1590 * to be read, and simulate a PIO irq.
1591 */
1592 if (data->flags & MMC_DATA_READ)
1593 msmsdcc_wait_for_rxdata(host,
1594 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 if (!data->error) {
1596 host->curr.data_xfered =
1597 host->curr.xfer_size;
1598 host->curr.xfer_remain -=
1599 host->curr.xfer_size;
1600 }
1601
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001602 if (!host->dummy_52_needed) {
1603 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301604 if (!data->stop ||
1605 (host->curr.mrq->sbc
1606 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001607 msmsdcc_request_end(
1608 host,
1609 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301610 else if ((host->curr.mrq->sbc
1611 && data->error) ||
1612 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001613 msmsdcc_start_command(
1614 host,
1615 data->stop, 0);
1616 timer = 1;
1617 }
1618 } else {
1619 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001621 &dummy52cmd,
1622 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 }
1624 }
1625 }
1626 }
1627
San Mehat9d2bd732009-09-22 16:44:22 -07001628 ret = 1;
1629 } while (status);
1630
1631 spin_unlock(&host->lock);
1632
San Mehat9d2bd732009-09-22 16:44:22 -07001633 return IRQ_RETVAL(ret);
1634}
1635
1636static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1638{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301639 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301641 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301642 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1643 else
1644 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 } else {
1646 msmsdcc_start_command(host, mrq->cmd, 0);
1647 }
1648}
1649
1650static void
San Mehat9d2bd732009-09-22 16:44:22 -07001651msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1652{
1653 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656 /*
1657 * Get the SDIO AL client out of LPM.
1658 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001659 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 if (host->plat->is_sdio_al_client)
1661 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001662
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301663 /* check if sps pipe reset is pending? */
1664 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1665 msmsdcc_sps_pipes_reset_and_restore(host);
1666 host->sps.pipe_reset_pending = false;
1667 }
1668
San Mehat9d2bd732009-09-22 16:44:22 -07001669 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 WARN(host->curr.mrq, "Request in progress\n");
1671 WARN(!host->pwr, "SDCC power is turned off\n");
1672 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1673 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001674
1675 if (host->eject) {
1676 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1677 mrq->cmd->error = 0;
1678 mrq->data->bytes_xfered = mrq->data->blksz *
1679 mrq->data->blocks;
1680 } else
1681 mrq->cmd->error = -ENOMEDIUM;
1682
1683 spin_unlock_irqrestore(&host->lock, flags);
1684 mmc_request_done(mmc, mrq);
1685 return;
1686 }
1687
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301688 /*
1689 * Kick the software command timeout timer here.
1690 * Timer expires in 10 secs.
1691 */
1692 mod_timer(&host->req_tout_timer,
1693 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001694
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301695 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301696 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301697 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1698 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301699 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301701 else
1702 /*
1703 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1704 * write operations using CMD53 and CMD54.
1705 * Setting this bit with CMD53 would
1706 * automatically triggers PROG_DONE interrupt
1707 * without the need of sending dummy CMD52.
1708 */
1709 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301710 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1711 host->sdcc_version) {
1712 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713 }
San Mehat9d2bd732009-09-22 16:44:22 -07001714 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301715
Pratibhasagar V00b94332011-10-18 14:57:27 +05301716 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301717 mrq->sbc->mrq = mrq;
1718 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301719 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301720 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301721 msmsdcc_start_command(host, mrq->sbc, 0);
1722 } else {
1723 msmsdcc_request_start(host, mrq);
1724 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301725 } else {
1726 msmsdcc_request_start(host, mrq);
1727 }
1728
San Mehat9d2bd732009-09-22 16:44:22 -07001729 spin_unlock_irqrestore(&host->lock, flags);
1730}
1731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1733 int min_uV, int max_uV)
1734{
1735 int rc = 0;
1736
1737 if (vreg->set_voltage_sup) {
1738 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1739 if (rc) {
1740 pr_err("%s: regulator_set_voltage(%s) failed."
1741 " min_uV=%d, max_uV=%d, rc=%d\n",
1742 __func__, vreg->name, min_uV, max_uV, rc);
1743 }
1744 }
1745
1746 return rc;
1747}
1748
1749static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1750 int uA_load)
1751{
1752 int rc = 0;
1753
Krishna Kondafea60182011-11-01 16:01:34 -07001754 /* regulators that do not support regulator_set_voltage also
1755 do not support regulator_set_optimum_mode */
1756 if (vreg->set_voltage_sup) {
1757 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1758 if (rc < 0)
1759 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1760 "uA_load=%d) failed. rc=%d\n", __func__,
1761 vreg->name, uA_load, rc);
1762 else
1763 /* regulator_set_optimum_mode() can return non zero
1764 * value even for success case.
1765 */
1766 rc = 0;
1767 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001768
1769 return rc;
1770}
1771
1772static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1773 struct device *dev)
1774{
1775 int rc = 0;
1776
1777 /* check if regulator is already initialized? */
1778 if (vreg->reg)
1779 goto out;
1780
1781 /* Get the regulator handle */
1782 vreg->reg = regulator_get(dev, vreg->name);
1783 if (IS_ERR(vreg->reg)) {
1784 rc = PTR_ERR(vreg->reg);
1785 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1786 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001787 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001789
1790 if (regulator_count_voltages(vreg->reg) > 0)
1791 vreg->set_voltage_sup = 1;
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793out:
1794 return rc;
1795}
1796
1797static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1798{
1799 if (vreg->reg)
1800 regulator_put(vreg->reg);
1801}
1802
1803/* This init function should be called only once for each SDCC slot */
1804static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1805{
1806 int rc = 0;
1807 struct msm_mmc_slot_reg_data *curr_slot;
1808 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1809 struct device *dev = mmc_dev(host->mmc);
1810
1811 curr_slot = host->plat->vreg_data;
1812 if (!curr_slot)
1813 goto out;
1814
1815 curr_vdd_reg = curr_slot->vdd_data;
1816 curr_vccq_reg = curr_slot->vccq_data;
1817 curr_vddp_reg = curr_slot->vddp_data;
1818
1819 if (is_init) {
1820 /*
1821 * Get the regulator handle from voltage regulator framework
1822 * and then try to set the voltage level for the regulator
1823 */
1824 if (curr_vdd_reg) {
1825 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1826 if (rc)
1827 goto out;
1828 }
1829 if (curr_vccq_reg) {
1830 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1831 if (rc)
1832 goto vdd_reg_deinit;
1833 }
1834 if (curr_vddp_reg) {
1835 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1836 if (rc)
1837 goto vccq_reg_deinit;
1838 }
1839 goto out;
1840 } else {
1841 /* Deregister all regulators from regulator framework */
1842 goto vddp_reg_deinit;
1843 }
1844vddp_reg_deinit:
1845 if (curr_vddp_reg)
1846 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1847vccq_reg_deinit:
1848 if (curr_vccq_reg)
1849 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1850vdd_reg_deinit:
1851 if (curr_vdd_reg)
1852 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1853out:
1854 return rc;
1855}
1856
1857static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1858{
1859 int rc = 0;
1860
Subhash Jadavanicc922692011-08-01 23:05:01 +05301861 /* Put regulator in HPM (high power mode) */
1862 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1863 if (rc < 0)
1864 goto out;
1865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 if (!vreg->is_enabled) {
1867 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301868 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1869 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 if (rc)
1871 goto out;
1872
1873 rc = regulator_enable(vreg->reg);
1874 if (rc) {
1875 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1876 __func__, vreg->name, rc);
1877 goto out;
1878 }
1879 vreg->is_enabled = true;
1880 }
1881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882out:
1883 return rc;
1884}
1885
1886static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1887{
1888 int rc = 0;
1889
1890 /* Never disable regulator marked as always_on */
1891 if (vreg->is_enabled && !vreg->always_on) {
1892 rc = regulator_disable(vreg->reg);
1893 if (rc) {
1894 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1895 __func__, vreg->name, rc);
1896 goto out;
1897 }
1898 vreg->is_enabled = false;
1899
1900 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1901 if (rc < 0)
1902 goto out;
1903
1904 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301905 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906 if (rc)
1907 goto out;
1908 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1909 /* Put always_on regulator in LPM (low power mode) */
1910 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1911 if (rc < 0)
1912 goto out;
1913 }
1914out:
1915 return rc;
1916}
1917
1918static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1919{
1920 int rc = 0, i;
1921 struct msm_mmc_slot_reg_data *curr_slot;
1922 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1923 struct msm_mmc_reg_data *vreg_table[3];
1924
1925 curr_slot = host->plat->vreg_data;
1926 if (!curr_slot)
1927 goto out;
1928
1929 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1930 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1931 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1932
1933 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1934 if (vreg_table[i]) {
1935 if (enable)
1936 rc = msmsdcc_vreg_enable(vreg_table[i]);
1937 else
1938 rc = msmsdcc_vreg_disable(vreg_table[i]);
1939 if (rc)
1940 goto out;
1941 }
1942 }
1943out:
1944 return rc;
1945}
1946
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301947static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948{
1949 int rc = 0;
1950
1951 if (host->plat->vreg_data) {
1952 struct msm_mmc_reg_data *vddp_reg =
1953 host->plat->vreg_data->vddp_data;
1954
1955 if (vddp_reg && vddp_reg->is_enabled)
1956 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1957 }
1958
1959 return rc;
1960}
1961
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301962static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1963{
1964 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1965 int rc = 0;
1966
1967 if (curr_slot && curr_slot->vddp_data) {
1968 rc = msmsdcc_set_vddp_level(host,
1969 curr_slot->vddp_data->low_vol_level);
1970
1971 if (rc)
1972 pr_err("%s: %s: failed to change vddp level to %d",
1973 mmc_hostname(host->mmc), __func__,
1974 curr_slot->vddp_data->low_vol_level);
1975 }
1976
1977 return rc;
1978}
1979
1980static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1981{
1982 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1983 int rc = 0;
1984
1985 if (curr_slot && curr_slot->vddp_data) {
1986 rc = msmsdcc_set_vddp_level(host,
1987 curr_slot->vddp_data->high_vol_level);
1988
1989 if (rc)
1990 pr_err("%s: %s: failed to change vddp level to %d",
1991 mmc_hostname(host->mmc), __func__,
1992 curr_slot->vddp_data->high_vol_level);
1993 }
1994
1995 return rc;
1996}
1997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1999{
2000 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2001 return 1;
2002 return 0;
2003}
2004
2005static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2006{
2007 if (enable) {
2008 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2009 clk_enable(host->dfab_pclk);
2010 if (!IS_ERR(host->pclk))
2011 clk_enable(host->pclk);
2012 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302013 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302015 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 clk_disable(host->clk);
2017 if (!IS_ERR(host->pclk))
2018 clk_disable(host->pclk);
2019 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2020 clk_disable(host->dfab_pclk);
2021 }
2022}
2023
2024static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2025 unsigned int req_clk)
2026{
2027 unsigned int sel_clk = -1;
2028
2029 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2030 unsigned char cnt;
2031
2032 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2033 if (host->plat->sup_clk_table[cnt] > req_clk)
2034 break;
2035 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2036 sel_clk = host->plat->sup_clk_table[cnt];
2037 break;
2038 } else
2039 sel_clk = host->plat->sup_clk_table[cnt];
2040 }
2041 } else {
2042 if ((req_clk < host->plat->msmsdcc_fmax) &&
2043 (req_clk > host->plat->msmsdcc_fmid))
2044 sel_clk = host->plat->msmsdcc_fmid;
2045 else
2046 sel_clk = req_clk;
2047 }
2048
2049 return sel_clk;
2050}
2051
2052static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2053 struct msmsdcc_host *host)
2054{
2055 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2056 return host->plat->sup_clk_table[0];
2057 else
2058 return host->plat->msmsdcc_fmin;
2059}
2060
2061static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2062 struct msmsdcc_host *host)
2063{
2064 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2065 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2066 else
2067 return host->plat->msmsdcc_fmax;
2068}
2069
2070static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302071{
2072 struct msm_mmc_gpio_data *curr;
2073 int i, rc = 0;
2074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302076 for (i = 0; i < curr->size; i++) {
2077 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 if (curr->gpio[i].is_always_on &&
2079 curr->gpio[i].is_enabled)
2080 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302081 rc = gpio_request(curr->gpio[i].no,
2082 curr->gpio[i].name);
2083 if (rc) {
2084 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2085 mmc_hostname(host->mmc),
2086 curr->gpio[i].no,
2087 curr->gpio[i].name, rc);
2088 goto free_gpios;
2089 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302091 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 if (curr->gpio[i].is_always_on)
2093 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302094 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302096 }
2097 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302099
2100free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302102 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 curr->gpio[i].is_enabled = false;
2104 }
2105out:
2106 return rc;
2107}
2108
2109static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2110{
2111 struct msm_mmc_pad_data *curr;
2112 int i;
2113
2114 curr = host->plat->pin_data->pad_data;
2115 for (i = 0; i < curr->drv->size; i++) {
2116 if (enable)
2117 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2118 curr->drv->on[i].val);
2119 else
2120 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2121 curr->drv->off[i].val);
2122 }
2123
2124 for (i = 0; i < curr->pull->size; i++) {
2125 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002126 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002127 curr->pull->on[i].val);
2128 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002129 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 curr->pull->off[i].val);
2131 }
2132
2133 return 0;
2134}
2135
2136static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2137{
2138 int rc = 0;
2139
2140 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2141 return 0;
2142
2143 if (host->plat->pin_data->is_gpio)
2144 rc = msmsdcc_setup_gpio(host, enable);
2145 else
2146 rc = msmsdcc_setup_pad(host, enable);
2147
2148 if (!rc)
2149 host->plat->pin_data->cfg_sts = enable;
2150
2151 return rc;
2152}
2153
2154static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2155{
2156 unsigned int wakeup_irq;
2157
2158 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2159 host->plat->sdiowakeup_irq :
2160 host->core_irqres->start;
2161
2162 if (!host->irq_wake_enabled) {
2163 enable_irq_wake(wakeup_irq);
2164 host->irq_wake_enabled = true;
2165 }
2166}
2167
2168static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2169{
2170 unsigned int wakeup_irq;
2171
2172 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2173 host->plat->sdiowakeup_irq :
2174 host->core_irqres->start;
2175
2176 if (host->irq_wake_enabled) {
2177 disable_irq_wake(wakeup_irq);
2178 host->irq_wake_enabled = false;
2179 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302180}
2181
San Mehat9d2bd732009-09-22 16:44:22 -07002182static void
2183msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2184{
2185 struct msmsdcc_host *host = mmc_priv(mmc);
2186 u32 clk = 0, pwr = 0;
2187 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002188 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002191 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302192
San Mehat9d2bd732009-09-22 16:44:22 -07002193 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 spin_lock_irqsave(&host->lock, flags);
2195 if (!host->clks_on) {
2196 msmsdcc_setup_clocks(host, true);
2197 host->clks_on = 1;
2198 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2199 if (!host->plat->sdiowakeup_irq) {
2200 writel_relaxed(host->mci_irqenable,
2201 host->base + MMCIMASK0);
2202 mb();
2203 if (host->plat->cfg_mpm_sdiowakeup &&
2204 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2205 host->plat->cfg_mpm_sdiowakeup(
2206 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2207 msmsdcc_disable_irq_wake(host);
2208 } else if (!(mmc->pm_flags &
2209 MMC_PM_WAKE_SDIO_IRQ)) {
2210 writel_relaxed(host->mci_irqenable,
2211 host->base + MMCIMASK0);
2212 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302213 } else {
2214 writel_relaxed(host->mci_irqenable,
2215 host->base + MMCIMASK0);
2216 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217 }
San Mehat9d2bd732009-09-22 16:44:22 -07002218 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219 spin_unlock_irqrestore(&host->lock, flags);
2220
2221 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2222 /*
2223 * For DDR50 mode, controller needs clock rate to be
2224 * double than what is required on the SD card CLK pin.
2225 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302226 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 /*
2228 * Make sure that we don't double the clock if
2229 * doubled clock rate is already set
2230 */
2231 if (!host->ddr_doubled_clk_rate ||
2232 (host->ddr_doubled_clk_rate &&
2233 (host->ddr_doubled_clk_rate != ios->clock))) {
2234 host->ddr_doubled_clk_rate =
2235 msmsdcc_get_sup_clk_rate(
2236 host, (ios->clock * 2));
2237 clock = host->ddr_doubled_clk_rate;
2238 }
2239 } else {
2240 host->ddr_doubled_clk_rate = 0;
2241 }
2242
2243 if (clock != host->clk_rate) {
2244 rc = clk_set_rate(host->clk, clock);
2245 if (rc < 0)
2246 pr_debug("%s: failed to set clk rate %u\n",
2247 mmc_hostname(mmc), clock);
2248 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302249 host->reg_write_delay =
2250 (1 + ((3 * USEC_PER_SEC) /
2251 (host->clk_rate ? host->clk_rate :
2252 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 }
2254 /*
2255 * give atleast 2 MCLK cycles delay for clocks
2256 * and SDCC core to stabilize
2257 */
2258 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002259 clk |= MCI_CLK_ENABLE;
2260 }
2261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262 if (ios->bus_width == MMC_BUS_WIDTH_8)
2263 clk |= MCI_CLK_WIDEBUS_8;
2264 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2265 clk |= MCI_CLK_WIDEBUS_4;
2266 else
2267 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 if (msmsdcc_is_pwrsave(host))
2270 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 host->tuning_needed = 0;
2275 /*
2276 * Select the controller timing mode according
2277 * to current bus speed mode
2278 */
2279 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2280 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2281 clk |= (4 << 14);
2282 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302283 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 clk |= (3 << 14);
2285 } else {
2286 clk |= (2 << 14); /* feedback clock */
2287 }
2288
2289 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2290 clk |= (2 << 23);
2291
2292 if (host->io_pad_pwr_switch)
2293 clk |= IO_PAD_PWR_SWITCH;
2294
2295 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002296 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2298 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002299
2300 switch (ios->power_mode) {
2301 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2303 if (!host->sdcc_irq_disabled) {
2304 if (host->plat->cfg_mpm_sdiowakeup)
2305 host->plat->cfg_mpm_sdiowakeup(
2306 mmc_dev(mmc), SDC_DAT1_DISABLE);
2307 disable_irq(host->core_irqres->start);
2308 host->sdcc_irq_disabled = 1;
2309 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302310 /*
2311 * As VDD pad rail is always on, set low voltage for VDD
2312 * pad rail when slot is unused (when card is not present
2313 * or during system suspend).
2314 */
2315 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002317 break;
2318 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302319 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002320 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 if (host->sdcc_irq_disabled) {
2322 if (host->plat->cfg_mpm_sdiowakeup)
2323 host->plat->cfg_mpm_sdiowakeup(
2324 mmc_dev(mmc), SDC_DAT1_ENABLE);
2325 enable_irq(host->core_irqres->start);
2326 host->sdcc_irq_disabled = 0;
2327 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302328 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002330 break;
2331 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002333 pwr |= MCI_PWR_ON;
2334 break;
2335 }
2336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 spin_lock_irqsave(&host->lock, flags);
2338 if (!host->clks_on) {
2339 /* force the clocks to be on */
2340 msmsdcc_setup_clocks(host, true);
2341 /*
2342 * give atleast 2 MCLK cycles delay for clocks
2343 * and SDCC core to stabilize
2344 */
2345 msmsdcc_delay(host);
2346 }
2347 writel_relaxed(clk, host->base + MMCICLOCK);
2348 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002349
2350 if (host->pwr != pwr) {
2351 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302353 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002354 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 if (!host->clks_on) {
2356 /* force the clocks to be off */
2357 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 }
2359
2360 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2361 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2362 if (!host->plat->sdiowakeup_irq) {
2363 writel_relaxed(MCI_SDIOINTMASK,
2364 host->base + MMCIMASK0);
2365 mb();
2366 if (host->plat->cfg_mpm_sdiowakeup &&
2367 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2368 host->plat->cfg_mpm_sdiowakeup(
2369 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2370 msmsdcc_enable_irq_wake(host);
2371 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2372 writel_relaxed(0, host->base + MMCIMASK0);
2373 } else {
2374 writel_relaxed(MCI_SDIOINTMASK,
2375 host->base + MMCIMASK0);
2376 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302377 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378 }
2379 msmsdcc_setup_clocks(host, false);
2380 host->clks_on = 0;
2381 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002382 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002383}
2384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2386{
2387 struct msmsdcc_host *host = mmc_priv(mmc);
2388 u32 clk;
2389
2390 clk = readl_relaxed(host->base + MMCICLOCK);
2391 pr_debug("Changing to pwr_save=%d", pwrsave);
2392 if (pwrsave && msmsdcc_is_pwrsave(host))
2393 clk |= MCI_CLK_PWRSAVE;
2394 else
2395 clk &= ~MCI_CLK_PWRSAVE;
2396 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302397 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398
2399 return 0;
2400}
2401
2402static int msmsdcc_get_ro(struct mmc_host *mmc)
2403{
2404 int status = -ENOSYS;
2405 struct msmsdcc_host *host = mmc_priv(mmc);
2406
2407 if (host->plat->wpswitch) {
2408 status = host->plat->wpswitch(mmc_dev(mmc));
2409 } else if (host->plat->wpswitch_gpio) {
2410 status = gpio_request(host->plat->wpswitch_gpio,
2411 "SD_WP_Switch");
2412 if (status) {
2413 pr_err("%s: %s: Failed to request GPIO %d\n",
2414 mmc_hostname(mmc), __func__,
2415 host->plat->wpswitch_gpio);
2416 } else {
2417 status = gpio_direction_input(
2418 host->plat->wpswitch_gpio);
2419 if (!status) {
2420 /*
2421 * Wait for atleast 300ms as debounce
2422 * time for GPIO input to stabilize.
2423 */
2424 msleep(300);
2425 status = gpio_get_value_cansleep(
2426 host->plat->wpswitch_gpio);
2427 status ^= !host->plat->wpswitch_polarity;
2428 }
2429 gpio_free(host->plat->wpswitch_gpio);
2430 }
2431 }
2432
2433 if (status < 0)
2434 status = -ENOSYS;
2435 pr_debug("%s: Card read-only status %d\n", __func__, status);
2436
2437 return status;
2438}
2439
2440#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002441static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2442{
2443 struct msmsdcc_host *host = mmc_priv(mmc);
2444 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445
2446 if (enable) {
2447 spin_lock_irqsave(&host->lock, flags);
2448 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2449 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2450 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2451 spin_unlock_irqrestore(&host->lock, flags);
2452 } else {
2453 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2454 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2455 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2456 }
2457 mb();
2458}
2459#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2460
2461#ifdef CONFIG_PM_RUNTIME
2462static int msmsdcc_enable(struct mmc_host *mmc)
2463{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302464 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 struct device *dev = mmc->parent;
2466
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302467 if (dev->power.runtime_status == RPM_SUSPENDING) {
2468 if (mmc->suspend_task == current) {
2469 pm_runtime_get_noresume(dev);
2470 goto out;
2471 }
2472 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302474 rc = pm_runtime_get_sync(dev);
2475
2476 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2478 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302479 return rc;
2480 }
2481out:
2482 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483}
2484
2485static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2486{
2487 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302488 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302490 if (host->plat->disable_runtime_pm)
2491 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2493 return -ENOTSUPP;
2494
2495 rc = pm_runtime_put_sync(mmc->parent);
2496
2497 if (rc < 0)
2498 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2499 __func__, rc);
2500 return rc;
2501}
2502#else
2503#define msmsdcc_enable NULL
2504#define msmsdcc_disable NULL
2505#endif
2506
2507static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2508 struct mmc_ios *ios)
2509{
2510 struct msmsdcc_host *host = mmc_priv(mmc);
2511 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302512 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513
2514 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2515 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302516 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517 goto out;
2518 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2519 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302520 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002521 goto out;
2522 }
San Mehat9d2bd732009-09-22 16:44:22 -07002523
2524 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 /*
2526 * If we are here means voltage switch from high voltage to
2527 * low voltage is required
2528 */
2529
2530 /*
2531 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2532 * register until they become all zeros.
2533 */
2534 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302535 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002536 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2537 mmc_hostname(mmc), __func__);
2538 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002539 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540
2541 /* Stop SD CLK output. */
2542 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2543 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302544 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002545 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546
2547 /*
2548 * Switch VDDPX from high voltage to low voltage
2549 * to change the VDD of the SD IO pads.
2550 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302551 rc = msmsdcc_set_vddp_low_vol(host);
2552 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002554
2555 spin_lock_irqsave(&host->lock, flags);
2556 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2557 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302558 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002559 host->io_pad_pwr_switch = 1;
2560 spin_unlock_irqrestore(&host->lock, flags);
2561
2562 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2563 usleep_range(5000, 5500);
2564
2565 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302566 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2568 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302569 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570 spin_unlock_irqrestore(&host->lock, flags);
2571
2572 /*
2573 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2574 * don't become all ones within 1 ms then a Voltage Switch
2575 * sequence has failed and a power cycle to the card is required.
2576 * Otherwise Voltage Switch sequence is completed successfully.
2577 */
2578 usleep_range(1000, 1500);
2579
2580 spin_lock_irqsave(&host->lock, flags);
2581 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2582 != (0xF << 1)) {
2583 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2584 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302585 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586 goto out_unlock;
2587 }
2588
2589out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302590 /* Enable PWRSAVE */
2591 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2592 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 spin_unlock_irqrestore(&host->lock, flags);
2594out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302595 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596}
2597
2598static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2599 u8 phase);
2600/* Initialize the DLL (Programmable Delay Line ) */
2601static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2602{
2603 int rc = 0;
2604 u32 wait_timeout;
2605
2606 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2607 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2608 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2609
2610 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2611 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2612 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2613
2614 msmsdcc_delay(host);
2615
2616 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2617 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2618 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2619
2620 /* Initialize the phase to 0 */
2621 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2622 if (rc)
2623 goto out;
2624
2625 wait_timeout = 1000;
2626 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2627 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2628 /* max. wait for 1 sec for LOCK bit to be set */
2629 if (--wait_timeout == 0) {
2630 pr_err("%s: %s: DLL failed to lock at phase: %d",
2631 mmc_hostname(host->mmc), __func__, 0);
2632 rc = -1;
2633 goto out;
2634 }
2635 /* wait for 1ms */
2636 usleep_range(1000, 1500);
2637 }
2638out:
2639 return rc;
2640}
2641
2642/*
2643 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2644 * calibration sequence. This function should be called before
2645 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2646 * commands (CMD17/CMD18).
2647 */
2648static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2649{
2650 /* Set CDR_EN bit to 1. */
2651 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2652 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2653
2654 /* Set CDR_EXT_EN bit to 0. */
2655 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2656 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2657
2658 /* Set CK_OUT_EN bit to 0. */
2659 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2660 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2661
2662 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2663 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2664 ;
2665
2666 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2667 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2668 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2669
2670 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2671 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2672 ;
2673}
2674
2675static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2676 u8 phase)
2677{
2678 int rc = 0;
2679 u32 mclk_freq = 0;
2680 u32 wait_timeout;
2681
2682 /* Set CDR_EN bit to 0. */
2683 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2684 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2685
2686 /* Set CDR_EXT_EN bit to 1. */
2687 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2688 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2689
2690 /* Program the MCLK value to MCLK_FREQ bit field */
2691 if (host->clk_rate <= 112000000)
2692 mclk_freq = 0;
2693 else if (host->clk_rate <= 125000000)
2694 mclk_freq = 1;
2695 else if (host->clk_rate <= 137000000)
2696 mclk_freq = 2;
2697 else if (host->clk_rate <= 150000000)
2698 mclk_freq = 3;
2699 else if (host->clk_rate <= 162000000)
2700 mclk_freq = 4;
2701 else if (host->clk_rate <= 175000000)
2702 mclk_freq = 5;
2703 else if (host->clk_rate <= 187000000)
2704 mclk_freq = 6;
2705 else if (host->clk_rate <= 200000000)
2706 mclk_freq = 7;
2707
2708 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2709 & ~(7 << 24)) | (mclk_freq << 24)),
2710 host->base + MCI_DLL_CONFIG);
2711
2712 /* Set CK_OUT_EN bit to 0. */
2713 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2714 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2715
2716 /* Set DLL_EN bit to 1. */
2717 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2718 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2719
2720 wait_timeout = 1000;
2721 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2722 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2723 /* max. wait for 1 sec for LOCK bit for be set */
2724 if (--wait_timeout == 0) {
2725 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2726 mmc_hostname(host->mmc), __func__, phase);
2727 rc = -1;
2728 goto out;
2729 }
2730 /* wait for 1ms */
2731 usleep_range(1000, 1500);
2732 }
2733
2734 /*
2735 * Write the selected DLL clock output phase (0 ... 15)
2736 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2737 */
2738 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2739 & ~(0xF << 20)) | (phase << 20)),
2740 host->base + MCI_DLL_CONFIG);
2741
2742 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2743 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2744 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2745
2746 wait_timeout = 1000;
2747 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2748 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2749 /* max. wait for 1 sec for LOCK bit for be set */
2750 if (--wait_timeout == 0) {
2751 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2752 mmc_hostname(host->mmc), __func__, phase);
2753 rc = -1;
2754 goto out;
2755 }
2756 /* wait for 1ms */
2757 usleep_range(1000, 1500);
2758 }
2759out:
2760 return rc;
2761}
2762
2763static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2764{
2765 struct msmsdcc_host *host = mmc_priv(mmc);
2766 u8 phase;
2767 u8 *data_buf;
2768 u8 tuned_phases[16], tuned_phase_cnt = 0;
2769 int rc = 0;
2770
2771 /* Tuning is only required for SDR50 & SDR104 modes */
2772 if (!host->tuning_needed) {
2773 rc = 0;
2774 goto out;
2775 }
2776
2777 host->cmd19_tuning_in_progress = 1;
2778 /*
2779 * Make sure that clock is always enabled when DLL
2780 * tuning is in progress. Keeping PWRSAVE ON may
2781 * turn off the clock. So let's disable the PWRSAVE
2782 * here and re-enable it once tuning is completed.
2783 */
2784 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2785 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302786 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787 /* first of all reset the tuning block */
2788 rc = msmsdcc_init_cm_sdc4_dll(host);
2789 if (rc)
2790 goto out;
2791
2792 data_buf = kmalloc(64, GFP_KERNEL);
2793 if (!data_buf) {
2794 rc = -ENOMEM;
2795 goto out;
2796 }
2797
2798 phase = 0;
2799 do {
2800 struct mmc_command cmd = {0};
2801 struct mmc_data data = {0};
2802 struct mmc_request mrq = {
2803 .cmd = &cmd,
2804 .data = &data
2805 };
2806 struct scatterlist sg;
2807
2808 /* set the phase in delay line hw block */
2809 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2810 if (rc)
2811 goto kfree;
2812
2813 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2814 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2815
2816 data.blksz = 64;
2817 data.blocks = 1;
2818 data.flags = MMC_DATA_READ;
2819 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2820
2821 data.sg = &sg;
2822 data.sg_len = 1;
2823 sg_init_one(&sg, data_buf, 64);
2824 memset(data_buf, 0, 64);
2825 mmc_wait_for_req(mmc, &mrq);
2826
2827 if (!cmd.error && !data.error &&
2828 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2829 /* tuning is successful with this tuning point */
2830 tuned_phases[tuned_phase_cnt++] = phase;
2831 }
2832 } while (++phase < 16);
2833
2834 kfree(data_buf);
2835
2836 if (tuned_phase_cnt) {
2837 tuned_phase_cnt--;
2838 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2839 phase = tuned_phases[tuned_phase_cnt];
2840 /*
2841 * Finally set the selected phase in delay
2842 * line hw block.
2843 */
2844 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2845 if (rc)
2846 goto out;
2847 } else {
2848 /* tuning failed */
2849 rc = -EAGAIN;
2850 pr_err("%s: %s: no tuning point found",
2851 mmc_hostname(mmc), __func__);
2852 }
2853 goto out;
2854
2855kfree:
2856 kfree(data_buf);
2857out:
2858 /* re-enable PWESAVE */
2859 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2860 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302861 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002862 host->cmd19_tuning_in_progress = 0;
2863 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002864}
2865
2866static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 .enable = msmsdcc_enable,
2868 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002869 .request = msmsdcc_request,
2870 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871 .get_ro = msmsdcc_get_ro,
2872#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002873 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002874#endif
2875 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2876 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002877};
2878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879static unsigned int
2880msmsdcc_slot_status(struct msmsdcc_host *host)
2881{
2882 int status;
2883 unsigned int gpio_no = host->plat->status_gpio;
2884
2885 status = gpio_request(gpio_no, "SD_HW_Detect");
2886 if (status) {
2887 pr_err("%s: %s: Failed to request GPIO %d\n",
2888 mmc_hostname(host->mmc), __func__, gpio_no);
2889 } else {
2890 status = gpio_direction_input(gpio_no);
2891 if (!status)
2892 status = !gpio_get_value_cansleep(gpio_no);
2893 gpio_free(gpio_no);
2894 }
2895 return status;
2896}
2897
San Mehat9d2bd732009-09-22 16:44:22 -07002898static void
2899msmsdcc_check_status(unsigned long data)
2900{
2901 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2902 unsigned int status;
2903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002904 if (host->plat->status || host->plat->status_gpio) {
2905 if (host->plat->status)
2906 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002907 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002908 status = msmsdcc_slot_status(host);
2909
2910 host->eject = !status;
2911 if (status ^ host->oldstat) {
2912 pr_info("%s: Slot status change detected (%d -> %d)\n",
2913 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002914 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915 }
2916 host->oldstat = status;
2917 } else {
2918 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002919 }
San Mehat9d2bd732009-09-22 16:44:22 -07002920}
2921
2922static irqreturn_t
2923msmsdcc_platform_status_irq(int irq, void *dev_id)
2924{
2925 struct msmsdcc_host *host = dev_id;
2926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002928 msmsdcc_check_status((unsigned long) host);
2929 return IRQ_HANDLED;
2930}
2931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932static irqreturn_t
2933msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2934{
2935 struct msmsdcc_host *host = dev_id;
2936
2937 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2938 spin_lock(&host->lock);
2939 if (!host->sdio_irq_disabled) {
2940 disable_irq_nosync(irq);
2941 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2942 wake_lock(&host->sdio_wlock);
2943 msmsdcc_disable_irq_wake(host);
2944 }
2945 host->sdio_irq_disabled = 1;
2946 }
2947 if (host->plat->is_sdio_al_client) {
2948 if (!host->clks_on) {
2949 msmsdcc_setup_clocks(host, true);
2950 host->clks_on = 1;
2951 }
2952 if (host->sdcc_irq_disabled) {
2953 writel_relaxed(host->mci_irqenable,
2954 host->base + MMCIMASK0);
2955 mb();
2956 enable_irq(host->core_irqres->start);
2957 host->sdcc_irq_disabled = 0;
2958 }
2959 wake_lock(&host->sdio_wlock);
2960 }
2961 spin_unlock(&host->lock);
2962
2963 return IRQ_HANDLED;
2964}
2965
San Mehat9d2bd732009-09-22 16:44:22 -07002966static void
2967msmsdcc_status_notify_cb(int card_present, void *dev_id)
2968{
2969 struct msmsdcc_host *host = dev_id;
2970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002972 card_present);
2973 msmsdcc_check_status((unsigned long) host);
2974}
2975
San Mehat9d2bd732009-09-22 16:44:22 -07002976static int
2977msmsdcc_init_dma(struct msmsdcc_host *host)
2978{
2979 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2980 host->dma.host = host;
2981 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002982 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002983
2984 if (!host->dmares)
2985 return -ENODEV;
2986
2987 host->dma.nc = dma_alloc_coherent(NULL,
2988 sizeof(struct msmsdcc_nc_dmadata),
2989 &host->dma.nc_busaddr,
2990 GFP_KERNEL);
2991 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002992 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002993 return -ENOMEM;
2994 }
2995 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2996 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2997 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2998 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2999 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003000 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003001
3002 return 0;
3003}
3004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3006/**
3007 * Allocate and Connect a SDCC peripheral's SPS endpoint
3008 *
3009 * This function allocates endpoint context and
3010 * connect it with memory endpoint by calling
3011 * appropriate SPS driver APIs.
3012 *
3013 * Also registers a SPS callback function with
3014 * SPS driver
3015 *
3016 * This function should only be called once typically
3017 * during driver probe.
3018 *
3019 * @host - Pointer to sdcc host structure
3020 * @ep - Pointer to sps endpoint data structure
3021 * @is_produce - 1 means Producer endpoint
3022 * 0 means Consumer endpoint
3023 *
3024 * @return - 0 if successful else negative value.
3025 *
3026 */
3027static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3028 struct msmsdcc_sps_ep_conn_data *ep,
3029 bool is_producer)
3030{
3031 int rc = 0;
3032 struct sps_pipe *sps_pipe_handle;
3033 struct sps_connect *sps_config = &ep->config;
3034 struct sps_register_event *sps_event = &ep->event;
3035
3036 /* Allocate endpoint context */
3037 sps_pipe_handle = sps_alloc_endpoint();
3038 if (!sps_pipe_handle) {
3039 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3040 mmc_hostname(host->mmc), is_producer);
3041 rc = -ENOMEM;
3042 goto out;
3043 }
3044
3045 /* Get default connection configuration for an endpoint */
3046 rc = sps_get_config(sps_pipe_handle, sps_config);
3047 if (rc) {
3048 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3049 " rc=%d", mmc_hostname(host->mmc),
3050 (u32)sps_pipe_handle, rc);
3051 goto get_config_err;
3052 }
3053
3054 /* Modify the default connection configuration */
3055 if (is_producer) {
3056 /*
3057 * For SDCC producer transfer, source should be
3058 * SDCC peripheral where as destination should
3059 * be system memory.
3060 */
3061 sps_config->source = host->sps.bam_handle;
3062 sps_config->destination = SPS_DEV_HANDLE_MEM;
3063 /* Producer pipe will handle this connection */
3064 sps_config->mode = SPS_MODE_SRC;
3065 sps_config->options =
3066 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3067 } else {
3068 /*
3069 * For SDCC consumer transfer, source should be
3070 * system memory where as destination should
3071 * SDCC peripheral
3072 */
3073 sps_config->source = SPS_DEV_HANDLE_MEM;
3074 sps_config->destination = host->sps.bam_handle;
3075 sps_config->mode = SPS_MODE_DEST;
3076 sps_config->options =
3077 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3078 }
3079
3080 /* Producer pipe index */
3081 sps_config->src_pipe_index = host->sps.src_pipe_index;
3082 /* Consumer pipe index */
3083 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3084 /*
3085 * This event thresold value is only significant for BAM-to-BAM
3086 * transfer. It's ignored for BAM-to-System mode transfer.
3087 */
3088 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303089
3090 /* Allocate maximum descriptor fifo size */
3091 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3092 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003093 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3094 sps_config->desc.size,
3095 &sps_config->desc.phys_base,
3096 GFP_KERNEL);
3097
Pratibhasagar V00b94332011-10-18 14:57:27 +05303098 if (!sps_config->desc.base) {
3099 rc = -ENOMEM;
3100 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3101 , mmc_hostname(host->mmc));
3102 goto get_config_err;
3103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003104 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3105
3106 /* Establish connection between peripheral and memory endpoint */
3107 rc = sps_connect(sps_pipe_handle, sps_config);
3108 if (rc) {
3109 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3110 " rc=%d", mmc_hostname(host->mmc),
3111 (u32)sps_pipe_handle, rc);
3112 goto sps_connect_err;
3113 }
3114
3115 sps_event->mode = SPS_TRIGGER_CALLBACK;
3116 sps_event->options = SPS_O_EOT;
3117 sps_event->callback = msmsdcc_sps_complete_cb;
3118 sps_event->xfer_done = NULL;
3119 sps_event->user = (void *)host;
3120
3121 /* Register callback event for EOT (End of transfer) event. */
3122 rc = sps_register_event(sps_pipe_handle, sps_event);
3123 if (rc) {
3124 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3125 " rc=%d", mmc_hostname(host->mmc),
3126 (u32)sps_pipe_handle, rc);
3127 goto reg_event_err;
3128 }
3129 /* Now save the sps pipe handle */
3130 ep->pipe_handle = sps_pipe_handle;
3131 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3132 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3133 __func__, is_producer ? "READ" : "WRITE",
3134 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3135 goto out;
3136
3137reg_event_err:
3138 sps_disconnect(sps_pipe_handle);
3139sps_connect_err:
3140 dma_free_coherent(mmc_dev(host->mmc),
3141 sps_config->desc.size,
3142 sps_config->desc.base,
3143 sps_config->desc.phys_base);
3144get_config_err:
3145 sps_free_endpoint(sps_pipe_handle);
3146out:
3147 return rc;
3148}
3149
3150/**
3151 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3152 *
3153 * This function disconnect endpoint and deallocates
3154 * endpoint context.
3155 *
3156 * This function should only be called once typically
3157 * during driver remove.
3158 *
3159 * @host - Pointer to sdcc host structure
3160 * @ep - Pointer to sps endpoint data structure
3161 *
3162 */
3163static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3164 struct msmsdcc_sps_ep_conn_data *ep)
3165{
3166 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3167 struct sps_connect *sps_config = &ep->config;
3168 struct sps_register_event *sps_event = &ep->event;
3169
3170 sps_event->xfer_done = NULL;
3171 sps_event->callback = NULL;
3172 sps_register_event(sps_pipe_handle, sps_event);
3173 sps_disconnect(sps_pipe_handle);
3174 dma_free_coherent(mmc_dev(host->mmc),
3175 sps_config->desc.size,
3176 sps_config->desc.base,
3177 sps_config->desc.phys_base);
3178 sps_free_endpoint(sps_pipe_handle);
3179}
3180
3181/**
3182 * Reset SDCC peripheral's SPS endpoint
3183 *
3184 * This function disconnects an endpoint.
3185 *
3186 * This function should be called for reseting
3187 * SPS endpoint when data transfer error is
3188 * encountered during data transfer. This
3189 * can be considered as soft reset to endpoint.
3190 *
3191 * This function should only be called if
3192 * msmsdcc_sps_init() is already called.
3193 *
3194 * @host - Pointer to sdcc host structure
3195 * @ep - Pointer to sps endpoint data structure
3196 *
3197 * @return - 0 if successful else negative value.
3198 */
3199static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3200 struct msmsdcc_sps_ep_conn_data *ep)
3201{
3202 int rc = 0;
3203 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3204
3205 rc = sps_disconnect(sps_pipe_handle);
3206 if (rc) {
3207 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3208 " rc=%d", mmc_hostname(host->mmc), __func__,
3209 (u32)sps_pipe_handle, rc);
3210 goto out;
3211 }
3212 out:
3213 return rc;
3214}
3215
3216/**
3217 * Restore SDCC peripheral's SPS endpoint
3218 *
3219 * This function connects an endpoint.
3220 *
3221 * This function should be called for restoring
3222 * SPS endpoint after data transfer error is
3223 * encountered during data transfer. This
3224 * can be considered as soft reset to endpoint.
3225 *
3226 * This function should only be called if
3227 * msmsdcc_sps_reset_ep() is called before.
3228 *
3229 * @host - Pointer to sdcc host structure
3230 * @ep - Pointer to sps endpoint data structure
3231 *
3232 * @return - 0 if successful else negative value.
3233 */
3234static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3235 struct msmsdcc_sps_ep_conn_data *ep)
3236{
3237 int rc = 0;
3238 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3239 struct sps_connect *sps_config = &ep->config;
3240 struct sps_register_event *sps_event = &ep->event;
3241
3242 /* Establish connection between peripheral and memory endpoint */
3243 rc = sps_connect(sps_pipe_handle, sps_config);
3244 if (rc) {
3245 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3246 " rc=%d", mmc_hostname(host->mmc), __func__,
3247 (u32)sps_pipe_handle, rc);
3248 goto out;
3249 }
3250
3251 /* Register callback event for EOT (End of transfer) event. */
3252 rc = sps_register_event(sps_pipe_handle, sps_event);
3253 if (rc) {
3254 pr_err("%s: %s: sps_register_event() failed!!!"
3255 " pipe_handle=0x%x, rc=%d",
3256 mmc_hostname(host->mmc), __func__,
3257 (u32)sps_pipe_handle, rc);
3258 goto reg_event_err;
3259 }
3260 goto out;
3261
3262reg_event_err:
3263 sps_disconnect(sps_pipe_handle);
3264out:
3265 return rc;
3266}
3267
3268/**
3269 * Initialize SPS HW connected with SDCC core
3270 *
3271 * This function register BAM HW resources with
3272 * SPS driver and then initialize 2 SPS endpoints
3273 *
3274 * This function should only be called once typically
3275 * during driver probe.
3276 *
3277 * @host - Pointer to sdcc host structure
3278 *
3279 * @return - 0 if successful else negative value.
3280 *
3281 */
3282static int msmsdcc_sps_init(struct msmsdcc_host *host)
3283{
3284 int rc = 0;
3285 struct sps_bam_props bam = {0};
3286
3287 host->bam_base = ioremap(host->bam_memres->start,
3288 resource_size(host->bam_memres));
3289 if (!host->bam_base) {
3290 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3291 " size=0x%x", mmc_hostname(host->mmc),
3292 host->bam_memres->start,
3293 (host->bam_memres->end -
3294 host->bam_memres->start));
3295 rc = -ENOMEM;
3296 goto out;
3297 }
3298
3299 bam.phys_addr = host->bam_memres->start;
3300 bam.virt_addr = host->bam_base;
3301 /*
3302 * This event thresold value is only significant for BAM-to-BAM
3303 * transfer. It's ignored for BAM-to-System mode transfer.
3304 */
3305 bam.event_threshold = 0x10; /* Pipe event threshold */
3306 /*
3307 * This threshold controls when the BAM publish
3308 * the descriptor size on the sideband interface.
3309 * SPS HW will only be used when
3310 * data transfer size > MCI_FIFOSIZE (64 bytes).
3311 * PIO mode will be used when
3312 * data transfer size < MCI_FIFOSIZE (64 bytes).
3313 * So set this thresold value to 64 bytes.
3314 */
3315 bam.summing_threshold = 64;
3316 /* SPS driver wll handle the SDCC BAM IRQ */
3317 bam.irq = (u32)host->bam_irqres->start;
3318 bam.manage = SPS_BAM_MGR_LOCAL;
3319
3320 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3321 (u32)bam.phys_addr);
3322 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3323 (u32)bam.virt_addr);
3324
3325 /* Register SDCC Peripheral BAM device to SPS driver */
3326 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3327 if (rc) {
3328 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3329 mmc_hostname(host->mmc), rc);
3330 goto reg_bam_err;
3331 }
3332 pr_info("%s: BAM device registered. bam_handle=0x%x",
3333 mmc_hostname(host->mmc), host->sps.bam_handle);
3334
3335 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3336 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3337
3338 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3339 SPS_PROD_PERIPHERAL);
3340 if (rc)
3341 goto sps_reset_err;
3342 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3343 SPS_CONS_PERIPHERAL);
3344 if (rc)
3345 goto cons_conn_err;
3346
3347 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3348 mmc_hostname(host->mmc),
3349 (unsigned long long)host->bam_memres->start,
3350 (unsigned int)host->bam_irqres->start);
3351 goto out;
3352
3353cons_conn_err:
3354 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3355sps_reset_err:
3356 sps_deregister_bam_device(host->sps.bam_handle);
3357reg_bam_err:
3358 iounmap(host->bam_base);
3359out:
3360 return rc;
3361}
3362
3363/**
3364 * De-initialize SPS HW connected with SDCC core
3365 *
3366 * This function deinitialize SPS endpoints and then
3367 * deregisters BAM resources from SPS driver.
3368 *
3369 * This function should only be called once typically
3370 * during driver remove.
3371 *
3372 * @host - Pointer to sdcc host structure
3373 *
3374 */
3375static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3376{
3377 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3378 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3379 sps_deregister_bam_device(host->sps.bam_handle);
3380 iounmap(host->bam_base);
3381}
3382#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3383
3384static ssize_t
3385show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3386{
3387 struct mmc_host *mmc = dev_get_drvdata(dev);
3388 struct msmsdcc_host *host = mmc_priv(mmc);
3389 int poll;
3390 unsigned long flags;
3391
3392 spin_lock_irqsave(&host->lock, flags);
3393 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3394 spin_unlock_irqrestore(&host->lock, flags);
3395
3396 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3397}
3398
3399static ssize_t
3400set_polling(struct device *dev, struct device_attribute *attr,
3401 const char *buf, size_t count)
3402{
3403 struct mmc_host *mmc = dev_get_drvdata(dev);
3404 struct msmsdcc_host *host = mmc_priv(mmc);
3405 int value;
3406 unsigned long flags;
3407
3408 sscanf(buf, "%d", &value);
3409
3410 spin_lock_irqsave(&host->lock, flags);
3411 if (value) {
3412 mmc->caps |= MMC_CAP_NEEDS_POLL;
3413 mmc_detect_change(host->mmc, 0);
3414 } else {
3415 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3416 }
3417#ifdef CONFIG_HAS_EARLYSUSPEND
3418 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3419#endif
3420 spin_unlock_irqrestore(&host->lock, flags);
3421 return count;
3422}
3423
3424static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3425 show_polling, set_polling);
3426static struct attribute *dev_attrs[] = {
3427 &dev_attr_polling.attr,
3428 NULL,
3429};
3430static struct attribute_group dev_attr_grp = {
3431 .attrs = dev_attrs,
3432};
3433
3434#ifdef CONFIG_HAS_EARLYSUSPEND
3435static void msmsdcc_early_suspend(struct early_suspend *h)
3436{
3437 struct msmsdcc_host *host =
3438 container_of(h, struct msmsdcc_host, early_suspend);
3439 unsigned long flags;
3440
3441 spin_lock_irqsave(&host->lock, flags);
3442 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3443 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3444 spin_unlock_irqrestore(&host->lock, flags);
3445};
3446static void msmsdcc_late_resume(struct early_suspend *h)
3447{
3448 struct msmsdcc_host *host =
3449 container_of(h, struct msmsdcc_host, early_suspend);
3450 unsigned long flags;
3451
3452 if (host->polling_enabled) {
3453 spin_lock_irqsave(&host->lock, flags);
3454 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3455 mmc_detect_change(host->mmc, 0);
3456 spin_unlock_irqrestore(&host->lock, flags);
3457 }
3458};
3459#endif
3460
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303461void msmsdcc_print_regs(const char *name, void __iomem *base,
3462 unsigned int no_of_regs)
3463{
3464 unsigned int i;
3465
3466 if (!base)
3467 return;
3468 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3469 name, (u32)base);
3470 for (i = 0; i < no_of_regs; i = i + 4) {
3471 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3472 (u32)readl_relaxed(base + i*4),
3473 (u32)readl_relaxed(base + ((i+1)*4)),
3474 (u32)readl_relaxed(base + ((i+2)*4)),
3475 (u32)readl_relaxed(base + ((i+3)*4)));
3476 }
3477}
3478
3479static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3480{
3481 /* Dump current state of SDCC clocks, power and irq */
3482 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3483 (host->pwr ? "ON" : "OFF"));
3484 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3485 mmc_hostname(host->mmc),
3486 (host->clks_on ? "ON" : "OFF"),
3487 (u32)clk_get_rate(host->clk));
3488 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3489 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3490
3491 /* Now dump SDCC registers. Don't print FIFO registers */
3492 if (host->clks_on)
3493 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3494
3495 if (host->curr.data) {
3496 if (msmsdcc_check_dma_op_req(host->curr.data))
3497 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3498 else if (host->is_dma_mode)
3499 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3500 mmc_hostname(host->mmc), host->dma.busy,
3501 host->dma.channel, host->dma.crci);
3502 else if (host->is_sps_mode)
3503 pr_info("%s: SPS mode: busy=%d\n",
3504 mmc_hostname(host->mmc), host->sps.busy);
3505
3506 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3507 mmc_hostname(host->mmc), host->curr.xfer_size,
3508 host->curr.data_xfered, host->curr.xfer_remain);
3509 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3510 " wait_for_auto_prog_done=%d,"
3511 " got_auto_prog_done=%d\n",
3512 mmc_hostname(host->mmc), host->curr.got_dataend,
3513 host->prog_enable, host->curr.wait_for_auto_prog_done,
3514 host->curr.got_auto_prog_done);
3515 }
3516
3517}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3519{
3520 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3521 struct mmc_request *mrq;
3522 unsigned long flags;
3523
3524 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003525 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 pr_info("%s: %s: dummy CMD52 timeout\n",
3527 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003528 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003529 }
3530
3531 mrq = host->curr.mrq;
3532
3533 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303534 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3535 mrq->cmd->opcode);
3536 msmsdcc_dump_sdcc_state(host);
3537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 if (!mrq->cmd->error)
3539 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303540 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 if (mrq->data && !mrq->data->error)
3543 mrq->data->error = -ETIMEDOUT;
3544 host->curr.data_xfered = 0;
3545 if (host->dma.sg && host->is_dma_mode) {
3546 msm_dmov_stop_cmd(host->dma.channel,
3547 &host->dma.hdr, 0);
3548 } else if (host->sps.sg && host->is_sps_mode) {
3549 /* Stop current SPS transfer */
3550 msmsdcc_sps_exit_curr_xfer(host);
3551 } else {
3552 msmsdcc_reset_and_restore(host);
3553 msmsdcc_stop_data(host);
3554 if (mrq->data && mrq->data->stop)
3555 msmsdcc_start_command(host,
3556 mrq->data->stop, 0);
3557 else
3558 msmsdcc_request_end(host, mrq);
3559 }
3560 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303561 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562 msmsdcc_reset_and_restore(host);
3563 msmsdcc_request_end(host, mrq);
3564 }
3565 }
3566 spin_unlock_irqrestore(&host->lock, flags);
3567}
3568
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303569static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3570{
3571 int i, ret;
3572 struct mmc_platform_data *pdata;
3573 struct device_node *np = dev->of_node;
3574 u32 bus_width = 0;
3575 u32 *clk_table;
3576 int clk_table_len;
3577 u32 *sup_voltages;
3578 int sup_volt_len;
3579
3580 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3581 if (!pdata) {
3582 dev_err(dev, "could not allocate memory for platform data\n");
3583 goto err;
3584 }
3585
3586 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3587 if (bus_width == 8) {
3588 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3589 } else if (bus_width == 4) {
3590 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3591 } else {
3592 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3593 pdata->mmc_bus_width = 0;
3594 }
3595
3596 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3597 size_t sz;
3598 sz = sup_volt_len / sizeof(*sup_voltages);
3599 if (sz > 0) {
3600 sup_voltages = devm_kzalloc(dev,
3601 sz * sizeof(*sup_voltages), GFP_KERNEL);
3602 if (!sup_voltages) {
3603 dev_err(dev, "No memory for supported voltage\n");
3604 goto err;
3605 }
3606
3607 ret = of_property_read_u32_array(np,
3608 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3609 if (ret < 0) {
3610 dev_err(dev, "error while reading voltage"
3611 "ranges %d\n", ret);
3612 goto err;
3613 }
3614 } else {
3615 dev_err(dev, "No supported voltages\n");
3616 goto err;
3617 }
3618 for (i = 0; i < sz; i += 2) {
3619 u32 mask;
3620
3621 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3622 sup_voltages[i + 1]);
3623 if (!mask)
3624 dev_err(dev, "Invalide voltage range %d\n", i);
3625 pdata->ocr_mask |= mask;
3626 }
3627 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3628 } else {
3629 dev_err(dev, "Supported voltage range not specified\n");
3630 }
3631
3632 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3633 size_t sz;
3634 sz = clk_table_len / sizeof(*clk_table);
3635
3636 if (sz > 0) {
3637 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3638 GFP_KERNEL);
3639 if (!clk_table) {
3640 dev_err(dev, "No memory for clock table\n");
3641 goto err;
3642 }
3643
3644 ret = of_property_read_u32_array(np,
3645 "qcom,sdcc-clk-rates", clk_table, sz);
3646 if (ret < 0) {
3647 dev_err(dev, "error while reading clk"
3648 "table %d\n", ret);
3649 goto err;
3650 }
3651 } else {
3652 dev_err(dev, "clk_table not specified\n");
3653 goto err;
3654 }
3655 pdata->sup_clk_table = clk_table;
3656 pdata->sup_clk_cnt = sz;
3657 } else {
3658 dev_err(dev, "Supported clock rates not specified\n");
3659 }
3660
3661 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3662 pdata->nonremovable = true;
3663 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3664 pdata->disable_cmd23 = true;
3665
3666 return pdata;
3667err:
3668 return NULL;
3669}
3670
San Mehat9d2bd732009-09-22 16:44:22 -07003671static int
3672msmsdcc_probe(struct platform_device *pdev)
3673{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303674 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003675 struct msmsdcc_host *host;
3676 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 unsigned long flags;
3678 struct resource *core_irqres = NULL;
3679 struct resource *bam_irqres = NULL;
3680 struct resource *core_memres = NULL;
3681 struct resource *dml_memres = NULL;
3682 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003683 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003684 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303685 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003686 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003687
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303688 if (pdev->dev.of_node) {
3689 plat = msmsdcc_populate_pdata(&pdev->dev);
3690 of_property_read_u32((&pdev->dev)->of_node,
3691 "cell-index", &pdev->id);
3692 } else {
3693 plat = pdev->dev.platform_data;
3694 }
3695
San Mehat9d2bd732009-09-22 16:44:22 -07003696 /* must have platform data */
3697 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003698 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003699 ret = -EINVAL;
3700 goto out;
3701 }
3702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003704 return -EINVAL;
3705
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303706 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3707 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3708 return -EINVAL;
3709 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003710
San Mehat9d2bd732009-09-22 16:44:22 -07003711 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003712 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003713 return -ENXIO;
3714 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303715 if (pdev->dev.of_node) {
3716 /*
3717 * Device tree iomem resources are only accessible by index.
3718 * index = 0 -> SDCC register interface
3719 * index = 1 -> DML register interface
3720 * index = 2 -> BAM register interface
3721 * IRQ resources:
3722 * index = 0 -> SDCC IRQ
3723 * index = 1 -> BAM IRQ
3724 */
3725 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3726 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3727 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3728 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3729 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3730 } else {
3731 for (i = 0; i < pdev->num_resources; i++) {
3732 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3733 if (!strncmp(pdev->resource[i].name,
3734 "sdcc_dml_addr",
3735 sizeof("sdcc_dml_addr")))
3736 dml_memres = &pdev->resource[i];
3737 else if (!strncmp(pdev->resource[i].name,
3738 "sdcc_bam_addr",
3739 sizeof("sdcc_bam_addr")))
3740 bam_memres = &pdev->resource[i];
3741 else
3742 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003743
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303744 }
3745 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3746 if (!strncmp(pdev->resource[i].name,
3747 "sdcc_bam_irq",
3748 sizeof("sdcc_bam_irq")))
3749 bam_irqres = &pdev->resource[i];
3750 else
3751 core_irqres = &pdev->resource[i];
3752 }
3753 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3754 if (!strncmp(pdev->resource[i].name,
3755 "sdcc_dma_chnl",
3756 sizeof("sdcc_dma_chnl")))
3757 dmares = &pdev->resource[i];
3758 else if (!strncmp(pdev->resource[i].name,
3759 "sdcc_dma_crci",
3760 sizeof("sdcc_dma_crci")))
3761 dma_crci_res = &pdev->resource[i];
3762 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003763 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764 }
3765
3766 if (!core_irqres || !core_memres) {
3767 pr_err("%s: Invalid sdcc core resource\n", __func__);
3768 return -ENXIO;
3769 }
3770
3771 /*
3772 * Both BAM and DML memory resource should be preset.
3773 * BAM IRQ resource should also be present.
3774 */
3775 if ((bam_memres && !dml_memres) ||
3776 (!bam_memres && dml_memres) ||
3777 ((bam_memres && dml_memres) && !bam_irqres)) {
3778 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003779 return -ENXIO;
3780 }
3781
3782 /*
3783 * Setup our host structure
3784 */
San Mehat9d2bd732009-09-22 16:44:22 -07003785 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3786 if (!mmc) {
3787 ret = -ENOMEM;
3788 goto out;
3789 }
3790
3791 host = mmc_priv(mmc);
3792 host->pdev_id = pdev->id;
3793 host->plat = plat;
3794 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003795 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303796
3797 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 host->is_sps_mode = 1;
3799 else if (dmares)
3800 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802 host->base = ioremap(core_memres->start,
3803 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003804 if (!host->base) {
3805 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003806 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003807 }
3808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809 host->core_irqres = core_irqres;
3810 host->bam_irqres = bam_irqres;
3811 host->core_memres = core_memres;
3812 host->dml_memres = dml_memres;
3813 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003814 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003815 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003816 spin_lock_init(&host->lock);
3817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818#ifdef CONFIG_MMC_EMBEDDED_SDIO
3819 if (plat->embedded_sdio)
3820 mmc_set_embedded_sdio_data(mmc,
3821 &plat->embedded_sdio->cis,
3822 &plat->embedded_sdio->cccr,
3823 plat->embedded_sdio->funcs,
3824 plat->embedded_sdio->num_funcs);
3825#endif
3826
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303827 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3828 (unsigned long)host);
3829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3831 (unsigned long)host);
3832 if (host->is_dma_mode) {
3833 /* Setup DMA */
3834 ret = msmsdcc_init_dma(host);
3835 if (ret)
3836 goto ioremap_free;
3837 } else {
3838 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003839 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003840 }
3841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003842 /*
3843 * Setup SDCC clock if derived from Dayatona
3844 * fabric core clock.
3845 */
3846 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003847 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848 if (!IS_ERR(host->dfab_pclk)) {
3849 /* Set the clock rate to 64MHz for max. performance */
3850 ret = clk_set_rate(host->dfab_pclk, 64000000);
3851 if (ret)
3852 goto dfab_pclk_put;
3853 ret = clk_enable(host->dfab_pclk);
3854 if (ret)
3855 goto dfab_pclk_put;
3856 } else
3857 goto dma_free;
3858 }
3859
3860 /*
3861 * Setup main peripheral bus clock
3862 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003863 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003864 if (!IS_ERR(host->pclk)) {
3865 ret = clk_enable(host->pclk);
3866 if (ret)
3867 goto pclk_put;
3868
3869 host->pclk_rate = clk_get_rate(host->pclk);
3870 }
3871
3872 /*
3873 * Setup SDC MMC clock
3874 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003875 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003876 if (IS_ERR(host->clk)) {
3877 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003879 }
3880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3882 if (ret) {
3883 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3884 goto clk_put;
3885 }
3886
3887 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003888 if (ret)
3889 goto clk_put;
3890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303892 if (!host->clk_rate)
3893 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303894
3895 /*
3896 * Lookup the Controller Version, to identify the supported features
3897 * Version number read as 0 would indicate SDCC3 or earlier versions
3898 */
3899 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3900 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3901 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303902 /*
3903 * Set the register write delay according to min. clock frequency
3904 * supported and update later when the host->clk_rate changes.
3905 */
3906 host->reg_write_delay =
3907 (1 + ((3 * USEC_PER_SEC) /
3908 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909
3910 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303911 /* Apply Hard reset to SDCC to put it in power on default state */
3912 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003913
3914 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003915 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003917 goto clk_disable;
3918 }
3919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920
3921 /* Clocks has to be running before accessing SPS/DML HW blocks */
3922 if (host->is_sps_mode) {
3923 /* Initialize SPS */
3924 ret = msmsdcc_sps_init(host);
3925 if (ret)
3926 goto vreg_deinit;
3927 /* Initialize DML */
3928 ret = msmsdcc_dml_init(host);
3929 if (ret)
3930 goto sps_exit;
3931 }
San Mehat9d2bd732009-09-22 16:44:22 -07003932
San Mehat9d2bd732009-09-22 16:44:22 -07003933 /*
3934 * Setup MMC host structure
3935 */
3936 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3938 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003939 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3941 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003942
San Mehat9d2bd732009-09-22 16:44:22 -07003943 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303944 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303945
3946 /*
3947 * If we send the CMD23 before multi block write/read command
3948 * then we need not to send CMD12 at the end of the transfer.
3949 * If we don't send the CMD12 then only way to detect the PROG_DONE
3950 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3951 * controller. So let's enable the CMD23 for SDCC4 only.
3952 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303953 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303954 mmc->caps |= MMC_CAP_CMD23;
3955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956 mmc->caps |= plat->uhs_caps;
3957 /*
3958 * XPC controls the maximum current in the default speed mode of SDXC
3959 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3960 * XPC=1 means 150mA (max.) and speed class is supported.
3961 */
3962 if (plat->xpc_cap)
3963 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3964 MMC_CAP_SET_XPC_180);
3965
3966 if (plat->nonremovable)
3967 mmc->caps |= MMC_CAP_NONREMOVABLE;
3968#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3969 mmc->caps |= MMC_CAP_SDIO_IRQ;
3970#endif
3971
3972 if (plat->is_sdio_al_client)
3973 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003974
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303975 mmc->max_segs = msmsdcc_get_nr_sg(host);
3976 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
3977 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07003978
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303979 mmc->max_req_size = MMC_MAX_REQ_SIZE;
3980 mmc->max_seg_size = msmsdcc_get_max_seg_size(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 writel_relaxed(0, host->base + MMCIMASK0);
3983 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003985 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3986 mb();
3987 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003989 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3990 DRIVER_NAME " (cmd)", host);
3991 if (ret)
3992 goto dml_exit;
3993
3994 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3995 DRIVER_NAME " (pio)", host);
3996 if (ret)
3997 goto irq_free;
3998
3999 /*
4000 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4001 * IRQ is un-necessarily being monitored by MPM (Modem power
4002 * management block) during idle-power collapse. The MPM will be
4003 * configured to monitor the DATA1 GPIO line with level-low trigger
4004 * and thus depending on the GPIO status, it prevents TCXO shutdown
4005 * during idle-power collapse.
4006 */
4007 disable_irq(core_irqres->start);
4008 host->sdcc_irq_disabled = 1;
4009
4010 if (plat->sdiowakeup_irq) {
4011 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4012 mmc_hostname(mmc));
4013 ret = request_irq(plat->sdiowakeup_irq,
4014 msmsdcc_platform_sdiowakeup_irq,
4015 IRQF_SHARED | IRQF_TRIGGER_LOW,
4016 DRIVER_NAME "sdiowakeup", host);
4017 if (ret) {
4018 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4019 plat->sdiowakeup_irq, ret);
4020 goto pio_irq_free;
4021 } else {
4022 spin_lock_irqsave(&host->lock, flags);
4023 if (!host->sdio_irq_disabled) {
4024 disable_irq_nosync(plat->sdiowakeup_irq);
4025 host->sdio_irq_disabled = 1;
4026 }
4027 spin_unlock_irqrestore(&host->lock, flags);
4028 }
4029 }
4030
4031 if (plat->cfg_mpm_sdiowakeup) {
4032 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4033 mmc_hostname(mmc));
4034 }
4035
4036 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4037 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004038 /*
4039 * Setup card detect change
4040 */
4041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042 if (plat->status || plat->status_gpio) {
4043 if (plat->status)
4044 host->oldstat = plat->status(mmc_dev(host->mmc));
4045 else
4046 host->oldstat = msmsdcc_slot_status(host);
4047 host->eject = !host->oldstat;
4048 }
San Mehat9d2bd732009-09-22 16:44:22 -07004049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050 if (plat->status_irq) {
4051 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004052 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004053 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004054 DRIVER_NAME " (slot)",
4055 host);
4056 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 pr_err("Unable to get slot IRQ %d (%d)\n",
4058 plat->status_irq, ret);
4059 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004060 }
4061 } else if (plat->register_status_notify) {
4062 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4063 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004064 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004065 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004066
4067 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068
4069 ret = pm_runtime_set_active(&(pdev)->dev);
4070 if (ret < 0)
4071 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4072 __func__, ret);
4073 /*
4074 * There is no notion of suspend/resume for SD/MMC/SDIO
4075 * cards. So host can be suspended/resumed with out
4076 * worrying about its children.
4077 */
4078 pm_suspend_ignore_children(&(pdev)->dev, true);
4079
4080 /*
4081 * MMC/SD/SDIO bus suspend/resume operations are defined
4082 * only for the slots that will be used for non-removable
4083 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4084 * defined. Otherwise, they simply become card removal and
4085 * insertion events during suspend and resume respectively.
4086 * Hence, enable run-time PM only for slots for which bus
4087 * suspend/resume operations are defined.
4088 */
4089#ifdef CONFIG_MMC_UNSAFE_RESUME
4090 /*
4091 * If this capability is set, MMC core will enable/disable host
4092 * for every claim/release operation on a host. We use this
4093 * notification to increment/decrement runtime pm usage count.
4094 */
4095 mmc->caps |= MMC_CAP_DISABLE;
4096 pm_runtime_enable(&(pdev)->dev);
4097#else
4098 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4099 mmc->caps |= MMC_CAP_DISABLE;
4100 pm_runtime_enable(&(pdev)->dev);
4101 }
4102#endif
4103 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4104 (unsigned long)host);
4105
San Mehat9d2bd732009-09-22 16:44:22 -07004106 mmc_add_host(mmc);
4107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108#ifdef CONFIG_HAS_EARLYSUSPEND
4109 host->early_suspend.suspend = msmsdcc_early_suspend;
4110 host->early_suspend.resume = msmsdcc_late_resume;
4111 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4112 register_early_suspend(&host->early_suspend);
4113#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004114
Krishna Konda25786ec2011-07-25 16:21:36 -07004115 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4116 " dmacrcri %d\n", mmc_hostname(mmc),
4117 (unsigned long long)core_memres->start,
4118 (unsigned int) core_irqres->start,
4119 (unsigned int) plat->status_irq, host->dma.channel,
4120 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004121
4122 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4123 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4124 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4125 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4126 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4127 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4128 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4129 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4130 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4131 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4132 host->eject);
4133 pr_info("%s: Power save feature enable = %d\n",
4134 mmc_hostname(mmc), msmsdcc_pwrsave);
4135
Krishna Konda25786ec2011-07-25 16:21:36 -07004136 if (host->is_dma_mode && host->dma.channel != -1
4137 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004138 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004139 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004140 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 mmc_hostname(mmc), host->dma.cmd_busaddr,
4142 host->dma.cmdptr_busaddr);
4143 } else if (host->is_sps_mode) {
4144 pr_info("%s: SPS-BAM data transfer mode available\n",
4145 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004146 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004147 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149#if defined(CONFIG_DEBUG_FS)
4150 msmsdcc_dbg_createhost(host);
4151#endif
4152 if (!plat->status_irq) {
4153 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4154 if (ret)
4155 goto platform_irq_free;
4156 }
San Mehat9d2bd732009-09-22 16:44:22 -07004157 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004158
4159 platform_irq_free:
4160 del_timer_sync(&host->req_tout_timer);
4161 pm_runtime_disable(&(pdev)->dev);
4162 pm_runtime_set_suspended(&(pdev)->dev);
4163
4164 if (plat->status_irq)
4165 free_irq(plat->status_irq, host);
4166 sdiowakeup_irq_free:
4167 wake_lock_destroy(&host->sdio_suspend_wlock);
4168 if (plat->sdiowakeup_irq)
4169 free_irq(plat->sdiowakeup_irq, host);
4170 pio_irq_free:
4171 if (plat->sdiowakeup_irq)
4172 wake_lock_destroy(&host->sdio_wlock);
4173 free_irq(core_irqres->start, host);
4174 irq_free:
4175 free_irq(core_irqres->start, host);
4176 dml_exit:
4177 if (host->is_sps_mode)
4178 msmsdcc_dml_exit(host);
4179 sps_exit:
4180 if (host->is_sps_mode)
4181 msmsdcc_sps_exit(host);
4182 vreg_deinit:
4183 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004184 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004185 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004186 clk_put:
4187 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004188 pclk_disable:
4189 if (!IS_ERR(host->pclk))
4190 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004191 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004192 if (!IS_ERR(host->pclk))
4193 clk_put(host->pclk);
4194 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4195 clk_disable(host->dfab_pclk);
4196 dfab_pclk_put:
4197 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4198 clk_put(host->dfab_pclk);
4199 dma_free:
4200 if (host->is_dma_mode) {
4201 if (host->dmares)
4202 dma_free_coherent(NULL,
4203 sizeof(struct msmsdcc_nc_dmadata),
4204 host->dma.nc, host->dma.nc_busaddr);
4205 }
4206 ioremap_free:
4207 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004208 host_free:
4209 mmc_free_host(mmc);
4210 out:
4211 return ret;
4212}
4213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004214static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004215{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4217 struct mmc_platform_data *plat;
4218 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220 if (!mmc)
4221 return -ENXIO;
4222
4223 if (pm_runtime_suspended(&(pdev)->dev))
4224 pm_runtime_resume(&(pdev)->dev);
4225
4226 host = mmc_priv(mmc);
4227
4228 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4229 plat = host->plat;
4230
4231 if (!plat->status_irq)
4232 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4233
4234 del_timer_sync(&host->req_tout_timer);
4235 tasklet_kill(&host->dma_tlet);
4236 tasklet_kill(&host->sps.tlet);
4237 mmc_remove_host(mmc);
4238
4239 if (plat->status_irq)
4240 free_irq(plat->status_irq, host);
4241
4242 wake_lock_destroy(&host->sdio_suspend_wlock);
4243 if (plat->sdiowakeup_irq) {
4244 wake_lock_destroy(&host->sdio_wlock);
4245 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4246 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004247 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004248
4249 free_irq(host->core_irqres->start, host);
4250 free_irq(host->core_irqres->start, host);
4251
4252 clk_put(host->clk);
4253 if (!IS_ERR(host->pclk))
4254 clk_put(host->pclk);
4255 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4256 clk_put(host->dfab_pclk);
4257
4258 msmsdcc_vreg_init(host, false);
4259
4260 if (host->is_dma_mode) {
4261 if (host->dmares)
4262 dma_free_coherent(NULL,
4263 sizeof(struct msmsdcc_nc_dmadata),
4264 host->dma.nc, host->dma.nc_busaddr);
4265 }
4266
4267 if (host->is_sps_mode) {
4268 msmsdcc_dml_exit(host);
4269 msmsdcc_sps_exit(host);
4270 }
4271
4272 iounmap(host->base);
4273 mmc_free_host(mmc);
4274
4275#ifdef CONFIG_HAS_EARLYSUSPEND
4276 unregister_early_suspend(&host->early_suspend);
4277#endif
4278 pm_runtime_disable(&(pdev)->dev);
4279 pm_runtime_set_suspended(&(pdev)->dev);
4280
4281 return 0;
4282}
4283
4284#ifdef CONFIG_MSM_SDIO_AL
4285int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4286{
4287 struct msmsdcc_host *host = mmc_priv(mmc);
4288 unsigned long flags;
4289
4290 spin_lock_irqsave(&host->lock, flags);
4291 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4292 enable ? "En" : "Dis");
4293
4294 if (enable) {
4295 if (!host->sdcc_irq_disabled) {
4296 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304297 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004298 host->sdcc_irq_disabled = 1;
4299 }
4300
4301 if (host->clks_on) {
4302 msmsdcc_setup_clocks(host, false);
4303 host->clks_on = 0;
4304 }
4305
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304306 if (host->plat->sdio_lpm_gpio_setup &&
4307 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308 spin_unlock_irqrestore(&host->lock, flags);
4309 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4310 spin_lock_irqsave(&host->lock, flags);
4311 host->sdio_gpio_lpm = 1;
4312 }
4313
4314 if (host->sdio_irq_disabled) {
4315 msmsdcc_enable_irq_wake(host);
4316 enable_irq(host->plat->sdiowakeup_irq);
4317 host->sdio_irq_disabled = 0;
4318 }
4319 } else {
4320 if (!host->sdio_irq_disabled) {
4321 disable_irq_nosync(host->plat->sdiowakeup_irq);
4322 host->sdio_irq_disabled = 1;
4323 msmsdcc_disable_irq_wake(host);
4324 }
4325
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304326 if (host->plat->sdio_lpm_gpio_setup &&
4327 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004328 spin_unlock_irqrestore(&host->lock, flags);
4329 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4330 spin_lock_irqsave(&host->lock, flags);
4331 host->sdio_gpio_lpm = 0;
4332 }
4333
4334 if (!host->clks_on) {
4335 msmsdcc_setup_clocks(host, true);
4336 host->clks_on = 1;
4337 }
4338
4339 if (host->sdcc_irq_disabled) {
4340 writel_relaxed(host->mci_irqenable,
4341 host->base + MMCIMASK0);
4342 mb();
4343 enable_irq(host->core_irqres->start);
4344 host->sdcc_irq_disabled = 0;
4345 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004346 }
4347 spin_unlock_irqrestore(&host->lock, flags);
4348 return 0;
4349}
4350#else
4351int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4352{
4353 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004354}
4355#endif
4356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004358static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004359msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004360{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361 struct mmc_host *mmc = dev_get_drvdata(dev);
4362 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004363 int rc = 0;
4364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 if (host->plat->is_sdio_al_client)
4366 return 0;
4367
Sahitya Tummala7661a452011-07-18 13:28:35 +05304368 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004369 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004370 host->sdcc_suspending = 1;
4371 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004373 /*
4374 * If the clocks are already turned off by SDIO clients (as
4375 * part of LPM), then clocks should be turned on before
4376 * calling mmc_suspend_host() because mmc_suspend_host might
4377 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304378 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004379 * cards, clocks will be turned on before mmc_suspend_host
4380 * and turned off after mmc_suspend_host.
4381 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304382 if (mmc->card && mmc_card_sdio(mmc->card)) {
4383 mmc->ios.clock = host->clk_rate;
4384 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4385 }
San Mehat9d2bd732009-09-22 16:44:22 -07004386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004387 /*
4388 * MMC core thinks that host is disabled by now since
4389 * runtime suspend is scheduled after msmsdcc_disable()
4390 * is called. Thus, MMC core will try to enable the host
4391 * while suspending it. This results in a synchronous
4392 * runtime resume request while in runtime suspending
4393 * context and hence inorder to complete this resume
4394 * requet, it will wait for suspend to be complete,
4395 * but runtime suspend also can not proceed further
4396 * until the host is resumed. Thus, it leads to a hang.
4397 * Hence, increase the pm usage count before suspending
4398 * the host so that any resume requests after this will
4399 * simple become pm usage counter increment operations.
4400 */
4401 pm_runtime_get_noresume(dev);
4402 rc = mmc_suspend_host(mmc);
4403 pm_runtime_put_noidle(dev);
4404
4405 if (!rc) {
4406 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4407 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4408 disable_irq(host->core_irqres->start);
4409 host->sdcc_irq_disabled = 1;
4410
4411 /*
4412 * If MMC core level suspend is not supported,
4413 * turn off clocks to allow deep sleep (TCXO
4414 * shutdown).
4415 */
4416 mmc->ios.clock = 0;
4417 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4418 enable_irq(host->core_irqres->start);
4419 host->sdcc_irq_disabled = 0;
4420
4421 if (host->plat->sdiowakeup_irq) {
4422 host->sdio_irq_disabled = 0;
4423 msmsdcc_enable_irq_wake(host);
4424 enable_irq(host->plat->sdiowakeup_irq);
4425 }
4426 }
4427 }
4428 host->sdcc_suspending = 0;
4429 mmc->suspend_task = NULL;
4430 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4431 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004432 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304433 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004434 return rc;
4435}
4436
4437static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004438msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004439{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004440 struct mmc_host *mmc = dev_get_drvdata(dev);
4441 struct msmsdcc_host *host = mmc_priv(mmc);
4442 unsigned long flags;
4443
4444 if (host->plat->is_sdio_al_client)
4445 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004446
Sahitya Tummala7661a452011-07-18 13:28:35 +05304447 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004448 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004449 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4450 if (host->sdcc_irq_disabled) {
4451 enable_irq(host->core_irqres->start);
4452 host->sdcc_irq_disabled = 0;
4453 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304454 mmc->ios.clock = host->clk_rate;
4455 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004456
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304457 spin_lock_irqsave(&host->lock, flags);
4458 writel_relaxed(host->mci_irqenable,
4459 host->base + MMCIMASK0);
4460 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004461
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304462 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4463 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004464 if (host->plat->sdiowakeup_irq) {
4465 disable_irq_nosync(
4466 host->plat->sdiowakeup_irq);
4467 msmsdcc_disable_irq_wake(host);
4468 host->sdio_irq_disabled = 1;
4469 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304470 }
San Mehat9d2bd732009-09-22 16:44:22 -07004471
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304472 spin_unlock_irqrestore(&host->lock, flags);
4473 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004474
4475 mmc_resume_host(mmc);
4476
4477 /*
4478 * FIXME: Clearing of flags must be handled in clients
4479 * resume handler.
4480 */
4481 spin_lock_irqsave(&host->lock, flags);
4482 mmc->pm_flags = 0;
4483 spin_unlock_irqrestore(&host->lock, flags);
4484
4485 /*
4486 * After resuming the host wait for sometime so that
4487 * the SDIO work will be processed.
4488 */
4489 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4490 if ((host->plat->cfg_mpm_sdiowakeup ||
4491 host->plat->sdiowakeup_irq) &&
4492 wake_lock_active(&host->sdio_wlock))
4493 wake_lock_timeout(&host->sdio_wlock, 1);
4494 }
4495
4496 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004497 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304498 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004499 return 0;
4500}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004501
4502static int msmsdcc_runtime_idle(struct device *dev)
4503{
4504 struct mmc_host *mmc = dev_get_drvdata(dev);
4505 struct msmsdcc_host *host = mmc_priv(mmc);
4506
4507 if (host->plat->is_sdio_al_client)
4508 return 0;
4509
4510 /* Idle timeout is not configurable for now */
4511 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4512
4513 return -EAGAIN;
4514}
4515
4516static int msmsdcc_pm_suspend(struct device *dev)
4517{
4518 struct mmc_host *mmc = dev_get_drvdata(dev);
4519 struct msmsdcc_host *host = mmc_priv(mmc);
4520 int rc = 0;
4521
4522 if (host->plat->is_sdio_al_client)
4523 return 0;
4524
4525
4526 if (host->plat->status_irq)
4527 disable_irq(host->plat->status_irq);
4528
4529 if (!pm_runtime_suspended(dev))
4530 rc = msmsdcc_runtime_suspend(dev);
4531
4532 return rc;
4533}
4534
4535static int msmsdcc_pm_resume(struct device *dev)
4536{
4537 struct mmc_host *mmc = dev_get_drvdata(dev);
4538 struct msmsdcc_host *host = mmc_priv(mmc);
4539 int rc = 0;
4540
4541 if (host->plat->is_sdio_al_client)
4542 return 0;
4543
Sahitya Tummalafb486372011-09-02 19:01:49 +05304544 if (!pm_runtime_suspended(dev))
4545 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004546 if (host->plat->status_irq) {
4547 msmsdcc_check_status((unsigned long)host);
4548 enable_irq(host->plat->status_irq);
4549 }
4550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551 return rc;
4552}
4553
Daniel Walker08ecfde2010-06-23 12:32:20 -07004554#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004555#define msmsdcc_runtime_suspend NULL
4556#define msmsdcc_runtime_resume NULL
4557#define msmsdcc_runtime_idle NULL
4558#define msmsdcc_pm_suspend NULL
4559#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004560#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004562static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4563 .runtime_suspend = msmsdcc_runtime_suspend,
4564 .runtime_resume = msmsdcc_runtime_resume,
4565 .runtime_idle = msmsdcc_runtime_idle,
4566 .suspend = msmsdcc_pm_suspend,
4567 .resume = msmsdcc_pm_resume,
4568};
4569
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304570static const struct of_device_id msmsdcc_dt_match[] = {
4571 {.compatible = "qcom,msm-sdcc"},
4572
4573};
4574MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4575
San Mehat9d2bd732009-09-22 16:44:22 -07004576static struct platform_driver msmsdcc_driver = {
4577 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004578 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004579 .driver = {
4580 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004581 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304582 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004583 },
4584};
4585
4586static int __init msmsdcc_init(void)
4587{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004588#if defined(CONFIG_DEBUG_FS)
4589 int ret = 0;
4590 ret = msmsdcc_dbg_init();
4591 if (ret) {
4592 pr_err("Failed to create debug fs dir \n");
4593 return ret;
4594 }
4595#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004596 return platform_driver_register(&msmsdcc_driver);
4597}
4598
4599static void __exit msmsdcc_exit(void)
4600{
4601 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004602
4603#if defined(CONFIG_DEBUG_FS)
4604 debugfs_remove(debugfs_file);
4605 debugfs_remove(debugfs_dir);
4606#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004607}
4608
4609module_init(msmsdcc_init);
4610module_exit(msmsdcc_exit);
4611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004612MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004613MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004614
4615#if defined(CONFIG_DEBUG_FS)
4616
4617static int
4618msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4619{
4620 file->private_data = inode->i_private;
4621 return 0;
4622}
4623
4624static ssize_t
4625msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4626 size_t count, loff_t *ppos)
4627{
4628 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4629 char buf[1024];
4630 int max, i;
4631
4632 i = 0;
4633 max = sizeof(buf) - 1;
4634
4635 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4636 host->curr.cmd, host->curr.data);
4637 if (host->curr.cmd) {
4638 struct mmc_command *cmd = host->curr.cmd;
4639
4640 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4641 cmd->opcode, cmd->arg, cmd->flags);
4642 }
4643 if (host->curr.data) {
4644 struct mmc_data *data = host->curr.data;
4645 i += scnprintf(buf + i, max - i,
4646 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4647 data->timeout_ns, data->timeout_clks,
4648 data->blksz, data->blocks, data->error,
4649 data->flags);
4650 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4651 host->curr.xfer_size, host->curr.xfer_remain,
4652 host->curr.data_xfered, host->dma.sg);
4653 }
4654
4655 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4656}
4657
4658static const struct file_operations msmsdcc_dbg_state_ops = {
4659 .read = msmsdcc_dbg_state_read,
4660 .open = msmsdcc_dbg_state_open,
4661};
4662
4663static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4664{
4665 if (debugfs_dir) {
4666 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4667 0644, debugfs_dir, host,
4668 &msmsdcc_dbg_state_ops);
4669 }
4670}
4671
4672static int __init msmsdcc_dbg_init(void)
4673{
4674 int err;
4675
4676 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4677 if (IS_ERR(debugfs_dir)) {
4678 err = PTR_ERR(debugfs_dir);
4679 debugfs_dir = NULL;
4680 return err;
4681 }
4682
4683 return 0;
4684}
4685#endif