blob: 8f42e5ba66286a69c6739aea2ae7371fe0e157b4 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Krishna Konda941604a2012-01-10 17:46:34 -08006 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
Subhash Jadavani933e6a62011-12-26 18:05:04 +053046#include <linux/pm_qos_params.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
56#include <mach/htc_pwrsink.h>
57#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070058
San Mehat9d2bd732009-09-22 16:44:22 -070059#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070061
62#define DRIVER_NAME "msm-sdcc"
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#define DBG(host, fmt, args...) \
65 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
66
67#define IRQ_DEBUG 0
68#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
69#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
70#define SPS_CONS_PERIPHERAL 0
71#define SPS_PROD_PERIPHERAL 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072
73#if defined(CONFIG_DEBUG_FS)
74static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
75static struct dentry *debugfs_dir;
76static struct dentry *debugfs_file;
77static int msmsdcc_dbg_init(void);
78#endif
79
Subhash Jadavani8766e352011-11-30 11:30:32 +053080static u64 dma_mask = DMA_BIT_MASK(32);
San Mehat9d2bd732009-09-22 16:44:22 -070081static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083static struct mmc_command dummy52cmd;
84static struct mmc_request dummy52mrq = {
85 .cmd = &dummy52cmd,
86 .data = NULL,
87 .stop = NULL,
88};
89static struct mmc_command dummy52cmd = {
90 .opcode = SD_IO_RW_DIRECT,
91 .flags = MMC_RSP_PRESENT,
92 .data = NULL,
93 .mrq = &dummy52mrq,
94};
95/*
96 * An array holding the Tuning pattern to compare with when
97 * executing a tuning cycle.
98 */
99static const u32 cmd19_tuning_block[16] = {
100 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
101 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
102 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
103 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
104};
San Mehat865c8062009-11-13 13:42:06 -0800105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106#if IRQ_DEBUG == 1
107static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
108 "dattimeout", "txunderrun", "rxoverrun",
109 "cmdrespend", "cmdsent", "dataend", NULL,
110 "datablkend", "cmdactive", "txactive",
111 "rxactive", "txhalfempty", "rxhalffull",
112 "txfifofull", "rxfifofull", "txfifoempty",
113 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
114 "sdiointr", "progdone", "atacmdcompl",
115 "sdiointrope", "ccstimeout", NULL, NULL,
116 NULL, NULL, NULL };
117
118static void
119msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800120{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
124 for (i = 0; i < 32; i++) {
125 if (status & (1 << i))
126 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800127 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800129}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130#endif
San Mehat865c8062009-11-13 13:42:06 -0800131
San Mehat9d2bd732009-09-22 16:44:22 -0700132static void
133msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
134 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530135static inline void msmsdcc_delay(struct msmsdcc_host *host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530136static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530137
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530138static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
139{
140 unsigned short ret = NR_SG;
141
142 if (host->is_sps_mode) {
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +0530143 ret = SPS_MAX_DESCS;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530144 } else { /* DMA or PIO mode */
145 if (NR_SG > MAX_NR_SG_DMA_PIO)
146 ret = MAX_NR_SG_DMA_PIO;
147 }
148
149 return ret;
150}
151
Subhash Jadavani933e6a62011-12-26 18:05:04 +0530152/* Prevent idle power collapse(pc) while operating in peripheral mode */
153static void msmsdcc_pm_qos_update_latency(struct msmsdcc_host *host, int vote)
154{
155 u32 swfi_latency = 0;
156
157 if (!host->plat->swfi_latency)
158 return;
159
160 swfi_latency = host->plat->swfi_latency + 1;
161
162 if (vote)
163 pm_qos_update_request(&host->pm_qos_req_dma,
164 swfi_latency);
165 else
166 pm_qos_update_request(&host->pm_qos_req_dma,
167 PM_QOS_DEFAULT_VALUE);
168}
169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
171static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
172 struct msmsdcc_sps_ep_conn_data *ep);
173static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
174 struct msmsdcc_sps_ep_conn_data *ep);
175#else
176static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
177 struct msmsdcc_sps_ep_conn_data *ep,
178 bool is_producer) { return 0; }
179static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
180 struct msmsdcc_sps_ep_conn_data *ep) { }
181static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
182 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530183{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184 return 0;
185}
186static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
187 struct msmsdcc_sps_ep_conn_data *ep)
188{
189 return 0;
190}
191static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
192static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
193#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530196 * Apply soft reset to all SDCC BAM pipes
197 *
198 * This function applies soft reset to SDCC BAM pipe.
199 *
200 * This function should be called to recover from error
201 * conditions encountered during CMD/DATA tranfsers with card.
202 *
203 * @host - Pointer to driver's host structure
204 *
205 */
206static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
207{
208 int rc;
209
210 /* Reset all SDCC BAM pipes */
211 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
212 if (rc)
213 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
214 mmc_hostname(host->mmc), rc);
215 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
216 if (rc)
217 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
218 mmc_hostname(host->mmc), rc);
219
220 /* Restore all BAM pipes connections */
221 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
222 if (rc)
223 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
224 mmc_hostname(host->mmc), rc);
225 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
226 if (rc)
227 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
228 mmc_hostname(host->mmc), rc);
229}
230
231/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 * Apply soft reset
233 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530234 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 *
236 * This function should be called to recover from error
237 * conditions encountered with CMD/DATA tranfsers with card.
238 *
239 * Soft reset should only be used with SDCC controller v4.
240 *
241 * @host - Pointer to driver's host structure
242 *
243 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530244static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 /*
247 * Reset SDCC controller's DPSM (data path state machine
248 * and CPSM (command path state machine).
249 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530251 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530253 msmsdcc_delay(host);
254}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530255
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530256static void msmsdcc_hard_reset(struct msmsdcc_host *host)
257{
258 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530259
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530260 /* Reset the controller */
261 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
262 if (ret)
263 pr_err("%s: Clock assert failed at %u Hz"
264 " with err %d\n", mmc_hostname(host->mmc),
265 host->clk_rate, ret);
266
267 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
268 if (ret)
269 pr_err("%s: Clock deassert failed at %u Hz"
270 " with err %d\n", mmc_hostname(host->mmc),
271 host->clk_rate, ret);
272
273 /* Give some delay for clock reset to propogate to controller */
274 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530275}
276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
278{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530279 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530280 if (host->is_sps_mode) {
281 /* Reset DML first */
282 msmsdcc_dml_reset(host);
283 /*
284 * delay the SPS pipe reset in thread context as
285 * sps_connect/sps_disconnect APIs can be called
286 * only from non-atomic context.
287 */
288 host->sps.pipe_reset_pending = true;
289 }
290 mb();
291 msmsdcc_soft_reset(host);
292
293 pr_debug("%s: Applied soft reset to Controller\n",
294 mmc_hostname(host->mmc));
295
296 if (host->is_sps_mode)
297 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 } else {
299 /* Give Clock reset (hard reset) to controller */
300 u32 mci_clk = 0;
301 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302
303 /* Save the controller state */
304 mci_clk = readl_relaxed(host->base + MMCICLOCK);
305 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530308 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 pr_debug("%s: Controller has been reinitialized\n",
310 mmc_hostname(host->mmc));
311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 /* Restore the contoller state */
313 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530314 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530316 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530318 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530320
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700321 if (host->dummy_52_needed)
322 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323}
324
325static int
San Mehat9d2bd732009-09-22 16:44:22 -0700326msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
327{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 int retval = 0;
329
San Mehat9d2bd732009-09-22 16:44:22 -0700330 BUG_ON(host->curr.data);
331
332 host->curr.mrq = NULL;
333 host->curr.cmd = NULL;
334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 del_timer(&host->req_tout_timer);
336
San Mehat9d2bd732009-09-22 16:44:22 -0700337 if (mrq->data)
338 mrq->data->bytes_xfered = host->curr.data_xfered;
339 if (mrq->cmd->error == -ETIMEDOUT)
340 mdelay(5);
341
342 /*
343 * Need to drop the host lock here; mmc_request_done may call
344 * back into the driver...
345 */
346 spin_unlock(&host->lock);
347 mmc_request_done(host->mmc, mrq);
348 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349
350 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700351}
352
353static void
354msmsdcc_stop_data(struct msmsdcc_host *host)
355{
San Mehat9d2bd732009-09-22 16:44:22 -0700356 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530357 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530358 host->curr.wait_for_auto_prog_done = 0;
359 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700360 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
361 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700362 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700363}
364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700366{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367 return host->core_memres->start + MMCIFIFO;
368}
369
370static inline unsigned int msmsdcc_get_min_sup_clk_rate(
371 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373static inline void msmsdcc_delay(struct msmsdcc_host *host)
374{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530375 ktime_t start, diff;
376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530378 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530379
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530380 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530381 (readl_relaxed(host->base + MCI_STATUS2) &
382 MCI_MCLK_REG_WR_ACTIVE)) {
383 start = ktime_get();
384 while (readl_relaxed(host->base + MCI_STATUS2) &
385 MCI_MCLK_REG_WR_ACTIVE) {
386 diff = ktime_sub(ktime_get(), start);
387 /* poll for max. 1 ms */
388 if (ktime_to_us(diff) > 1000) {
389 pr_warning("%s: previous reg. write is"
390 " still active\n",
391 mmc_hostname(host->mmc));
392 break;
393 }
394 }
395 }
San Mehat9d2bd732009-09-22 16:44:22 -0700396}
397
San Mehat56a8b5b2009-11-21 12:29:46 -0800398static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
400{
401 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530403 /*
404 * As after sending the command, we don't write any of the
405 * controller registers and just wait for the
406 * CMD_RESPOND_END/CMD_SENT/Command failure notication
407 * from Controller.
408 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800410}
411
412static void
413msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
414{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
418 writel_relaxed((unsigned int)host->curr.xfer_size,
419 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
421 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800422
San Mehat6ac9ea62009-12-02 17:24:58 -0800423 if (host->cmd_cmd) {
424 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800426 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800427}
428
San Mehat9d2bd732009-09-22 16:44:22 -0700429static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530430msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700431{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530432 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700433 unsigned long flags;
434 struct mmc_request *mrq;
435
436 spin_lock_irqsave(&host->lock, flags);
437 mrq = host->curr.mrq;
438 BUG_ON(!mrq);
439
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530440 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700441 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700442 goto out;
443 }
444
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530445 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700446 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700448 } else {
449 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530450 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700451 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530452 mmc_hostname(host->mmc), host->dma.result);
453 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700454 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530455 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530456 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 host->dma.err.flush[0], host->dma.err.flush[1],
458 host->dma.err.flush[2], host->dma.err.flush[3],
459 host->dma.err.flush[4],
460 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530461 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700462 if (!mrq->data->error)
463 mrq->data->error = -EIO;
464 }
San Mehat9d2bd732009-09-22 16:44:22 -0700465 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
466 host->dma.dir);
467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 if (host->curr.user_pages) {
469 struct scatterlist *sg = host->dma.sg;
470 int i;
471
472 for (i = 0; i < host->dma.num_ents; i++, sg++)
473 flush_dcache_page(sg_page(sg));
474 }
475
San Mehat9d2bd732009-09-22 16:44:22 -0700476 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800477 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700478
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530479 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
480 (host->curr.wait_for_auto_prog_done &&
481 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700482 /*
483 * If we've already gotten our DATAEND / DATABLKEND
484 * for this request, then complete it through here.
485 */
San Mehat9d2bd732009-09-22 16:44:22 -0700486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700488 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 host->curr.xfer_remain -= host->curr.xfer_size;
490 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700491 if (host->dummy_52_needed) {
492 mrq->data->bytes_xfered = host->curr.data_xfered;
493 host->dummy_52_sent = 1;
494 msmsdcc_start_command(host, &dummy52cmd,
495 MCI_CPSM_PROGENA);
496 goto out;
497 }
498 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530499 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530500 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700501 host->curr.mrq = NULL;
502 host->curr.cmd = NULL;
503 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700505 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506
San Mehat9d2bd732009-09-22 16:44:22 -0700507 mmc_request_done(host->mmc, mrq);
508 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530509 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
510 || !mrq->sbc)) {
511 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530512 }
San Mehat9d2bd732009-09-22 16:44:22 -0700513 }
514
515out:
516 spin_unlock_irqrestore(&host->lock, flags);
517 return;
518}
519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
521/**
522 * Callback notification from SPS driver
523 *
524 * This callback function gets triggered called from
525 * SPS driver when requested SPS data transfer is
526 * completed.
527 *
528 * SPS driver invokes this callback in BAM irq context so
529 * SDCC driver schedule a tasklet for further processing
530 * this callback notification at later point of time in
531 * tasklet context and immediately returns control back
532 * to SPS driver.
533 *
534 * @nofity - Pointer to sps event notify sturcture
535 *
536 */
537static void
538msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
539{
540 struct msmsdcc_host *host =
541 (struct msmsdcc_host *)
542 ((struct sps_event_notify *)notify)->user;
543
544 host->sps.notify = *notify;
545 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
546 mmc_hostname(host->mmc), __func__, notify->event_id,
547 notify->data.transfer.iovec.addr,
548 notify->data.transfer.iovec.size,
549 notify->data.transfer.iovec.flags);
550 /* Schedule a tasklet for completing data transfer */
551 tasklet_schedule(&host->sps.tlet);
552}
553
554/**
555 * Tasklet handler for processing SPS callback event
556 *
557 * This function processing SPS event notification and
558 * checks if the SPS transfer is completed or not and
559 * then accordingly notifies status to MMC core layer.
560 *
561 * This function is called in tasklet context.
562 *
563 * @data - Pointer to sdcc driver data
564 *
565 */
566static void msmsdcc_sps_complete_tlet(unsigned long data)
567{
568 unsigned long flags;
569 int i, rc;
570 u32 data_xfered = 0;
571 struct mmc_request *mrq;
572 struct sps_iovec iovec;
573 struct sps_pipe *sps_pipe_handle;
574 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
575 struct sps_event_notify *notify = &host->sps.notify;
576
577 spin_lock_irqsave(&host->lock, flags);
578 if (host->sps.dir == DMA_FROM_DEVICE)
579 sps_pipe_handle = host->sps.prod.pipe_handle;
580 else
581 sps_pipe_handle = host->sps.cons.pipe_handle;
582 mrq = host->curr.mrq;
583
584 if (!mrq) {
585 spin_unlock_irqrestore(&host->lock, flags);
586 return;
587 }
588
589 pr_debug("%s: %s: sps event_id=%d\n",
590 mmc_hostname(host->mmc), __func__,
591 notify->event_id);
592
593 if (msmsdcc_is_dml_busy(host)) {
594 /* oops !!! this should never happen. */
595 pr_err("%s: %s: Received SPS EOT event"
596 " but DML HW is still busy !!!\n",
597 mmc_hostname(host->mmc), __func__);
598 }
599 /*
600 * Got End of transfer event!!! Check if all of the data
601 * has been transferred?
602 */
603 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
604 rc = sps_get_iovec(sps_pipe_handle, &iovec);
605 if (rc) {
606 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
607 mmc_hostname(host->mmc), __func__, rc, i);
608 break;
609 }
610 data_xfered += iovec.size;
611 }
612
613 if (data_xfered == host->curr.xfer_size) {
614 host->curr.data_xfered = host->curr.xfer_size;
615 host->curr.xfer_remain -= host->curr.xfer_size;
616 pr_debug("%s: Data xfer success. data_xfered=0x%x",
617 mmc_hostname(host->mmc),
618 host->curr.xfer_size);
619 } else {
620 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
621 " xfer_size=%d", mmc_hostname(host->mmc),
622 data_xfered, host->curr.xfer_size);
623 msmsdcc_reset_and_restore(host);
624 if (!mrq->data->error)
625 mrq->data->error = -EIO;
626 }
627
628 /* Unmap sg buffers */
629 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
630 host->sps.dir);
631
632 host->sps.sg = NULL;
633 host->sps.busy = 0;
634
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530635 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
636 (host->curr.wait_for_auto_prog_done &&
637 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 /*
639 * If we've already gotten our DATAEND / DATABLKEND
640 * for this request, then complete it through here.
641 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642
643 if (!mrq->data->error) {
644 host->curr.data_xfered = host->curr.xfer_size;
645 host->curr.xfer_remain -= host->curr.xfer_size;
646 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700647 if (host->dummy_52_needed) {
648 mrq->data->bytes_xfered = host->curr.data_xfered;
649 host->dummy_52_sent = 1;
650 msmsdcc_start_command(host, &dummy52cmd,
651 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700652 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700653 return;
654 }
655 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530656 if (!mrq->data->stop || mrq->cmd->error ||
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530657 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 host->curr.mrq = NULL;
659 host->curr.cmd = NULL;
660 mrq->data->bytes_xfered = host->curr.data_xfered;
661 del_timer(&host->req_tout_timer);
662 spin_unlock_irqrestore(&host->lock, flags);
663
664 mmc_request_done(host->mmc, mrq);
665 return;
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530666 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
667 || !mrq->sbc)) {
668 msmsdcc_start_command(host, mrq->data->stop, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 }
670 }
671 spin_unlock_irqrestore(&host->lock, flags);
672}
673
674/**
675 * Exit from current SPS data transfer
676 *
677 * This function exits from current SPS data transfer.
678 *
679 * This function should be called when error condition
680 * is encountered during data transfer.
681 *
682 * @host - Pointer to sdcc host structure
683 *
684 */
685static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
686{
687 struct mmc_request *mrq;
688
689 mrq = host->curr.mrq;
690 BUG_ON(!mrq);
691
692 msmsdcc_reset_and_restore(host);
693 if (!mrq->data->error)
694 mrq->data->error = -EIO;
695
696 /* Unmap sg buffers */
697 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
698 host->sps.dir);
699
700 host->sps.sg = NULL;
701 host->sps.busy = 0;
702 if (host->curr.data)
703 msmsdcc_stop_data(host);
704
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530705 if (!mrq->data->stop || mrq->cmd->error ||
706 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530708 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
709 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 msmsdcc_start_command(host, mrq->data->stop, 0);
711
712}
713#else
714static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
715static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
716static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
717#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
718
Subhash Jadavanib52b4d72011-12-05 19:16:28 +0530719static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530721static void
722msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
723 unsigned int result,
724 struct msm_dmov_errdata *err)
725{
726 struct msmsdcc_dma_data *dma_data =
727 container_of(cmd, struct msmsdcc_dma_data, hdr);
728 struct msmsdcc_host *host = dma_data->host;
729
730 dma_data->result = result;
731 if (err)
732 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
733
734 tasklet_schedule(&host->dma_tlet);
735}
736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700738{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
740 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700741 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 else
743 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700744}
745
746static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
747{
748 struct msmsdcc_nc_dmadata *nc;
749 dmov_box *box;
750 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700751 unsigned int n;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530752 int i, err = 0, box_cmd_cnt = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700753 struct scatterlist *sg = data->sg;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530754 unsigned int len, offset;
San Mehat9d2bd732009-09-22 16:44:22 -0700755
Krishna Konda25786ec2011-07-25 16:21:36 -0700756 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700758
Krishna Konda25786ec2011-07-25 16:21:36 -0700759 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
760
San Mehat9d2bd732009-09-22 16:44:22 -0700761 host->dma.sg = data->sg;
762 host->dma.num_ents = data->sg_len;
763
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530764 /* Prevent memory corruption */
765 BUG_ON(host->dma.num_ents > msmsdcc_get_nr_sg(host));
San Mehat56a8b5b2009-11-21 12:29:46 -0800766
San Mehat9d2bd732009-09-22 16:44:22 -0700767 nc = host->dma.nc;
768
San Mehat9d2bd732009-09-22 16:44:22 -0700769 if (data->flags & MMC_DATA_READ)
770 host->dma.dir = DMA_FROM_DEVICE;
771 else
772 host->dma.dir = DMA_TO_DEVICE;
773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
775 host->dma.num_ents, host->dma.dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776
777 if (n != host->dma.num_ents) {
778 pr_err("%s: Unable to map in all sg elements\n",
779 mmc_hostname(host->mmc));
780 host->dma.sg = NULL;
781 host->dma.num_ents = 0;
782 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800783 }
San Mehat9d2bd732009-09-22 16:44:22 -0700784
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530785 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
786 host->curr.user_pages = 0;
787 box = &nc->cmd[0];
788 for (i = 0; i < host->dma.num_ents; i++) {
789 len = sg_dma_len(sg);
790 offset = 0;
791
792 do {
793 /* Check if we can do DMA */
794 if (!len || (box_cmd_cnt >= MMC_MAX_DMA_CMDS)) {
795 err = -ENOTSUPP;
796 goto unmap;
797 }
798
799 box->cmd = CMD_MODE_BOX;
800
801 if (len >= MMC_MAX_DMA_BOX_LENGTH) {
802 len = MMC_MAX_DMA_BOX_LENGTH;
803 len -= len % data->blksz;
804 }
805 rows = (len % MCI_FIFOSIZE) ?
806 (len / MCI_FIFOSIZE) + 1 :
807 (len / MCI_FIFOSIZE);
808
809 if (data->flags & MMC_DATA_READ) {
810 box->src_row_addr = msmsdcc_fifo_addr(host);
811 box->dst_row_addr = sg_dma_address(sg) + offset;
812 box->src_dst_len = (MCI_FIFOSIZE << 16) |
813 (MCI_FIFOSIZE);
814 box->row_offset = MCI_FIFOSIZE;
815 box->num_rows = rows * ((1 << 16) + 1);
816 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
817 } else {
818 box->src_row_addr = sg_dma_address(sg) + offset;
819 box->dst_row_addr = msmsdcc_fifo_addr(host);
820 box->src_dst_len = (MCI_FIFOSIZE << 16) |
821 (MCI_FIFOSIZE);
822 box->row_offset = (MCI_FIFOSIZE << 16);
823 box->num_rows = rows * ((1 << 16) + 1);
824 box->cmd |= CMD_DST_CRCI(host->dma.crci);
825 }
826
827 offset += len;
828 len = sg_dma_len(sg) - offset;
829 box++;
830 box_cmd_cnt++;
831 } while (len);
832 sg++;
833 }
834 /* Mark last command */
835 box--;
836 box->cmd |= CMD_LC;
837
838 /* location of command block must be 64 bit aligned */
839 BUG_ON(host->dma.cmd_busaddr & 0x07);
840
841 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
842 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
843 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
844 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
845
846 /* Flush all data to memory before starting dma */
847 mb();
848
849unmap:
850 if (err) {
851 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
852 host->dma.num_ents, host->dma.dir);
853 pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
854 mmc_hostname(host->mmc), err);
855 }
856
857 return err;
San Mehat9d2bd732009-09-22 16:44:22 -0700858}
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
861/**
862 * Submits data transfer request to SPS driver
863 *
864 * This function make sg (scatter gather) data buffers
865 * DMA ready and then submits them to SPS driver for
866 * transfer.
867 *
868 * @host - Pointer to sdcc host structure
869 * @data - Pointer to mmc_data structure
870 *
871 * @return 0 if success else negative value
872 */
873static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
874 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800875{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 int rc = 0;
877 u32 flags;
878 int i;
879 u32 addr, len, data_cnt;
880 struct scatterlist *sg = data->sg;
881 struct sps_pipe *sps_pipe_handle;
882
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +0530883 /* Prevent memory corruption */
884 BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885
886 host->sps.sg = data->sg;
887 host->sps.num_ents = data->sg_len;
888 host->sps.xfer_req_cnt = 0;
889 if (data->flags & MMC_DATA_READ) {
890 host->sps.dir = DMA_FROM_DEVICE;
891 sps_pipe_handle = host->sps.prod.pipe_handle;
892 } else {
893 host->sps.dir = DMA_TO_DEVICE;
894 sps_pipe_handle = host->sps.cons.pipe_handle;
895 }
896
897 /* Make sg buffers DMA ready */
898 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
899 host->sps.dir);
900
901 if (rc != data->sg_len) {
902 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
903 mmc_hostname(host->mmc), rc);
904 host->sps.sg = NULL;
905 host->sps.num_ents = 0;
906 rc = -ENOMEM;
907 goto dma_map_err;
908 }
909
910 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
911 mmc_hostname(host->mmc), __func__,
912 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
913 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
914
915 for (i = 0; i < data->sg_len; i++) {
916 /*
917 * Check if this is the last buffer to transfer?
918 * If yes then set the INT and EOT flags.
919 */
920 len = sg_dma_len(sg);
921 addr = sg_dma_address(sg);
922 flags = 0;
923 while (len > 0) {
924 if (len > SPS_MAX_DESC_SIZE) {
925 data_cnt = SPS_MAX_DESC_SIZE;
926 } else {
927 data_cnt = len;
928 if (i == data->sg_len - 1)
929 flags = SPS_IOVEC_FLAG_INT |
930 SPS_IOVEC_FLAG_EOT;
931 }
932 rc = sps_transfer_one(sps_pipe_handle, addr,
933 data_cnt, host, flags);
934 if (rc) {
935 pr_err("%s: sps_transfer_one() error! rc=%d,"
936 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
937 mmc_hostname(host->mmc), rc,
938 (u32)sps_pipe_handle, (u32)sg, i);
939 goto dma_map_err;
940 }
941 addr += data_cnt;
942 len -= data_cnt;
943 host->sps.xfer_req_cnt++;
944 }
945 sg++;
946 }
947 goto out;
948
949dma_map_err:
950 /* unmap sg buffers */
951 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
952 host->sps.dir);
953out:
954 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700955}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956#else
957static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
958 struct mmc_data *data) { return 0; }
959#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700960
961static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800962msmsdcc_start_command_deferred(struct msmsdcc_host *host,
963 struct mmc_command *cmd, u32 *c)
964{
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +0530965 DBG(host, "op %02x arg %08x flags %08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 cmd->opcode, cmd->arg, cmd->flags);
967
San Mehat56a8b5b2009-11-21 12:29:46 -0800968 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
969
970 if (cmd->flags & MMC_RSP_PRESENT) {
971 if (cmd->flags & MMC_RSP_136)
972 *c |= MCI_CPSM_LONGRSP;
973 *c |= MCI_CPSM_RESPONSE;
974 }
975
976 if (/*interrupt*/0)
977 *c |= MCI_CPSM_INTERRUPT;
978
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530979 if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
980 cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
981 cmd->opcode == MMC_WRITE_BLOCK ||
982 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
983 cmd->opcode == SD_IO_RW_EXTENDED)
San Mehat56a8b5b2009-11-21 12:29:46 -0800984 *c |= MCI_CSPM_DATCMD;
985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530987 if (host->tuning_needed) {
988 /*
989 * For open ended block read operation (without CMD23),
990 * AUTO_CMD19 bit should be set while sending the READ command.
991 * For close ended block read operation (with CMD23),
992 * AUTO_CMD19 bit should be set while sending CMD23.
993 */
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530994 if ((cmd->opcode == MMC_SET_BLOCK_COUNT &&
995 host->curr.mrq->cmd->opcode ==
996 MMC_READ_MULTIPLE_BLOCK) ||
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530997 (!host->curr.mrq->sbc &&
Subhash Jadavanide0fc772011-11-13 12:27:52 +0530998 (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
999 cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301000 msmsdcc_enable_cdr_cm_sdc4_dll(host);
1001 *c |= MCI_CSPM_AUTO_CMD19;
1002 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 }
1004
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301005 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301006 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301008 }
1009
San Mehat56a8b5b2009-11-21 12:29:46 -08001010 if (cmd == cmd->mrq->stop)
1011 *c |= MCI_CSPM_MCIABORT;
1012
San Mehat56a8b5b2009-11-21 12:29:46 -08001013 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 pr_err("%s: Overlapping command requests\n",
1015 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -08001016 }
1017 host->curr.cmd = cmd;
1018}
1019
1020static void
1021msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
1022 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -07001023{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301024 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -07001025 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001027 unsigned int pio_irqmask = 0;
1028
Subhash Jadavani7d572f12011-11-13 13:09:36 +05301029 BUG_ON(!data->sg);
1030 BUG_ON(!data->sg_len);
1031
San Mehat9d2bd732009-09-22 16:44:22 -07001032 host->curr.data = data;
1033 host->curr.xfer_size = data->blksz * data->blocks;
1034 host->curr.xfer_remain = host->curr.xfer_size;
1035 host->curr.data_xfered = 0;
1036 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301037 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001038
1039 memset(&host->pio, 0, sizeof(host->pio));
1040
San Mehat9d2bd732009-09-22 16:44:22 -07001041 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
1042
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301043 if (host->curr.wait_for_auto_prog_done)
1044 datactrl |= MCI_AUTO_PROG_DONE;
1045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 if (!msmsdcc_check_dma_op_req(data)) {
1047 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
1048 datactrl |= MCI_DPSM_DMAENABLE;
1049 } else if (host->is_sps_mode) {
1050 if (!msmsdcc_is_dml_busy(host)) {
1051 if (!msmsdcc_sps_start_xfer(host, data)) {
1052 /* Now kick start DML transfer */
1053 mb();
1054 msmsdcc_dml_start_xfer(host, data);
1055 datactrl |= MCI_DPSM_DMAENABLE;
1056 host->sps.busy = 1;
1057 }
1058 } else {
1059 /*
1060 * Can't proceed with new transfer as
1061 * previous trasnfer is already in progress.
1062 * There is no point of going into PIO mode
1063 * as well. Is this a time to do kernel panic?
1064 */
1065 pr_err("%s: %s: DML HW is busy!!!"
1066 " Can't perform new SPS transfers"
1067 " now\n", mmc_hostname(host->mmc),
1068 __func__);
1069 }
1070 }
1071 }
1072
1073 /* Is data transfer in PIO mode required? */
1074 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001075 host->pio.sg = data->sg;
1076 host->pio.sg_len = data->sg_len;
1077 host->pio.sg_off = 0;
1078
1079 if (data->flags & MMC_DATA_READ) {
1080 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1081 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1082 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1083 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1085 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001086 }
1087
1088 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301089 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001090
San Mehat56a8b5b2009-11-21 12:29:46 -08001091 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001093 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1096 /* Use ADM (Application Data Mover) HW for Data transfer */
1097 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001098 host->cmd_timeout = timeout;
1099 host->cmd_pio_irqmask = pio_irqmask;
1100 host->cmd_datactrl = datactrl;
1101 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1104 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001105 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001106
1107 if (cmd) {
1108 msmsdcc_start_command_deferred(host, cmd, &c);
1109 host->cmd_c = c;
1110 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1112 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1113 host->base + MMCIMASK0);
1114 mb();
1115 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001116 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1123 (~(MCI_IRQ_PIO))) | pio_irqmask,
1124 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301126 /*
1127 * We don't need delay after writing to DATA_CTRL register
1128 * if we are not writing to CMD register immediately after
1129 * this. As we already have delay before sending the
1130 * command, we just need mb() here.
1131 */
1132 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001133
1134 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001136 /* Daisy-chain the command if requested */
1137 msmsdcc_start_command(host, cmd, c);
1138 }
San Mehat9d2bd732009-09-22 16:44:22 -07001139 }
1140}
1141
1142static void
1143msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1144{
San Mehat56a8b5b2009-11-21 12:29:46 -08001145 msmsdcc_start_command_deferred(host, cmd, &c);
1146 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001147}
1148
1149static void
1150msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1151 unsigned int status)
1152{
1153 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1155 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1156 pr_err("%s: Data CRC error\n",
1157 mmc_hostname(host->mmc));
1158 pr_err("%s: opcode 0x%.8x\n", __func__,
1159 data->mrq->cmd->opcode);
1160 pr_err("%s: blksz %d, blocks %d\n", __func__,
1161 data->blksz, data->blocks);
1162 data->error = -EILSEQ;
1163 }
San Mehat9d2bd732009-09-22 16:44:22 -07001164 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 /* CRC is optional for the bus test commands, not all
1166 * cards respond back with CRC. However controller
1167 * waits for the CRC and times out. Hence ignore the
1168 * data timeouts during the Bustest.
1169 */
1170 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1171 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301172 pr_err("%s: CMD%d: Data timeout\n",
1173 mmc_hostname(host->mmc),
1174 data->mrq->cmd->opcode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 data->error = -ETIMEDOUT;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301176 msmsdcc_dump_sdcc_state(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 }
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);
Sujit Reddy Thumma18e41a12011-12-14 21:46:54 +05301287 /* len might have aligned to 32bits above */
1288 if (len > remain)
1289 len = remain;
San Mehat9d2bd732009-09-22 16:44:22 -07001290
1291 /* Unmap the buffer */
1292 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1293 local_irq_restore(flags);
1294
1295 host->pio.sg_off += len;
1296 host->curr.xfer_remain -= len;
1297 host->curr.data_xfered += len;
1298 remain -= len;
1299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 if (remain) /* Done with this page? */
1301 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 if (status & MCI_RXACTIVE && host->curr.user_pages)
1304 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 if (!--host->pio.sg_len) {
1307 memset(&host->pio, 0, sizeof(host->pio));
1308 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001309 }
1310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 /* Advance to next sg */
1312 host->pio.sg++;
1313 host->pio.sg_off = 0;
1314
1315 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001316 } while (1);
1317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1319 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1320 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1321 host->base + MMCIMASK0);
1322 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301323 /*
1324 * back to back write to MASK0 register don't need
1325 * synchronization delay.
1326 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1328 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1329 }
1330 mb();
1331 } else if (!host->curr.xfer_remain) {
1332 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1333 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1334 mb();
1335 }
San Mehat9d2bd732009-09-22 16:44:22 -07001336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001338
1339 return IRQ_HANDLED;
1340}
1341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342static void
1343msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1344
1345static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1346 struct mmc_data *data)
1347{
1348 u32 loop_cnt = 0;
1349
1350 /*
1351 * For read commands with data less than fifo size, it is possible to
1352 * get DATAEND first and RXDATA_AVAIL might be set later because of
1353 * synchronization delay through the asynchronous RX FIFO. Thus, for
1354 * such cases, even after DATAEND interrupt is received software
1355 * should poll for RXDATA_AVAIL until the requested data is read out
1356 * of FIFO. This change is needed to get around this abnormal but
1357 * sometimes expected behavior of SDCC3 controller.
1358 *
1359 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1360 * after the data is loaded into RX FIFO. This would amount to less
1361 * than a microsecond and thus looping for 1000 times is good enough
1362 * for that delay.
1363 */
1364 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1365 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1366 spin_unlock(&host->lock);
1367 msmsdcc_pio_irq(1, host);
1368 spin_lock(&host->lock);
1369 }
1370 }
1371 if (loop_cnt == 1000) {
1372 pr_info("%s: Timed out while polling for Rx Data\n",
1373 mmc_hostname(host->mmc));
1374 data->error = -ETIMEDOUT;
1375 msmsdcc_reset_and_restore(host);
1376 }
1377}
1378
San Mehat9d2bd732009-09-22 16:44:22 -07001379static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1380{
1381 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001382
1383 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1385 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1386 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1387 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301390 pr_debug("%s: CMD%d: Command timeout\n",
1391 mmc_hostname(host->mmc), cmd->opcode);
San Mehat9d2bd732009-09-22 16:44:22 -07001392 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1394 !host->cmd19_tuning_in_progress) {
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05301395 pr_err("%s: CMD%d: Command CRC error\n",
1396 mmc_hostname(host->mmc), cmd->opcode);
1397 msmsdcc_dump_sdcc_state(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001398 cmd->error = -EILSEQ;
1399 }
1400
1401 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 if (host->curr.data && host->dma.sg &&
1403 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001404 msm_dmov_stop_cmd(host->dma.channel,
1405 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 else if (host->curr.data && host->sps.sg &&
1407 host->is_sps_mode){
1408 /* Stop current SPS transfer */
1409 msmsdcc_sps_exit_curr_xfer(host);
1410 }
San Mehat9d2bd732009-09-22 16:44:22 -07001411 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301412 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001413 msmsdcc_stop_data(host);
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301414 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301415 } else { /* host->data == NULL */
Sujit Reddy Thumma055106d2012-01-16 15:16:26 +05301416 if (!cmd->error && host->prog_enable) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301417 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301419 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301421 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301422 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301423 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001424 if (host->dummy_52_needed)
1425 host->dummy_52_needed = 0;
1426 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301428 msmsdcc_request_end(host, cmd->mrq);
1429 }
1430 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301431 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1432 if (cmd->data->flags & MMC_DATA_READ)
1433 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1434 else
1435 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301436 } else if (cmd->data) {
1437 if (!(cmd->data->flags & MMC_DATA_READ))
1438 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001439 }
1440}
1441
San Mehat9d2bd732009-09-22 16:44:22 -07001442static irqreturn_t
1443msmsdcc_irq(int irq, void *dev_id)
1444{
1445 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001446 u32 status;
1447 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001449
1450 spin_lock(&host->lock);
1451
1452 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 struct mmc_command *cmd;
1454 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 if (timer) {
1457 timer = 0;
1458 msmsdcc_delay(host);
1459 }
San Mehat865c8062009-11-13 13:42:06 -08001460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 if (!host->clks_on) {
1462 pr_debug("%s: %s: SDIO async irq received\n",
1463 mmc_hostname(host->mmc), __func__);
1464 host->mmc->ios.clock = host->clk_rate;
1465 spin_unlock(&host->lock);
1466 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1467 spin_lock(&host->lock);
1468 if (host->plat->cfg_mpm_sdiowakeup &&
1469 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1470 wake_lock(&host->sdio_wlock);
1471 /* only ansyc interrupt can come when clocks are off */
1472 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301473 if (host->clk_rate <=
1474 msmsdcc_get_min_sup_clk_rate(host))
1475 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 }
1477
1478 status = readl_relaxed(host->base + MMCISTATUS);
1479
1480 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1481 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001482 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484#if IRQ_DEBUG
1485 msmsdcc_print_status(host, "irq0-r", status);
1486#endif
1487 status &= readl_relaxed(host->base + MMCIMASK0);
1488 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301489 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301490 if (host->clk_rate <=
1491 msmsdcc_get_min_sup_clk_rate(host))
1492 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493#if IRQ_DEBUG
1494 msmsdcc_print_status(host, "irq0-p", status);
1495#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1498 if (status & MCI_SDIOINTROPE) {
1499 if (host->sdcc_suspending)
1500 wake_lock(&host->sdio_suspend_wlock);
1501 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001502 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001504 data = host->curr.data;
1505
1506 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1508 MCI_CMDTIMEOUT)) {
1509 if (status & MCI_CMDTIMEOUT)
1510 pr_debug("%s: dummy CMD52 timeout\n",
1511 mmc_hostname(host->mmc));
1512 if (status & MCI_CMDCRCFAIL)
1513 pr_debug("%s: dummy CMD52 CRC failed\n",
1514 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001515 host->dummy_52_sent = 0;
1516 host->dummy_52_needed = 0;
1517 if (data) {
1518 msmsdcc_stop_data(host);
1519 msmsdcc_request_end(host, data->mrq);
1520 }
1521 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 spin_unlock(&host->lock);
1523 return IRQ_HANDLED;
1524 }
1525 break;
1526 }
1527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 /*
1529 * Check for proper command response
1530 */
1531 cmd = host->curr.cmd;
1532 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1533 MCI_CMDTIMEOUT | MCI_PROGDONE |
1534 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1535 msmsdcc_do_cmdirq(host, status);
1536 }
1537
Sathish Ambley081d7842011-11-29 11:19:41 -08001538 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 /* Check for data errors */
1540 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1541 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1542 msmsdcc_data_err(host, data, status);
1543 host->curr.data_xfered = 0;
1544 if (host->dma.sg && host->is_dma_mode)
1545 msm_dmov_stop_cmd(host->dma.channel,
1546 &host->dma.hdr, 0);
1547 else if (host->sps.sg && host->is_sps_mode) {
1548 /* Stop current SPS transfer */
1549 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301550 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 msmsdcc_reset_and_restore(host);
1552 if (host->curr.data)
1553 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301554 if (!data->stop || (host->curr.mrq->sbc
1555 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 timer |=
1557 msmsdcc_request_end(host,
1558 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301559 else if ((host->curr.mrq->sbc
1560 && data->error) ||
1561 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 msmsdcc_start_command(host,
1563 data->stop,
1564 0);
1565 timer = 1;
1566 }
1567 }
1568 }
1569
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301570 /* Check for prog done */
1571 if (host->curr.wait_for_auto_prog_done &&
1572 (status & MCI_PROGDONE))
1573 host->curr.got_auto_prog_done = 1;
1574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 /* Check for data done */
1576 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1577 host->curr.got_dataend = 1;
1578
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301579 if (host->curr.got_dataend &&
1580 (!host->curr.wait_for_auto_prog_done ||
1581 (host->curr.wait_for_auto_prog_done &&
1582 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 /*
1584 * If DMA is still in progress, we complete
1585 * via the completion handler
1586 */
1587 if (!host->dma.busy && !host->sps.busy) {
1588 /*
1589 * There appears to be an issue in the
1590 * controller where if you request a
1591 * small block transfer (< fifo size),
1592 * you may get your DATAEND/DATABLKEND
1593 * irq without the PIO data irq.
1594 *
1595 * Check to see if theres still data
1596 * to be read, and simulate a PIO irq.
1597 */
1598 if (data->flags & MMC_DATA_READ)
1599 msmsdcc_wait_for_rxdata(host,
1600 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 if (!data->error) {
1602 host->curr.data_xfered =
1603 host->curr.xfer_size;
1604 host->curr.xfer_remain -=
1605 host->curr.xfer_size;
1606 }
1607
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001608 if (!host->dummy_52_needed) {
1609 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301610 if (!data->stop ||
1611 (host->curr.mrq->sbc
1612 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001613 msmsdcc_request_end(
1614 host,
1615 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301616 else if ((host->curr.mrq->sbc
1617 && data->error) ||
1618 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001619 msmsdcc_start_command(
1620 host,
1621 data->stop, 0);
1622 timer = 1;
1623 }
1624 } else {
1625 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001627 &dummy52cmd,
1628 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 }
1630 }
1631 }
1632 }
1633
San Mehat9d2bd732009-09-22 16:44:22 -07001634 ret = 1;
1635 } while (status);
1636
1637 spin_unlock(&host->lock);
1638
San Mehat9d2bd732009-09-22 16:44:22 -07001639 return IRQ_RETVAL(ret);
1640}
1641
1642static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1644{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301645 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301647 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301648 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1649 else
1650 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 } else {
1652 msmsdcc_start_command(host, mrq->cmd, 0);
1653 }
1654}
1655
1656static void
San Mehat9d2bd732009-09-22 16:44:22 -07001657msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1658{
1659 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 /*
1663 * Get the SDIO AL client out of LPM.
1664 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001665 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 if (host->plat->is_sdio_al_client)
1667 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001668
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301669 /* check if sps pipe reset is pending? */
1670 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1671 msmsdcc_sps_pipes_reset_and_restore(host);
1672 host->sps.pipe_reset_pending = false;
1673 }
1674
San Mehat9d2bd732009-09-22 16:44:22 -07001675 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 WARN(host->curr.mrq, "Request in progress\n");
1677 WARN(!host->pwr, "SDCC power is turned off\n");
1678 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1679 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001680
1681 if (host->eject) {
1682 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1683 mrq->cmd->error = 0;
1684 mrq->data->bytes_xfered = mrq->data->blksz *
1685 mrq->data->blocks;
1686 } else
1687 mrq->cmd->error = -ENOMEDIUM;
1688
1689 spin_unlock_irqrestore(&host->lock, flags);
1690 mmc_request_done(mmc, mrq);
1691 return;
1692 }
1693
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301694 /*
1695 * Kick the software command timeout timer here.
1696 * Timer expires in 10 secs.
1697 */
1698 mod_timer(&host->req_tout_timer,
1699 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001700
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301701 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301702 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301703 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1704 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301705 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301707 else
1708 /*
1709 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1710 * write operations using CMD53 and CMD54.
1711 * Setting this bit with CMD53 would
1712 * automatically triggers PROG_DONE interrupt
1713 * without the need of sending dummy CMD52.
1714 */
1715 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301716 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1717 host->sdcc_version) {
1718 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 }
San Mehat9d2bd732009-09-22 16:44:22 -07001720 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301721
Pratibhasagar V00b94332011-10-18 14:57:27 +05301722 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301723 mrq->sbc->mrq = mrq;
1724 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301725 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301726 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301727 msmsdcc_start_command(host, mrq->sbc, 0);
1728 } else {
1729 msmsdcc_request_start(host, mrq);
1730 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301731 } else {
1732 msmsdcc_request_start(host, mrq);
1733 }
1734
San Mehat9d2bd732009-09-22 16:44:22 -07001735 spin_unlock_irqrestore(&host->lock, flags);
1736}
1737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1739 int min_uV, int max_uV)
1740{
1741 int rc = 0;
1742
1743 if (vreg->set_voltage_sup) {
1744 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1745 if (rc) {
1746 pr_err("%s: regulator_set_voltage(%s) failed."
1747 " min_uV=%d, max_uV=%d, rc=%d\n",
1748 __func__, vreg->name, min_uV, max_uV, rc);
1749 }
1750 }
1751
1752 return rc;
1753}
1754
1755static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1756 int uA_load)
1757{
1758 int rc = 0;
1759
Krishna Kondafea60182011-11-01 16:01:34 -07001760 /* regulators that do not support regulator_set_voltage also
1761 do not support regulator_set_optimum_mode */
1762 if (vreg->set_voltage_sup) {
1763 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1764 if (rc < 0)
1765 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1766 "uA_load=%d) failed. rc=%d\n", __func__,
1767 vreg->name, uA_load, rc);
1768 else
1769 /* regulator_set_optimum_mode() can return non zero
1770 * value even for success case.
1771 */
1772 rc = 0;
1773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774
1775 return rc;
1776}
1777
1778static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1779 struct device *dev)
1780{
1781 int rc = 0;
1782
1783 /* check if regulator is already initialized? */
1784 if (vreg->reg)
1785 goto out;
1786
1787 /* Get the regulator handle */
1788 vreg->reg = regulator_get(dev, vreg->name);
1789 if (IS_ERR(vreg->reg)) {
1790 rc = PTR_ERR(vreg->reg);
1791 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1792 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001793 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001795
1796 if (regulator_count_voltages(vreg->reg) > 0)
1797 vreg->set_voltage_sup = 1;
1798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799out:
1800 return rc;
1801}
1802
1803static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1804{
1805 if (vreg->reg)
1806 regulator_put(vreg->reg);
1807}
1808
1809/* This init function should be called only once for each SDCC slot */
1810static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1811{
1812 int rc = 0;
1813 struct msm_mmc_slot_reg_data *curr_slot;
1814 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1815 struct device *dev = mmc_dev(host->mmc);
1816
1817 curr_slot = host->plat->vreg_data;
1818 if (!curr_slot)
1819 goto out;
1820
1821 curr_vdd_reg = curr_slot->vdd_data;
1822 curr_vccq_reg = curr_slot->vccq_data;
1823 curr_vddp_reg = curr_slot->vddp_data;
1824
1825 if (is_init) {
1826 /*
1827 * Get the regulator handle from voltage regulator framework
1828 * and then try to set the voltage level for the regulator
1829 */
1830 if (curr_vdd_reg) {
1831 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1832 if (rc)
1833 goto out;
1834 }
1835 if (curr_vccq_reg) {
1836 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1837 if (rc)
1838 goto vdd_reg_deinit;
1839 }
1840 if (curr_vddp_reg) {
1841 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1842 if (rc)
1843 goto vccq_reg_deinit;
1844 }
1845 goto out;
1846 } else {
1847 /* Deregister all regulators from regulator framework */
1848 goto vddp_reg_deinit;
1849 }
1850vddp_reg_deinit:
1851 if (curr_vddp_reg)
1852 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1853vccq_reg_deinit:
1854 if (curr_vccq_reg)
1855 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1856vdd_reg_deinit:
1857 if (curr_vdd_reg)
1858 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1859out:
1860 return rc;
1861}
1862
1863static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1864{
1865 int rc = 0;
1866
Subhash Jadavanicc922692011-08-01 23:05:01 +05301867 /* Put regulator in HPM (high power mode) */
1868 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1869 if (rc < 0)
1870 goto out;
1871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 if (!vreg->is_enabled) {
1873 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301874 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1875 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 if (rc)
1877 goto out;
1878
1879 rc = regulator_enable(vreg->reg);
1880 if (rc) {
1881 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1882 __func__, vreg->name, rc);
1883 goto out;
1884 }
1885 vreg->is_enabled = true;
1886 }
1887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888out:
1889 return rc;
1890}
1891
1892static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1893{
1894 int rc = 0;
1895
1896 /* Never disable regulator marked as always_on */
1897 if (vreg->is_enabled && !vreg->always_on) {
1898 rc = regulator_disable(vreg->reg);
1899 if (rc) {
1900 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1901 __func__, vreg->name, rc);
1902 goto out;
1903 }
1904 vreg->is_enabled = false;
1905
1906 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1907 if (rc < 0)
1908 goto out;
1909
1910 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301911 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 if (rc)
1913 goto out;
1914 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1915 /* Put always_on regulator in LPM (low power mode) */
1916 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1917 if (rc < 0)
1918 goto out;
1919 }
1920out:
1921 return rc;
1922}
1923
1924static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1925{
1926 int rc = 0, i;
1927 struct msm_mmc_slot_reg_data *curr_slot;
1928 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1929 struct msm_mmc_reg_data *vreg_table[3];
1930
1931 curr_slot = host->plat->vreg_data;
1932 if (!curr_slot)
1933 goto out;
1934
1935 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1936 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1937 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1938
1939 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1940 if (vreg_table[i]) {
1941 if (enable)
1942 rc = msmsdcc_vreg_enable(vreg_table[i]);
1943 else
1944 rc = msmsdcc_vreg_disable(vreg_table[i]);
1945 if (rc)
1946 goto out;
1947 }
1948 }
1949out:
1950 return rc;
1951}
1952
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301953static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954{
1955 int rc = 0;
1956
1957 if (host->plat->vreg_data) {
1958 struct msm_mmc_reg_data *vddp_reg =
1959 host->plat->vreg_data->vddp_data;
1960
1961 if (vddp_reg && vddp_reg->is_enabled)
1962 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1963 }
1964
1965 return rc;
1966}
1967
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301968static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1969{
1970 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1971 int rc = 0;
1972
1973 if (curr_slot && curr_slot->vddp_data) {
1974 rc = msmsdcc_set_vddp_level(host,
1975 curr_slot->vddp_data->low_vol_level);
1976
1977 if (rc)
1978 pr_err("%s: %s: failed to change vddp level to %d",
1979 mmc_hostname(host->mmc), __func__,
1980 curr_slot->vddp_data->low_vol_level);
1981 }
1982
1983 return rc;
1984}
1985
1986static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1987{
1988 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1989 int rc = 0;
1990
1991 if (curr_slot && curr_slot->vddp_data) {
1992 rc = msmsdcc_set_vddp_level(host,
1993 curr_slot->vddp_data->high_vol_level);
1994
1995 if (rc)
1996 pr_err("%s: %s: failed to change vddp level to %d",
1997 mmc_hostname(host->mmc), __func__,
1998 curr_slot->vddp_data->high_vol_level);
1999 }
2000
2001 return rc;
2002}
2003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
2005{
2006 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
2007 return 1;
2008 return 0;
2009}
2010
2011static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
2012{
2013 if (enable) {
2014 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2015 clk_enable(host->dfab_pclk);
2016 if (!IS_ERR(host->pclk))
2017 clk_enable(host->pclk);
2018 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302019 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302021 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 clk_disable(host->clk);
2023 if (!IS_ERR(host->pclk))
2024 clk_disable(host->pclk);
2025 if (!IS_ERR_OR_NULL(host->dfab_pclk))
2026 clk_disable(host->dfab_pclk);
2027 }
2028}
2029
2030static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
2031 unsigned int req_clk)
2032{
2033 unsigned int sel_clk = -1;
2034
2035 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
2036 unsigned char cnt;
2037
2038 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
2039 if (host->plat->sup_clk_table[cnt] > req_clk)
2040 break;
2041 else if (host->plat->sup_clk_table[cnt] == req_clk) {
2042 sel_clk = host->plat->sup_clk_table[cnt];
2043 break;
2044 } else
2045 sel_clk = host->plat->sup_clk_table[cnt];
2046 }
2047 } else {
2048 if ((req_clk < host->plat->msmsdcc_fmax) &&
2049 (req_clk > host->plat->msmsdcc_fmid))
2050 sel_clk = host->plat->msmsdcc_fmid;
2051 else
2052 sel_clk = req_clk;
2053 }
2054
2055 return sel_clk;
2056}
2057
2058static inline unsigned int msmsdcc_get_min_sup_clk_rate(
2059 struct msmsdcc_host *host)
2060{
2061 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2062 return host->plat->sup_clk_table[0];
2063 else
2064 return host->plat->msmsdcc_fmin;
2065}
2066
2067static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2068 struct msmsdcc_host *host)
2069{
2070 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2071 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2072 else
2073 return host->plat->msmsdcc_fmax;
2074}
2075
2076static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302077{
2078 struct msm_mmc_gpio_data *curr;
2079 int i, rc = 0;
2080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302082 for (i = 0; i < curr->size; i++) {
2083 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 if (curr->gpio[i].is_always_on &&
2085 curr->gpio[i].is_enabled)
2086 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302087 rc = gpio_request(curr->gpio[i].no,
2088 curr->gpio[i].name);
2089 if (rc) {
2090 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2091 mmc_hostname(host->mmc),
2092 curr->gpio[i].no,
2093 curr->gpio[i].name, rc);
2094 goto free_gpios;
2095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302097 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 if (curr->gpio[i].is_always_on)
2099 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302100 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302102 }
2103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302105
2106free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302108 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109 curr->gpio[i].is_enabled = false;
2110 }
2111out:
2112 return rc;
2113}
2114
2115static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2116{
2117 struct msm_mmc_pad_data *curr;
2118 int i;
2119
2120 curr = host->plat->pin_data->pad_data;
2121 for (i = 0; i < curr->drv->size; i++) {
2122 if (enable)
2123 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2124 curr->drv->on[i].val);
2125 else
2126 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2127 curr->drv->off[i].val);
2128 }
2129
2130 for (i = 0; i < curr->pull->size; i++) {
2131 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002132 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 curr->pull->on[i].val);
2134 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002135 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 curr->pull->off[i].val);
2137 }
2138
2139 return 0;
2140}
2141
2142static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2143{
2144 int rc = 0;
2145
2146 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2147 return 0;
2148
2149 if (host->plat->pin_data->is_gpio)
2150 rc = msmsdcc_setup_gpio(host, enable);
2151 else
2152 rc = msmsdcc_setup_pad(host, enable);
2153
2154 if (!rc)
2155 host->plat->pin_data->cfg_sts = enable;
2156
2157 return rc;
2158}
2159
2160static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2161{
2162 unsigned int wakeup_irq;
2163
2164 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2165 host->plat->sdiowakeup_irq :
2166 host->core_irqres->start;
2167
2168 if (!host->irq_wake_enabled) {
2169 enable_irq_wake(wakeup_irq);
2170 host->irq_wake_enabled = true;
2171 }
2172}
2173
2174static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2175{
2176 unsigned int wakeup_irq;
2177
2178 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2179 host->plat->sdiowakeup_irq :
2180 host->core_irqres->start;
2181
2182 if (host->irq_wake_enabled) {
2183 disable_irq_wake(wakeup_irq);
2184 host->irq_wake_enabled = false;
2185 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302186}
2187
San Mehat9d2bd732009-09-22 16:44:22 -07002188static void
2189msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2190{
2191 struct msmsdcc_host *host = mmc_priv(mmc);
2192 u32 clk = 0, pwr = 0;
2193 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002194 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302198
San Mehat9d2bd732009-09-22 16:44:22 -07002199 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200 spin_lock_irqsave(&host->lock, flags);
2201 if (!host->clks_on) {
2202 msmsdcc_setup_clocks(host, true);
2203 host->clks_on = 1;
2204 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2205 if (!host->plat->sdiowakeup_irq) {
2206 writel_relaxed(host->mci_irqenable,
2207 host->base + MMCIMASK0);
2208 mb();
2209 if (host->plat->cfg_mpm_sdiowakeup &&
2210 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2211 host->plat->cfg_mpm_sdiowakeup(
2212 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2213 msmsdcc_disable_irq_wake(host);
2214 } else if (!(mmc->pm_flags &
2215 MMC_PM_WAKE_SDIO_IRQ)) {
2216 writel_relaxed(host->mci_irqenable,
2217 host->base + MMCIMASK0);
2218 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302219 } else {
2220 writel_relaxed(host->mci_irqenable,
2221 host->base + MMCIMASK0);
2222 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 }
San Mehat9d2bd732009-09-22 16:44:22 -07002224 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225 spin_unlock_irqrestore(&host->lock, flags);
2226
2227 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2228 /*
2229 * For DDR50 mode, controller needs clock rate to be
2230 * double than what is required on the SD card CLK pin.
2231 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302232 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 /*
2234 * Make sure that we don't double the clock if
2235 * doubled clock rate is already set
2236 */
2237 if (!host->ddr_doubled_clk_rate ||
2238 (host->ddr_doubled_clk_rate &&
2239 (host->ddr_doubled_clk_rate != ios->clock))) {
2240 host->ddr_doubled_clk_rate =
2241 msmsdcc_get_sup_clk_rate(
2242 host, (ios->clock * 2));
2243 clock = host->ddr_doubled_clk_rate;
2244 }
2245 } else {
2246 host->ddr_doubled_clk_rate = 0;
2247 }
2248
2249 if (clock != host->clk_rate) {
2250 rc = clk_set_rate(host->clk, clock);
2251 if (rc < 0)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302252 pr_err("%s: failed to set clk rate %u\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 mmc_hostname(mmc), clock);
2254 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302255 host->reg_write_delay =
2256 (1 + ((3 * USEC_PER_SEC) /
2257 (host->clk_rate ? host->clk_rate :
2258 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 }
2260 /*
2261 * give atleast 2 MCLK cycles delay for clocks
2262 * and SDCC core to stabilize
2263 */
2264 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002265 clk |= MCI_CLK_ENABLE;
2266 }
2267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 if (ios->bus_width == MMC_BUS_WIDTH_8)
2269 clk |= MCI_CLK_WIDEBUS_8;
2270 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2271 clk |= MCI_CLK_WIDEBUS_4;
2272 else
2273 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 if (msmsdcc_is_pwrsave(host))
2276 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 host->tuning_needed = 0;
2281 /*
2282 * Select the controller timing mode according
2283 * to current bus speed mode
2284 */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302285 if (ios->timing == MMC_TIMING_UHS_SDR104) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 clk |= (4 << 14);
2287 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302288 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 clk |= (3 << 14);
2290 } else {
2291 clk |= (2 << 14); /* feedback clock */
2292 }
2293
2294 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2295 clk |= (2 << 23);
2296
2297 if (host->io_pad_pwr_switch)
2298 clk |= IO_PAD_PWR_SWITCH;
2299
2300 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002301 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2303 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002304
2305 switch (ios->power_mode) {
2306 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2308 if (!host->sdcc_irq_disabled) {
2309 if (host->plat->cfg_mpm_sdiowakeup)
2310 host->plat->cfg_mpm_sdiowakeup(
2311 mmc_dev(mmc), SDC_DAT1_DISABLE);
2312 disable_irq(host->core_irqres->start);
2313 host->sdcc_irq_disabled = 1;
2314 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302315 /*
2316 * As VDD pad rail is always on, set low voltage for VDD
2317 * pad rail when slot is unused (when card is not present
2318 * or during system suspend).
2319 */
2320 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002322 break;
2323 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302324 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002325 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 if (host->sdcc_irq_disabled) {
2327 if (host->plat->cfg_mpm_sdiowakeup)
2328 host->plat->cfg_mpm_sdiowakeup(
2329 mmc_dev(mmc), SDC_DAT1_ENABLE);
2330 enable_irq(host->core_irqres->start);
2331 host->sdcc_irq_disabled = 0;
2332 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302333 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002335 break;
2336 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002338 pwr |= MCI_PWR_ON;
2339 break;
2340 }
2341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342 spin_lock_irqsave(&host->lock, flags);
2343 if (!host->clks_on) {
2344 /* force the clocks to be on */
2345 msmsdcc_setup_clocks(host, true);
2346 /*
2347 * give atleast 2 MCLK cycles delay for clocks
2348 * and SDCC core to stabilize
2349 */
2350 msmsdcc_delay(host);
2351 }
2352 writel_relaxed(clk, host->base + MMCICLOCK);
2353 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002354
2355 if (host->pwr != pwr) {
2356 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302358 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002359 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 if (!host->clks_on) {
2361 /* force the clocks to be off */
2362 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 }
2364
2365 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2366 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2367 if (!host->plat->sdiowakeup_irq) {
2368 writel_relaxed(MCI_SDIOINTMASK,
2369 host->base + MMCIMASK0);
2370 mb();
2371 if (host->plat->cfg_mpm_sdiowakeup &&
2372 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2373 host->plat->cfg_mpm_sdiowakeup(
2374 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2375 msmsdcc_enable_irq_wake(host);
2376 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2377 writel_relaxed(0, host->base + MMCIMASK0);
2378 } else {
2379 writel_relaxed(MCI_SDIOINTMASK,
2380 host->base + MMCIMASK0);
2381 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302382 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 }
2384 msmsdcc_setup_clocks(host, false);
2385 host->clks_on = 0;
2386 }
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302387
2388 if (host->cmd19_tuning_in_progress)
2389 WARN(!host->clks_on,
2390 "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
2391
San Mehat4adbbcc2009-11-08 13:00:37 -08002392 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002393}
2394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2396{
2397 struct msmsdcc_host *host = mmc_priv(mmc);
2398 u32 clk;
2399
2400 clk = readl_relaxed(host->base + MMCICLOCK);
2401 pr_debug("Changing to pwr_save=%d", pwrsave);
2402 if (pwrsave && msmsdcc_is_pwrsave(host))
2403 clk |= MCI_CLK_PWRSAVE;
2404 else
2405 clk &= ~MCI_CLK_PWRSAVE;
2406 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302407 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408
2409 return 0;
2410}
2411
2412static int msmsdcc_get_ro(struct mmc_host *mmc)
2413{
2414 int status = -ENOSYS;
2415 struct msmsdcc_host *host = mmc_priv(mmc);
2416
2417 if (host->plat->wpswitch) {
2418 status = host->plat->wpswitch(mmc_dev(mmc));
2419 } else if (host->plat->wpswitch_gpio) {
2420 status = gpio_request(host->plat->wpswitch_gpio,
2421 "SD_WP_Switch");
2422 if (status) {
2423 pr_err("%s: %s: Failed to request GPIO %d\n",
2424 mmc_hostname(mmc), __func__,
2425 host->plat->wpswitch_gpio);
2426 } else {
2427 status = gpio_direction_input(
2428 host->plat->wpswitch_gpio);
2429 if (!status) {
2430 /*
2431 * Wait for atleast 300ms as debounce
2432 * time for GPIO input to stabilize.
2433 */
2434 msleep(300);
2435 status = gpio_get_value_cansleep(
2436 host->plat->wpswitch_gpio);
2437 status ^= !host->plat->wpswitch_polarity;
2438 }
2439 gpio_free(host->plat->wpswitch_gpio);
2440 }
2441 }
2442
2443 if (status < 0)
2444 status = -ENOSYS;
2445 pr_debug("%s: Card read-only status %d\n", __func__, status);
2446
2447 return status;
2448}
2449
2450#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002451static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2452{
2453 struct msmsdcc_host *host = mmc_priv(mmc);
2454 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455
2456 if (enable) {
2457 spin_lock_irqsave(&host->lock, flags);
2458 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2459 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2460 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2461 spin_unlock_irqrestore(&host->lock, flags);
2462 } else {
2463 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2464 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2465 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2466 }
2467 mb();
2468}
2469#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2470
2471#ifdef CONFIG_PM_RUNTIME
2472static int msmsdcc_enable(struct mmc_host *mmc)
2473{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302474 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 struct device *dev = mmc->parent;
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302476 struct msmsdcc_host *host = mmc_priv(mmc);
2477
2478 msmsdcc_pm_qos_update_latency(host, 1);
2479
2480 if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
2481 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302483 if (dev->power.runtime_status == RPM_SUSPENDING) {
2484 if (mmc->suspend_task == current) {
2485 pm_runtime_get_noresume(dev);
2486 goto out;
2487 }
2488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302490 rc = pm_runtime_get_sync(dev);
2491
2492 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2494 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302495 return rc;
2496 }
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302497
2498 host->is_resumed = true;
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302499out:
2500 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501}
2502
2503static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2504{
2505 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302506 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002507
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302508 msmsdcc_pm_qos_update_latency(host, 0);
2509
2510 if (mmc->card && mmc_card_sdio(mmc->card))
2511 return 0;
2512
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302513 if (host->plat->disable_runtime_pm)
2514 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515
2516 rc = pm_runtime_put_sync(mmc->parent);
2517
2518 if (rc < 0)
2519 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2520 __func__, rc);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302521 else
2522 host->is_resumed = false;
2523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002524 return rc;
2525}
2526#else
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302527static int msmsdcc_enable(struct mmc_host *mmc)
2528{
2529 struct msmsdcc_host *host = mmc_priv(mmc);
2530 unsigned long flags;
2531
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302532 msmsdcc_pm_qos_update_latency(host, 1);
2533
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302534 spin_lock_irqsave(&host->lock, flags);
2535 if (!host->clks_on) {
2536 msmsdcc_setup_clocks(host, true);
2537 host->clks_on = 1;
2538 }
2539 spin_unlock_irqrestore(&host->lock, flags);
2540
2541 return 0;
2542}
2543
2544static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2545{
2546 struct msmsdcc_host *host = mmc_priv(mmc);
2547 unsigned long flags;
2548
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302549 msmsdcc_pm_qos_update_latency(host, 0);
2550
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302551 if (mmc->card && mmc_card_sdio(mmc->card))
Subhash Jadavani933e6a62011-12-26 18:05:04 +05302552 return 0;
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05302553
2554 spin_lock_irqsave(&host->lock, flags);
2555 if (host->clks_on) {
2556 msmsdcc_setup_clocks(host, false);
2557 host->clks_on = 0;
2558 }
2559 spin_unlock_irqrestore(&host->lock, flags);
2560
2561 return 0;
2562}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563#endif
2564
2565static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2566 struct mmc_ios *ios)
2567{
2568 struct msmsdcc_host *host = mmc_priv(mmc);
2569 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302570 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571
2572 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2573 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302574 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575 goto out;
2576 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2577 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302578 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 goto out;
2580 }
San Mehat9d2bd732009-09-22 16:44:22 -07002581
2582 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583 /*
2584 * If we are here means voltage switch from high voltage to
2585 * low voltage is required
2586 */
2587
2588 /*
2589 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2590 * register until they become all zeros.
2591 */
2592 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302593 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2595 mmc_hostname(mmc), __func__);
2596 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002597 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002598
2599 /* Stop SD CLK output. */
2600 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2601 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302602 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002603 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604
2605 /*
2606 * Switch VDDPX from high voltage to low voltage
2607 * to change the VDD of the SD IO pads.
2608 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302609 rc = msmsdcc_set_vddp_low_vol(host);
2610 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612
2613 spin_lock_irqsave(&host->lock, flags);
2614 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2615 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302616 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 host->io_pad_pwr_switch = 1;
2618 spin_unlock_irqrestore(&host->lock, flags);
2619
2620 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2621 usleep_range(5000, 5500);
2622
2623 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302624 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2626 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302627 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 spin_unlock_irqrestore(&host->lock, flags);
2629
2630 /*
2631 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2632 * don't become all ones within 1 ms then a Voltage Switch
2633 * sequence has failed and a power cycle to the card is required.
2634 * Otherwise Voltage Switch sequence is completed successfully.
2635 */
2636 usleep_range(1000, 1500);
2637
2638 spin_lock_irqsave(&host->lock, flags);
2639 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2640 != (0xF << 1)) {
2641 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2642 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302643 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 goto out_unlock;
2645 }
2646
2647out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302648 /* Enable PWRSAVE */
2649 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2650 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 spin_unlock_irqrestore(&host->lock, flags);
2652out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302653 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654}
2655
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302656static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 u32 mclk_freq = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659
2660 /* Program the MCLK value to MCLK_FREQ bit field */
2661 if (host->clk_rate <= 112000000)
2662 mclk_freq = 0;
2663 else if (host->clk_rate <= 125000000)
2664 mclk_freq = 1;
2665 else if (host->clk_rate <= 137000000)
2666 mclk_freq = 2;
2667 else if (host->clk_rate <= 150000000)
2668 mclk_freq = 3;
2669 else if (host->clk_rate <= 162000000)
2670 mclk_freq = 4;
2671 else if (host->clk_rate <= 175000000)
2672 mclk_freq = 5;
2673 else if (host->clk_rate <= 187000000)
2674 mclk_freq = 6;
2675 else if (host->clk_rate <= 200000000)
2676 mclk_freq = 7;
2677
2678 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2679 & ~(7 << 24)) | (mclk_freq << 24)),
2680 host->base + MCI_DLL_CONFIG);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002681}
2682
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302683/* Initialize the DLL (Programmable Delay Line ) */
2684static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002685{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 int rc = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302687 unsigned long flags;
2688 u32 wait_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302690 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 /*
2692 * Make sure that clock is always enabled when DLL
2693 * tuning is in progress. Keeping PWRSAVE ON may
2694 * turn off the clock. So let's disable the PWRSAVE
2695 * here and re-enable it once tuning is completed.
2696 */
2697 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2698 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302699
2700 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2701 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2702 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2703
2704 /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
2705 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2706 | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2707
2708 msmsdcc_cm_sdc4_dll_set_freq(host);
2709
2710 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2711 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2712 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2713
2714 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2715 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2716 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2717
2718 /* Set DLL_EN bit to 1. */
2719 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2720 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2721
2722 /* Set CK_OUT_EN bit to 1. */
2723 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2724 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2725
2726 wait_cnt = 50;
2727 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2728 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2729 /* max. wait for 50us sec for LOCK bit to be set */
2730 if (--wait_cnt == 0) {
2731 pr_err("%s: %s: DLL failed to LOCK\n",
2732 mmc_hostname(host->mmc), __func__);
2733 rc = -ETIMEDOUT;
2734 goto out;
2735 }
2736 /* wait for 1us before polling again */
2737 udelay(1);
2738 }
2739
2740out:
2741 /* re-enable PWRSAVE */
2742 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2743 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
2744 spin_unlock_irqrestore(&host->lock, flags);
2745
2746 return rc;
2747}
2748
2749static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
2750 u8 poll)
2751{
2752 int rc = 0;
2753 u32 wait_cnt = 50;
2754 u8 ck_out_en = 0;
2755
2756 /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
2757 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2758 MCI_CK_OUT_EN);
2759
2760 while (ck_out_en != poll) {
2761 if (--wait_cnt == 0) {
2762 pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
2763 mmc_hostname(host->mmc), __func__, poll);
2764 rc = -ETIMEDOUT;
2765 goto out;
2766 }
2767 udelay(1);
2768
2769 ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
2770 MCI_CK_OUT_EN);
2771 }
2772out:
2773 return rc;
2774}
2775
2776/*
2777 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2778 * calibration sequence. This function should be called before
2779 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2780 * commands (CMD17/CMD18).
2781 *
2782 * This function gets called when host spinlock acquired.
2783 */
2784static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2785{
2786 int rc = 0;
2787 u32 config;
2788
2789 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2790 config |= MCI_CDR_EN;
2791 config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
2792 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2793
2794 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2795 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2796 if (rc)
2797 goto err_out;
2798
2799 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2800 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2801 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2802
2803 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2804 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2805 if (rc)
2806 goto err_out;
2807
2808 goto out;
2809
2810err_out:
2811 pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
2812out:
2813 return rc;
2814}
2815
2816static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2817 u8 phase)
2818{
2819 int rc = 0;
Subhash Jadavanifac0a092012-02-01 20:01:04 +05302820 u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
2821 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
2822 0x8};
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302823 unsigned long flags;
2824 u32 config;
2825
2826 spin_lock_irqsave(&host->lock, flags);
2827
2828 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2829 config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
2830 config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
2831 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2832
2833 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2834 rc = msmsdcc_dll_poll_ck_out_en(host, 0);
2835 if (rc)
2836 goto err_out;
2837
2838 /*
2839 * Write the selected DLL clock output phase (0 ... 15)
2840 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2841 */
2842 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2843 & ~(0xF << 20))
2844 | (grey_coded_phase_table[phase] << 20)),
2845 host->base + MCI_DLL_CONFIG);
2846
2847 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2848 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2849 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2850
2851 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2852 rc = msmsdcc_dll_poll_ck_out_en(host, 1);
2853 if (rc)
2854 goto err_out;
2855
2856 config = readl_relaxed(host->base + MCI_DLL_CONFIG);
2857 config |= MCI_CDR_EN;
2858 config &= ~MCI_CDR_EXT_EN;
2859 writel_relaxed(config, host->base + MCI_DLL_CONFIG);
2860 goto out;
2861
2862err_out:
2863 pr_err("%s: %s: Failed to set DLL phase: %d\n",
2864 mmc_hostname(host->mmc), __func__, phase);
2865out:
2866 spin_unlock_irqrestore(&host->lock, flags);
2867 return rc;
2868}
2869
2870/*
2871 * Find out the greatest range of consecuitive selected
2872 * DLL clock output phases that can be used as sampling
2873 * setting for SD3.0 UHS-I card read operation (in SDR104
2874 * timing mode) or for eMMC4.5 card read operation (in HS200
2875 * timing mode).
2876 * Select the 3/4 of the range and configure the DLL with the
2877 * selected DLL clock output phase.
2878*/
2879
2880static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
2881 u8 *phase_table, u8 total_phases)
2882{
2883 u8 ret, temp;
2884 u8 ranges[16][16] = { {0}, {0} };
2885 u8 phases_per_row[16] = {0};
2886 int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
2887 int cnt;
2888
2889 for (cnt = 0; cnt <= total_phases; cnt++) {
2890 ranges[row_index][col_index] = phase_table[cnt];
2891 phases_per_row[row_index] += 1;
2892 col_index++;
2893
2894 if ((cnt + 1) > total_phases) {
2895 continue;
2896 /* check if next phase in phase_table is consecutive or not */
2897 } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
2898 row_index++;
2899 col_index = 0;
2900 }
2901 }
2902
2903 for (cnt = 0; cnt <= total_phases; cnt++) {
2904 if (phases_per_row[cnt] > curr_max) {
2905 curr_max = phases_per_row[cnt];
2906 selected_row_index = cnt;
2907 }
2908 }
2909
2910 temp = ((curr_max * 3) / 4);
2911 ret = ranges[selected_row_index][temp];
2912
2913 return ret;
2914}
2915
2916static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2917{
2918 int rc = 0;
2919 struct msmsdcc_host *host = mmc_priv(mmc);
2920 unsigned long flags;
2921 u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
2922
2923 pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
2924
2925 /* Tuning is only required for SDR104 modes */
2926 if (!host->tuning_needed) {
2927 rc = 0;
2928 goto exit;
2929 }
2930
2931 spin_lock_irqsave(&host->lock, flags);
2932 WARN(!host->pwr, "SDCC power is turned off\n");
2933 WARN(!host->clks_on, "SDCC clocks are turned off\n");
2934 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
2935
2936 host->cmd19_tuning_in_progress = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302937 msmsdcc_delay(host);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302938 spin_unlock_irqrestore(&host->lock, flags);
2939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940 /* first of all reset the tuning block */
2941 rc = msmsdcc_init_cm_sdc4_dll(host);
2942 if (rc)
2943 goto out;
2944
2945 data_buf = kmalloc(64, GFP_KERNEL);
2946 if (!data_buf) {
2947 rc = -ENOMEM;
2948 goto out;
2949 }
2950
2951 phase = 0;
2952 do {
2953 struct mmc_command cmd = {0};
2954 struct mmc_data data = {0};
2955 struct mmc_request mrq = {
2956 .cmd = &cmd,
2957 .data = &data
2958 };
2959 struct scatterlist sg;
2960
2961 /* set the phase in delay line hw block */
2962 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2963 if (rc)
2964 goto kfree;
2965
2966 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2967 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2968
2969 data.blksz = 64;
2970 data.blocks = 1;
2971 data.flags = MMC_DATA_READ;
2972 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2973
2974 data.sg = &sg;
2975 data.sg_len = 1;
2976 sg_init_one(&sg, data_buf, 64);
2977 memset(data_buf, 0, 64);
2978 mmc_wait_for_req(mmc, &mrq);
2979
2980 if (!cmd.error && !data.error &&
2981 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2982 /* tuning is successful with this tuning point */
2983 tuned_phases[tuned_phase_cnt++] = phase;
2984 }
2985 } while (++phase < 16);
2986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987 if (tuned_phase_cnt) {
2988 tuned_phase_cnt--;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302989 phase = find_most_appropriate_phase(host, tuned_phases,
2990 tuned_phase_cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002991 /*
2992 * Finally set the selected phase in delay
2993 * line hw block.
2994 */
2995 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2996 if (rc)
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05302997 goto kfree;
2998 pr_debug("%s: %s: finally setting the tuning phase to %d\n",
2999 mmc_hostname(mmc), __func__, phase);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 } else {
3001 /* tuning failed */
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303002 pr_err("%s: %s: no tuning point found\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 mmc_hostname(mmc), __func__);
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303004 msmsdcc_dump_sdcc_state(host);
3005 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007
3008kfree:
3009 kfree(data_buf);
3010out:
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303011 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303012 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013 host->cmd19_tuning_in_progress = 0;
Subhash Jadavanib52b4d72011-12-05 19:16:28 +05303014 spin_unlock_irqrestore(&host->lock, flags);
3015exit:
3016 pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003017 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07003018}
3019
3020static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 .enable = msmsdcc_enable,
3022 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07003023 .request = msmsdcc_request,
3024 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 .get_ro = msmsdcc_get_ro,
3026#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07003027 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028#endif
3029 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
3030 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07003031};
3032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003033static unsigned int
3034msmsdcc_slot_status(struct msmsdcc_host *host)
3035{
3036 int status;
3037 unsigned int gpio_no = host->plat->status_gpio;
3038
3039 status = gpio_request(gpio_no, "SD_HW_Detect");
3040 if (status) {
3041 pr_err("%s: %s: Failed to request GPIO %d\n",
3042 mmc_hostname(host->mmc), __func__, gpio_no);
3043 } else {
3044 status = gpio_direction_input(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003045 if (!status) {
Krishna Konda360aa422011-12-06 18:27:41 -08003046 status = gpio_get_value_cansleep(gpio_no);
Krishna Konda941604a2012-01-10 17:46:34 -08003047 if (host->plat->is_status_gpio_active_low)
3048 status = !status;
3049 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003050 gpio_free(gpio_no);
3051 }
3052 return status;
3053}
3054
San Mehat9d2bd732009-09-22 16:44:22 -07003055static void
3056msmsdcc_check_status(unsigned long data)
3057{
3058 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3059 unsigned int status;
3060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003061 if (host->plat->status || host->plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08003062 if (host->plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063 status = host->plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08003064 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003065 status = msmsdcc_slot_status(host);
3066
Krishna Konda941604a2012-01-10 17:46:34 -08003067 host->eject = !status;
Krishna Konda360aa422011-12-06 18:27:41 -08003068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 if (status ^ host->oldstat) {
Krishna Konda360aa422011-12-06 18:27:41 -08003070 if (host->plat->status)
3071 pr_info("%s: Slot status change detected "
3072 "(%d -> %d)\n",
3073 mmc_hostname(host->mmc),
3074 host->oldstat, status);
3075 else if (host->plat->is_status_gpio_active_low)
3076 pr_info("%s: Slot status change detected "
3077 "(%d -> %d) and the card detect GPIO"
3078 " is ACTIVE_LOW\n",
3079 mmc_hostname(host->mmc),
3080 host->oldstat, status);
3081 else
3082 pr_info("%s: Slot status change detected "
3083 "(%d -> %d) and the card detect GPIO"
3084 " is ACTIVE_HIGH\n",
3085 mmc_hostname(host->mmc),
3086 host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07003087 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 }
3089 host->oldstat = status;
3090 } else {
3091 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07003092 }
San Mehat9d2bd732009-09-22 16:44:22 -07003093}
3094
3095static irqreturn_t
3096msmsdcc_platform_status_irq(int irq, void *dev_id)
3097{
3098 struct msmsdcc_host *host = dev_id;
3099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07003101 msmsdcc_check_status((unsigned long) host);
3102 return IRQ_HANDLED;
3103}
3104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105static irqreturn_t
3106msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
3107{
3108 struct msmsdcc_host *host = dev_id;
3109
3110 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
3111 spin_lock(&host->lock);
3112 if (!host->sdio_irq_disabled) {
3113 disable_irq_nosync(irq);
3114 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
3115 wake_lock(&host->sdio_wlock);
3116 msmsdcc_disable_irq_wake(host);
3117 }
3118 host->sdio_irq_disabled = 1;
3119 }
3120 if (host->plat->is_sdio_al_client) {
3121 if (!host->clks_on) {
3122 msmsdcc_setup_clocks(host, true);
3123 host->clks_on = 1;
3124 }
3125 if (host->sdcc_irq_disabled) {
3126 writel_relaxed(host->mci_irqenable,
3127 host->base + MMCIMASK0);
3128 mb();
3129 enable_irq(host->core_irqres->start);
3130 host->sdcc_irq_disabled = 0;
3131 }
3132 wake_lock(&host->sdio_wlock);
3133 }
3134 spin_unlock(&host->lock);
3135
3136 return IRQ_HANDLED;
3137}
3138
San Mehat9d2bd732009-09-22 16:44:22 -07003139static void
3140msmsdcc_status_notify_cb(int card_present, void *dev_id)
3141{
3142 struct msmsdcc_host *host = dev_id;
3143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07003145 card_present);
3146 msmsdcc_check_status((unsigned long) host);
3147}
3148
San Mehat9d2bd732009-09-22 16:44:22 -07003149static int
3150msmsdcc_init_dma(struct msmsdcc_host *host)
3151{
3152 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
3153 host->dma.host = host;
3154 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003155 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003156
3157 if (!host->dmares)
3158 return -ENODEV;
3159
3160 host->dma.nc = dma_alloc_coherent(NULL,
3161 sizeof(struct msmsdcc_nc_dmadata),
3162 &host->dma.nc_busaddr,
3163 GFP_KERNEL);
3164 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003165 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07003166 return -ENOMEM;
3167 }
3168 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
3169 host->dma.cmd_busaddr = host->dma.nc_busaddr;
3170 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
3171 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
3172 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07003173 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07003174
3175 return 0;
3176}
3177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003178#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
3179/**
3180 * Allocate and Connect a SDCC peripheral's SPS endpoint
3181 *
3182 * This function allocates endpoint context and
3183 * connect it with memory endpoint by calling
3184 * appropriate SPS driver APIs.
3185 *
3186 * Also registers a SPS callback function with
3187 * SPS driver
3188 *
3189 * This function should only be called once typically
3190 * during driver probe.
3191 *
3192 * @host - Pointer to sdcc host structure
3193 * @ep - Pointer to sps endpoint data structure
3194 * @is_produce - 1 means Producer endpoint
3195 * 0 means Consumer endpoint
3196 *
3197 * @return - 0 if successful else negative value.
3198 *
3199 */
3200static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
3201 struct msmsdcc_sps_ep_conn_data *ep,
3202 bool is_producer)
3203{
3204 int rc = 0;
3205 struct sps_pipe *sps_pipe_handle;
3206 struct sps_connect *sps_config = &ep->config;
3207 struct sps_register_event *sps_event = &ep->event;
3208
3209 /* Allocate endpoint context */
3210 sps_pipe_handle = sps_alloc_endpoint();
3211 if (!sps_pipe_handle) {
3212 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
3213 mmc_hostname(host->mmc), is_producer);
3214 rc = -ENOMEM;
3215 goto out;
3216 }
3217
3218 /* Get default connection configuration for an endpoint */
3219 rc = sps_get_config(sps_pipe_handle, sps_config);
3220 if (rc) {
3221 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
3222 " rc=%d", mmc_hostname(host->mmc),
3223 (u32)sps_pipe_handle, rc);
3224 goto get_config_err;
3225 }
3226
3227 /* Modify the default connection configuration */
3228 if (is_producer) {
3229 /*
3230 * For SDCC producer transfer, source should be
3231 * SDCC peripheral where as destination should
3232 * be system memory.
3233 */
3234 sps_config->source = host->sps.bam_handle;
3235 sps_config->destination = SPS_DEV_HANDLE_MEM;
3236 /* Producer pipe will handle this connection */
3237 sps_config->mode = SPS_MODE_SRC;
3238 sps_config->options =
3239 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3240 } else {
3241 /*
3242 * For SDCC consumer transfer, source should be
3243 * system memory where as destination should
3244 * SDCC peripheral
3245 */
3246 sps_config->source = SPS_DEV_HANDLE_MEM;
3247 sps_config->destination = host->sps.bam_handle;
3248 sps_config->mode = SPS_MODE_DEST;
3249 sps_config->options =
3250 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3251 }
3252
3253 /* Producer pipe index */
3254 sps_config->src_pipe_index = host->sps.src_pipe_index;
3255 /* Consumer pipe index */
3256 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3257 /*
3258 * This event thresold value is only significant for BAM-to-BAM
3259 * transfer. It's ignored for BAM-to-System mode transfer.
3260 */
3261 sps_config->event_thresh = 0x10;
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05303262
3263 /* Allocate maximum descriptor fifo size */
3264 sps_config->desc.size = SPS_MAX_DESC_FIFO_SIZE -
3265 (SPS_MAX_DESC_FIFO_SIZE % SPS_MAX_DESC_LENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3267 sps_config->desc.size,
3268 &sps_config->desc.phys_base,
3269 GFP_KERNEL);
3270
Pratibhasagar V00b94332011-10-18 14:57:27 +05303271 if (!sps_config->desc.base) {
3272 rc = -ENOMEM;
3273 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3274 , mmc_hostname(host->mmc));
3275 goto get_config_err;
3276 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3278
3279 /* Establish connection between peripheral and memory endpoint */
3280 rc = sps_connect(sps_pipe_handle, sps_config);
3281 if (rc) {
3282 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3283 " rc=%d", mmc_hostname(host->mmc),
3284 (u32)sps_pipe_handle, rc);
3285 goto sps_connect_err;
3286 }
3287
3288 sps_event->mode = SPS_TRIGGER_CALLBACK;
3289 sps_event->options = SPS_O_EOT;
3290 sps_event->callback = msmsdcc_sps_complete_cb;
3291 sps_event->xfer_done = NULL;
3292 sps_event->user = (void *)host;
3293
3294 /* Register callback event for EOT (End of transfer) event. */
3295 rc = sps_register_event(sps_pipe_handle, sps_event);
3296 if (rc) {
3297 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3298 " rc=%d", mmc_hostname(host->mmc),
3299 (u32)sps_pipe_handle, rc);
3300 goto reg_event_err;
3301 }
3302 /* Now save the sps pipe handle */
3303 ep->pipe_handle = sps_pipe_handle;
3304 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3305 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3306 __func__, is_producer ? "READ" : "WRITE",
3307 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3308 goto out;
3309
3310reg_event_err:
3311 sps_disconnect(sps_pipe_handle);
3312sps_connect_err:
3313 dma_free_coherent(mmc_dev(host->mmc),
3314 sps_config->desc.size,
3315 sps_config->desc.base,
3316 sps_config->desc.phys_base);
3317get_config_err:
3318 sps_free_endpoint(sps_pipe_handle);
3319out:
3320 return rc;
3321}
3322
3323/**
3324 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3325 *
3326 * This function disconnect endpoint and deallocates
3327 * endpoint context.
3328 *
3329 * This function should only be called once typically
3330 * during driver remove.
3331 *
3332 * @host - Pointer to sdcc host structure
3333 * @ep - Pointer to sps endpoint data structure
3334 *
3335 */
3336static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3337 struct msmsdcc_sps_ep_conn_data *ep)
3338{
3339 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3340 struct sps_connect *sps_config = &ep->config;
3341 struct sps_register_event *sps_event = &ep->event;
3342
3343 sps_event->xfer_done = NULL;
3344 sps_event->callback = NULL;
3345 sps_register_event(sps_pipe_handle, sps_event);
3346 sps_disconnect(sps_pipe_handle);
3347 dma_free_coherent(mmc_dev(host->mmc),
3348 sps_config->desc.size,
3349 sps_config->desc.base,
3350 sps_config->desc.phys_base);
3351 sps_free_endpoint(sps_pipe_handle);
3352}
3353
3354/**
3355 * Reset SDCC peripheral's SPS endpoint
3356 *
3357 * This function disconnects an endpoint.
3358 *
3359 * This function should be called for reseting
3360 * SPS endpoint when data transfer error is
3361 * encountered during data transfer. This
3362 * can be considered as soft reset to endpoint.
3363 *
3364 * This function should only be called if
3365 * msmsdcc_sps_init() is already called.
3366 *
3367 * @host - Pointer to sdcc host structure
3368 * @ep - Pointer to sps endpoint data structure
3369 *
3370 * @return - 0 if successful else negative value.
3371 */
3372static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3373 struct msmsdcc_sps_ep_conn_data *ep)
3374{
3375 int rc = 0;
3376 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3377
3378 rc = sps_disconnect(sps_pipe_handle);
3379 if (rc) {
3380 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3381 " rc=%d", mmc_hostname(host->mmc), __func__,
3382 (u32)sps_pipe_handle, rc);
3383 goto out;
3384 }
3385 out:
3386 return rc;
3387}
3388
3389/**
3390 * Restore SDCC peripheral's SPS endpoint
3391 *
3392 * This function connects an endpoint.
3393 *
3394 * This function should be called for restoring
3395 * SPS endpoint after data transfer error is
3396 * encountered during data transfer. This
3397 * can be considered as soft reset to endpoint.
3398 *
3399 * This function should only be called if
3400 * msmsdcc_sps_reset_ep() is called before.
3401 *
3402 * @host - Pointer to sdcc host structure
3403 * @ep - Pointer to sps endpoint data structure
3404 *
3405 * @return - 0 if successful else negative value.
3406 */
3407static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3408 struct msmsdcc_sps_ep_conn_data *ep)
3409{
3410 int rc = 0;
3411 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3412 struct sps_connect *sps_config = &ep->config;
3413 struct sps_register_event *sps_event = &ep->event;
3414
3415 /* Establish connection between peripheral and memory endpoint */
3416 rc = sps_connect(sps_pipe_handle, sps_config);
3417 if (rc) {
3418 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3419 " rc=%d", mmc_hostname(host->mmc), __func__,
3420 (u32)sps_pipe_handle, rc);
3421 goto out;
3422 }
3423
3424 /* Register callback event for EOT (End of transfer) event. */
3425 rc = sps_register_event(sps_pipe_handle, sps_event);
3426 if (rc) {
3427 pr_err("%s: %s: sps_register_event() failed!!!"
3428 " pipe_handle=0x%x, rc=%d",
3429 mmc_hostname(host->mmc), __func__,
3430 (u32)sps_pipe_handle, rc);
3431 goto reg_event_err;
3432 }
3433 goto out;
3434
3435reg_event_err:
3436 sps_disconnect(sps_pipe_handle);
3437out:
3438 return rc;
3439}
3440
3441/**
3442 * Initialize SPS HW connected with SDCC core
3443 *
3444 * This function register BAM HW resources with
3445 * SPS driver and then initialize 2 SPS endpoints
3446 *
3447 * This function should only be called once typically
3448 * during driver probe.
3449 *
3450 * @host - Pointer to sdcc host structure
3451 *
3452 * @return - 0 if successful else negative value.
3453 *
3454 */
3455static int msmsdcc_sps_init(struct msmsdcc_host *host)
3456{
3457 int rc = 0;
3458 struct sps_bam_props bam = {0};
3459
3460 host->bam_base = ioremap(host->bam_memres->start,
3461 resource_size(host->bam_memres));
3462 if (!host->bam_base) {
3463 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3464 " size=0x%x", mmc_hostname(host->mmc),
3465 host->bam_memres->start,
3466 (host->bam_memres->end -
3467 host->bam_memres->start));
3468 rc = -ENOMEM;
3469 goto out;
3470 }
3471
3472 bam.phys_addr = host->bam_memres->start;
3473 bam.virt_addr = host->bam_base;
3474 /*
3475 * This event thresold value is only significant for BAM-to-BAM
3476 * transfer. It's ignored for BAM-to-System mode transfer.
3477 */
3478 bam.event_threshold = 0x10; /* Pipe event threshold */
3479 /*
3480 * This threshold controls when the BAM publish
3481 * the descriptor size on the sideband interface.
3482 * SPS HW will only be used when
3483 * data transfer size > MCI_FIFOSIZE (64 bytes).
3484 * PIO mode will be used when
3485 * data transfer size < MCI_FIFOSIZE (64 bytes).
3486 * So set this thresold value to 64 bytes.
3487 */
3488 bam.summing_threshold = 64;
3489 /* SPS driver wll handle the SDCC BAM IRQ */
3490 bam.irq = (u32)host->bam_irqres->start;
3491 bam.manage = SPS_BAM_MGR_LOCAL;
3492
3493 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3494 (u32)bam.phys_addr);
3495 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3496 (u32)bam.virt_addr);
3497
3498 /* Register SDCC Peripheral BAM device to SPS driver */
3499 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3500 if (rc) {
3501 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3502 mmc_hostname(host->mmc), rc);
3503 goto reg_bam_err;
3504 }
3505 pr_info("%s: BAM device registered. bam_handle=0x%x",
3506 mmc_hostname(host->mmc), host->sps.bam_handle);
3507
3508 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3509 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3510
3511 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3512 SPS_PROD_PERIPHERAL);
3513 if (rc)
3514 goto sps_reset_err;
3515 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3516 SPS_CONS_PERIPHERAL);
3517 if (rc)
3518 goto cons_conn_err;
3519
3520 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3521 mmc_hostname(host->mmc),
3522 (unsigned long long)host->bam_memres->start,
3523 (unsigned int)host->bam_irqres->start);
3524 goto out;
3525
3526cons_conn_err:
3527 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3528sps_reset_err:
3529 sps_deregister_bam_device(host->sps.bam_handle);
3530reg_bam_err:
3531 iounmap(host->bam_base);
3532out:
3533 return rc;
3534}
3535
3536/**
3537 * De-initialize SPS HW connected with SDCC core
3538 *
3539 * This function deinitialize SPS endpoints and then
3540 * deregisters BAM resources from SPS driver.
3541 *
3542 * This function should only be called once typically
3543 * during driver remove.
3544 *
3545 * @host - Pointer to sdcc host structure
3546 *
3547 */
3548static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3549{
3550 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3551 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3552 sps_deregister_bam_device(host->sps.bam_handle);
3553 iounmap(host->bam_base);
3554}
3555#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3556
3557static ssize_t
3558show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3559{
3560 struct mmc_host *mmc = dev_get_drvdata(dev);
3561 struct msmsdcc_host *host = mmc_priv(mmc);
3562 int poll;
3563 unsigned long flags;
3564
3565 spin_lock_irqsave(&host->lock, flags);
3566 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3567 spin_unlock_irqrestore(&host->lock, flags);
3568
3569 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3570}
3571
3572static ssize_t
3573set_polling(struct device *dev, struct device_attribute *attr,
3574 const char *buf, size_t count)
3575{
3576 struct mmc_host *mmc = dev_get_drvdata(dev);
3577 struct msmsdcc_host *host = mmc_priv(mmc);
3578 int value;
3579 unsigned long flags;
3580
3581 sscanf(buf, "%d", &value);
3582
3583 spin_lock_irqsave(&host->lock, flags);
3584 if (value) {
3585 mmc->caps |= MMC_CAP_NEEDS_POLL;
3586 mmc_detect_change(host->mmc, 0);
3587 } else {
3588 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3589 }
3590#ifdef CONFIG_HAS_EARLYSUSPEND
3591 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3592#endif
3593 spin_unlock_irqrestore(&host->lock, flags);
3594 return count;
3595}
3596
3597static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3598 show_polling, set_polling);
3599static struct attribute *dev_attrs[] = {
3600 &dev_attr_polling.attr,
3601 NULL,
3602};
3603static struct attribute_group dev_attr_grp = {
3604 .attrs = dev_attrs,
3605};
3606
3607#ifdef CONFIG_HAS_EARLYSUSPEND
3608static void msmsdcc_early_suspend(struct early_suspend *h)
3609{
3610 struct msmsdcc_host *host =
3611 container_of(h, struct msmsdcc_host, early_suspend);
3612 unsigned long flags;
3613
3614 spin_lock_irqsave(&host->lock, flags);
3615 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3616 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3617 spin_unlock_irqrestore(&host->lock, flags);
3618};
3619static void msmsdcc_late_resume(struct early_suspend *h)
3620{
3621 struct msmsdcc_host *host =
3622 container_of(h, struct msmsdcc_host, early_suspend);
3623 unsigned long flags;
3624
3625 if (host->polling_enabled) {
3626 spin_lock_irqsave(&host->lock, flags);
3627 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3628 mmc_detect_change(host->mmc, 0);
3629 spin_unlock_irqrestore(&host->lock, flags);
3630 }
3631};
3632#endif
3633
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303634void msmsdcc_print_regs(const char *name, void __iomem *base,
3635 unsigned int no_of_regs)
3636{
3637 unsigned int i;
3638
3639 if (!base)
3640 return;
3641 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3642 name, (u32)base);
3643 for (i = 0; i < no_of_regs; i = i + 4) {
3644 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3645 (u32)readl_relaxed(base + i*4),
3646 (u32)readl_relaxed(base + ((i+1)*4)),
3647 (u32)readl_relaxed(base + ((i+2)*4)),
3648 (u32)readl_relaxed(base + ((i+3)*4)));
3649 }
3650}
3651
3652static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3653{
3654 /* Dump current state of SDCC clocks, power and irq */
3655 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3656 (host->pwr ? "ON" : "OFF"));
3657 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3658 mmc_hostname(host->mmc),
3659 (host->clks_on ? "ON" : "OFF"),
3660 (u32)clk_get_rate(host->clk));
3661 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3662 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3663
3664 /* Now dump SDCC registers. Don't print FIFO registers */
3665 if (host->clks_on)
3666 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3667
3668 if (host->curr.data) {
3669 if (msmsdcc_check_dma_op_req(host->curr.data))
3670 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3671 else if (host->is_dma_mode)
3672 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3673 mmc_hostname(host->mmc), host->dma.busy,
3674 host->dma.channel, host->dma.crci);
3675 else if (host->is_sps_mode)
3676 pr_info("%s: SPS mode: busy=%d\n",
3677 mmc_hostname(host->mmc), host->sps.busy);
3678
3679 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3680 mmc_hostname(host->mmc), host->curr.xfer_size,
3681 host->curr.data_xfered, host->curr.xfer_remain);
3682 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3683 " wait_for_auto_prog_done=%d,"
3684 " got_auto_prog_done=%d\n",
3685 mmc_hostname(host->mmc), host->curr.got_dataend,
3686 host->prog_enable, host->curr.wait_for_auto_prog_done,
3687 host->curr.got_auto_prog_done);
3688 }
3689
3690}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3692{
3693 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3694 struct mmc_request *mrq;
3695 unsigned long flags;
3696
3697 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003698 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699 pr_info("%s: %s: dummy CMD52 timeout\n",
3700 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003701 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003702 }
3703
3704 mrq = host->curr.mrq;
3705
3706 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303707 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3708 mrq->cmd->opcode);
3709 msmsdcc_dump_sdcc_state(host);
3710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711 if (!mrq->cmd->error)
3712 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303713 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003714 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 if (mrq->data && !mrq->data->error)
3716 mrq->data->error = -ETIMEDOUT;
3717 host->curr.data_xfered = 0;
3718 if (host->dma.sg && host->is_dma_mode) {
3719 msm_dmov_stop_cmd(host->dma.channel,
3720 &host->dma.hdr, 0);
3721 } else if (host->sps.sg && host->is_sps_mode) {
3722 /* Stop current SPS transfer */
3723 msmsdcc_sps_exit_curr_xfer(host);
3724 } else {
3725 msmsdcc_reset_and_restore(host);
3726 msmsdcc_stop_data(host);
3727 if (mrq->data && mrq->data->stop)
3728 msmsdcc_start_command(host,
3729 mrq->data->stop, 0);
3730 else
3731 msmsdcc_request_end(host, mrq);
3732 }
3733 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303734 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003735 msmsdcc_reset_and_restore(host);
3736 msmsdcc_request_end(host, mrq);
3737 }
3738 }
3739 spin_unlock_irqrestore(&host->lock, flags);
3740}
3741
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303742static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3743{
3744 int i, ret;
3745 struct mmc_platform_data *pdata;
3746 struct device_node *np = dev->of_node;
3747 u32 bus_width = 0;
3748 u32 *clk_table;
3749 int clk_table_len;
3750 u32 *sup_voltages;
3751 int sup_volt_len;
3752
3753 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3754 if (!pdata) {
3755 dev_err(dev, "could not allocate memory for platform data\n");
3756 goto err;
3757 }
3758
3759 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3760 if (bus_width == 8) {
3761 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3762 } else if (bus_width == 4) {
3763 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3764 } else {
3765 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3766 pdata->mmc_bus_width = 0;
3767 }
3768
3769 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3770 size_t sz;
3771 sz = sup_volt_len / sizeof(*sup_voltages);
3772 if (sz > 0) {
3773 sup_voltages = devm_kzalloc(dev,
3774 sz * sizeof(*sup_voltages), GFP_KERNEL);
3775 if (!sup_voltages) {
3776 dev_err(dev, "No memory for supported voltage\n");
3777 goto err;
3778 }
3779
3780 ret = of_property_read_u32_array(np,
3781 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3782 if (ret < 0) {
3783 dev_err(dev, "error while reading voltage"
3784 "ranges %d\n", ret);
3785 goto err;
3786 }
3787 } else {
3788 dev_err(dev, "No supported voltages\n");
3789 goto err;
3790 }
3791 for (i = 0; i < sz; i += 2) {
3792 u32 mask;
3793
3794 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3795 sup_voltages[i + 1]);
3796 if (!mask)
3797 dev_err(dev, "Invalide voltage range %d\n", i);
3798 pdata->ocr_mask |= mask;
3799 }
3800 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3801 } else {
3802 dev_err(dev, "Supported voltage range not specified\n");
3803 }
3804
3805 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3806 size_t sz;
3807 sz = clk_table_len / sizeof(*clk_table);
3808
3809 if (sz > 0) {
3810 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3811 GFP_KERNEL);
3812 if (!clk_table) {
3813 dev_err(dev, "No memory for clock table\n");
3814 goto err;
3815 }
3816
3817 ret = of_property_read_u32_array(np,
3818 "qcom,sdcc-clk-rates", clk_table, sz);
3819 if (ret < 0) {
3820 dev_err(dev, "error while reading clk"
3821 "table %d\n", ret);
3822 goto err;
3823 }
3824 } else {
3825 dev_err(dev, "clk_table not specified\n");
3826 goto err;
3827 }
3828 pdata->sup_clk_table = clk_table;
3829 pdata->sup_clk_cnt = sz;
3830 } else {
3831 dev_err(dev, "Supported clock rates not specified\n");
3832 }
3833
3834 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3835 pdata->nonremovable = true;
3836 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3837 pdata->disable_cmd23 = true;
3838
3839 return pdata;
3840err:
3841 return NULL;
3842}
3843
San Mehat9d2bd732009-09-22 16:44:22 -07003844static int
3845msmsdcc_probe(struct platform_device *pdev)
3846{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303847 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003848 struct msmsdcc_host *host;
3849 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003850 unsigned long flags;
3851 struct resource *core_irqres = NULL;
3852 struct resource *bam_irqres = NULL;
3853 struct resource *core_memres = NULL;
3854 struct resource *dml_memres = NULL;
3855 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003856 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003857 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303858 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003860
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303861 if (pdev->dev.of_node) {
3862 plat = msmsdcc_populate_pdata(&pdev->dev);
3863 of_property_read_u32((&pdev->dev)->of_node,
3864 "cell-index", &pdev->id);
3865 } else {
3866 plat = pdev->dev.platform_data;
3867 }
3868
San Mehat9d2bd732009-09-22 16:44:22 -07003869 /* must have platform data */
3870 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003871 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003872 ret = -EINVAL;
3873 goto out;
3874 }
3875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003876 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003877 return -EINVAL;
3878
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303879 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3880 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3881 return -EINVAL;
3882 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883
San Mehat9d2bd732009-09-22 16:44:22 -07003884 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003885 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003886 return -ENXIO;
3887 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303888 if (pdev->dev.of_node) {
3889 /*
3890 * Device tree iomem resources are only accessible by index.
3891 * index = 0 -> SDCC register interface
3892 * index = 1 -> DML register interface
3893 * index = 2 -> BAM register interface
3894 * IRQ resources:
3895 * index = 0 -> SDCC IRQ
3896 * index = 1 -> BAM IRQ
3897 */
3898 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3899 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3900 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3901 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3902 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3903 } else {
3904 for (i = 0; i < pdev->num_resources; i++) {
3905 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3906 if (!strncmp(pdev->resource[i].name,
3907 "sdcc_dml_addr",
3908 sizeof("sdcc_dml_addr")))
3909 dml_memres = &pdev->resource[i];
3910 else if (!strncmp(pdev->resource[i].name,
3911 "sdcc_bam_addr",
3912 sizeof("sdcc_bam_addr")))
3913 bam_memres = &pdev->resource[i];
3914 else
3915 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003916
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303917 }
3918 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3919 if (!strncmp(pdev->resource[i].name,
3920 "sdcc_bam_irq",
3921 sizeof("sdcc_bam_irq")))
3922 bam_irqres = &pdev->resource[i];
3923 else
3924 core_irqres = &pdev->resource[i];
3925 }
3926 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3927 if (!strncmp(pdev->resource[i].name,
3928 "sdcc_dma_chnl",
3929 sizeof("sdcc_dma_chnl")))
3930 dmares = &pdev->resource[i];
3931 else if (!strncmp(pdev->resource[i].name,
3932 "sdcc_dma_crci",
3933 sizeof("sdcc_dma_crci")))
3934 dma_crci_res = &pdev->resource[i];
3935 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003936 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937 }
3938
3939 if (!core_irqres || !core_memres) {
3940 pr_err("%s: Invalid sdcc core resource\n", __func__);
3941 return -ENXIO;
3942 }
3943
3944 /*
3945 * Both BAM and DML memory resource should be preset.
3946 * BAM IRQ resource should also be present.
3947 */
3948 if ((bam_memres && !dml_memres) ||
3949 (!bam_memres && dml_memres) ||
3950 ((bam_memres && dml_memres) && !bam_irqres)) {
3951 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003952 return -ENXIO;
3953 }
3954
3955 /*
3956 * Setup our host structure
3957 */
San Mehat9d2bd732009-09-22 16:44:22 -07003958 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3959 if (!mmc) {
3960 ret = -ENOMEM;
3961 goto out;
3962 }
3963
3964 host = mmc_priv(mmc);
3965 host->pdev_id = pdev->id;
3966 host->plat = plat;
3967 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003968 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303969
3970 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003971 host->is_sps_mode = 1;
3972 else if (dmares)
3973 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003974
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003975 host->base = ioremap(core_memres->start,
3976 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003977 if (!host->base) {
3978 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003980 }
3981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 host->core_irqres = core_irqres;
3983 host->bam_irqres = bam_irqres;
3984 host->core_memres = core_memres;
3985 host->dml_memres = dml_memres;
3986 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003987 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003988 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003989 spin_lock_init(&host->lock);
3990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003991#ifdef CONFIG_MMC_EMBEDDED_SDIO
3992 if (plat->embedded_sdio)
3993 mmc_set_embedded_sdio_data(mmc,
3994 &plat->embedded_sdio->cis,
3995 &plat->embedded_sdio->cccr,
3996 plat->embedded_sdio->funcs,
3997 plat->embedded_sdio->num_funcs);
3998#endif
3999
Sahitya Tummala62612cf2010-12-08 15:03:03 +05304000 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
4001 (unsigned long)host);
4002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004003 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
4004 (unsigned long)host);
4005 if (host->is_dma_mode) {
4006 /* Setup DMA */
4007 ret = msmsdcc_init_dma(host);
4008 if (ret)
4009 goto ioremap_free;
4010 } else {
4011 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07004012 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07004013 }
4014
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004015 /*
4016 * Setup SDCC clock if derived from Dayatona
4017 * fabric core clock.
4018 */
4019 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07004020 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 if (!IS_ERR(host->dfab_pclk)) {
4022 /* Set the clock rate to 64MHz for max. performance */
4023 ret = clk_set_rate(host->dfab_pclk, 64000000);
4024 if (ret)
4025 goto dfab_pclk_put;
4026 ret = clk_enable(host->dfab_pclk);
4027 if (ret)
4028 goto dfab_pclk_put;
4029 } else
4030 goto dma_free;
4031 }
4032
4033 /*
4034 * Setup main peripheral bus clock
4035 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004036 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004037 if (!IS_ERR(host->pclk)) {
4038 ret = clk_enable(host->pclk);
4039 if (ret)
4040 goto pclk_put;
4041
4042 host->pclk_rate = clk_get_rate(host->pclk);
4043 }
4044
4045 /*
4046 * Setup SDC MMC clock
4047 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07004048 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07004049 if (IS_ERR(host->clk)) {
4050 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07004052 }
4053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
4055 if (ret) {
4056 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
4057 goto clk_put;
4058 }
4059
4060 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004061 if (ret)
4062 goto clk_put;
4063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304065 if (!host->clk_rate)
4066 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304067
4068 /*
4069 * Lookup the Controller Version, to identify the supported features
4070 * Version number read as 0 would indicate SDCC3 or earlier versions
4071 */
4072 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
4073 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
4074 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05304075 /*
4076 * Set the register write delay according to min. clock frequency
4077 * supported and update later when the host->clk_rate changes.
4078 */
4079 host->reg_write_delay =
4080 (1 + ((3 * USEC_PER_SEC) /
4081 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082
4083 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05304084 /* Apply Hard reset to SDCC to put it in power on default state */
4085 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304087 /* pm qos request to prevent apps idle power collapse */
4088 if (host->plat->swfi_latency)
4089 pm_qos_add_request(&host->pm_qos_req_dma,
4090 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
4091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004092 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07004093 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07004095 goto clk_disable;
4096 }
4097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004098
4099 /* Clocks has to be running before accessing SPS/DML HW blocks */
4100 if (host->is_sps_mode) {
4101 /* Initialize SPS */
4102 ret = msmsdcc_sps_init(host);
4103 if (ret)
4104 goto vreg_deinit;
4105 /* Initialize DML */
4106 ret = msmsdcc_dml_init(host);
4107 if (ret)
4108 goto sps_exit;
4109 }
Subhash Jadavani8766e352011-11-30 11:30:32 +05304110 mmc_dev(mmc)->dma_mask = &dma_mask;
San Mehat9d2bd732009-09-22 16:44:22 -07004111
San Mehat9d2bd732009-09-22 16:44:22 -07004112 /*
4113 * Setup MMC host structure
4114 */
4115 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
4117 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07004118 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004119 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
4120 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07004121
San Mehat9d2bd732009-09-22 16:44:22 -07004122 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05304123 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304124
4125 /*
4126 * If we send the CMD23 before multi block write/read command
4127 * then we need not to send CMD12 at the end of the transfer.
4128 * If we don't send the CMD12 then only way to detect the PROG_DONE
4129 * status is to use the AUTO_PROG_DONE status provided by SDCC4
4130 * controller. So let's enable the CMD23 for SDCC4 only.
4131 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05304132 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05304133 mmc->caps |= MMC_CAP_CMD23;
4134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004135 mmc->caps |= plat->uhs_caps;
4136 /*
4137 * XPC controls the maximum current in the default speed mode of SDXC
4138 * card. XPC=0 means 100mA (max.) but speed class is not supported.
4139 * XPC=1 means 150mA (max.) and speed class is supported.
4140 */
4141 if (plat->xpc_cap)
4142 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
4143 MMC_CAP_SET_XPC_180);
4144
4145 if (plat->nonremovable)
4146 mmc->caps |= MMC_CAP_NONREMOVABLE;
4147#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
4148 mmc->caps |= MMC_CAP_SDIO_IRQ;
4149#endif
4150
4151 if (plat->is_sdio_al_client)
4152 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07004153
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304154 mmc->max_segs = msmsdcc_get_nr_sg(host);
4155 mmc->max_blk_size = MMC_MAX_BLK_SIZE;
4156 mmc->max_blk_count = MMC_MAX_BLK_CNT;
San Mehat9d2bd732009-09-22 16:44:22 -07004157
Sujit Reddy Thummacf6c4ed2011-11-14 17:20:36 +05304158 mmc->max_req_size = MMC_MAX_REQ_SIZE;
Subhash Jadavanid4aff7f2011-12-08 18:08:19 +05304159 mmc->max_seg_size = mmc->max_req_size;
San Mehat9d2bd732009-09-22 16:44:22 -07004160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004161 writel_relaxed(0, host->base + MMCIMASK0);
4162 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07004163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
4165 mb();
4166 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07004167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
4169 DRIVER_NAME " (cmd)", host);
4170 if (ret)
4171 goto dml_exit;
4172
4173 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
4174 DRIVER_NAME " (pio)", host);
4175 if (ret)
4176 goto irq_free;
4177
4178 /*
4179 * Enable SDCC IRQ only when host is powered on. Otherwise, this
4180 * IRQ is un-necessarily being monitored by MPM (Modem power
4181 * management block) during idle-power collapse. The MPM will be
4182 * configured to monitor the DATA1 GPIO line with level-low trigger
4183 * and thus depending on the GPIO status, it prevents TCXO shutdown
4184 * during idle-power collapse.
4185 */
4186 disable_irq(core_irqres->start);
4187 host->sdcc_irq_disabled = 1;
4188
4189 if (plat->sdiowakeup_irq) {
4190 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4191 mmc_hostname(mmc));
4192 ret = request_irq(plat->sdiowakeup_irq,
4193 msmsdcc_platform_sdiowakeup_irq,
4194 IRQF_SHARED | IRQF_TRIGGER_LOW,
4195 DRIVER_NAME "sdiowakeup", host);
4196 if (ret) {
4197 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
4198 plat->sdiowakeup_irq, ret);
4199 goto pio_irq_free;
4200 } else {
4201 spin_lock_irqsave(&host->lock, flags);
4202 if (!host->sdio_irq_disabled) {
4203 disable_irq_nosync(plat->sdiowakeup_irq);
4204 host->sdio_irq_disabled = 1;
4205 }
4206 spin_unlock_irqrestore(&host->lock, flags);
4207 }
4208 }
4209
4210 if (plat->cfg_mpm_sdiowakeup) {
4211 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
4212 mmc_hostname(mmc));
4213 }
4214
4215 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
4216 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004217 /*
4218 * Setup card detect change
4219 */
4220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004221 if (plat->status || plat->status_gpio) {
Krishna Konda941604a2012-01-10 17:46:34 -08004222 if (plat->status)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 host->oldstat = plat->status(mmc_dev(host->mmc));
Krishna Konda941604a2012-01-10 17:46:34 -08004224 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004225 host->oldstat = msmsdcc_slot_status(host);
Krishna Konda360aa422011-12-06 18:27:41 -08004226
Krishna Konda941604a2012-01-10 17:46:34 -08004227 host->eject = !host->oldstat;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004228 }
San Mehat9d2bd732009-09-22 16:44:22 -07004229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004230 if (plat->status_irq) {
4231 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07004232 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004233 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004234 DRIVER_NAME " (slot)",
4235 host);
4236 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004237 pr_err("Unable to get slot IRQ %d (%d)\n",
4238 plat->status_irq, ret);
4239 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004240 }
4241 } else if (plat->register_status_notify) {
4242 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4243 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004244 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004245 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004246
4247 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004248
4249 ret = pm_runtime_set_active(&(pdev)->dev);
4250 if (ret < 0)
4251 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4252 __func__, ret);
4253 /*
4254 * There is no notion of suspend/resume for SD/MMC/SDIO
4255 * cards. So host can be suspended/resumed with out
4256 * worrying about its children.
4257 */
4258 pm_suspend_ignore_children(&(pdev)->dev, true);
4259
4260 /*
4261 * MMC/SD/SDIO bus suspend/resume operations are defined
4262 * only for the slots that will be used for non-removable
4263 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4264 * defined. Otherwise, they simply become card removal and
4265 * insertion events during suspend and resume respectively.
4266 * Hence, enable run-time PM only for slots for which bus
4267 * suspend/resume operations are defined.
4268 */
4269#ifdef CONFIG_MMC_UNSAFE_RESUME
4270 /*
4271 * If this capability is set, MMC core will enable/disable host
4272 * for every claim/release operation on a host. We use this
4273 * notification to increment/decrement runtime pm usage count.
4274 */
4275 mmc->caps |= MMC_CAP_DISABLE;
4276 pm_runtime_enable(&(pdev)->dev);
4277#else
4278 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4279 mmc->caps |= MMC_CAP_DISABLE;
4280 pm_runtime_enable(&(pdev)->dev);
4281 }
4282#endif
Sujit Reddy Thumma5000d2a2011-11-17 12:09:04 +05304283#ifndef CONFIG_PM_RUNTIME
4284 mmc_set_disable_delay(mmc, MSM_MMC_DISABLE_TIMEOUT);
4285#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004286 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4287 (unsigned long)host);
4288
San Mehat9d2bd732009-09-22 16:44:22 -07004289 mmc_add_host(mmc);
4290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004291#ifdef CONFIG_HAS_EARLYSUSPEND
4292 host->early_suspend.suspend = msmsdcc_early_suspend;
4293 host->early_suspend.resume = msmsdcc_late_resume;
4294 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4295 register_early_suspend(&host->early_suspend);
4296#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004297
Krishna Konda25786ec2011-07-25 16:21:36 -07004298 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4299 " dmacrcri %d\n", mmc_hostname(mmc),
4300 (unsigned long long)core_memres->start,
4301 (unsigned int) core_irqres->start,
4302 (unsigned int) plat->status_irq, host->dma.channel,
4303 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304
4305 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4306 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4307 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4308 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4309 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4310 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4311 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4312 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4313 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4314 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4315 host->eject);
4316 pr_info("%s: Power save feature enable = %d\n",
4317 mmc_hostname(mmc), msmsdcc_pwrsave);
4318
Krishna Konda25786ec2011-07-25 16:21:36 -07004319 if (host->is_dma_mode && host->dma.channel != -1
4320 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004321 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004322 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004323 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004324 mmc_hostname(mmc), host->dma.cmd_busaddr,
4325 host->dma.cmdptr_busaddr);
4326 } else if (host->is_sps_mode) {
4327 pr_info("%s: SPS-BAM data transfer mode available\n",
4328 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004329 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004330 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004332#if defined(CONFIG_DEBUG_FS)
4333 msmsdcc_dbg_createhost(host);
4334#endif
4335 if (!plat->status_irq) {
4336 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4337 if (ret)
4338 goto platform_irq_free;
4339 }
San Mehat9d2bd732009-09-22 16:44:22 -07004340 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004341
4342 platform_irq_free:
4343 del_timer_sync(&host->req_tout_timer);
4344 pm_runtime_disable(&(pdev)->dev);
4345 pm_runtime_set_suspended(&(pdev)->dev);
4346
4347 if (plat->status_irq)
4348 free_irq(plat->status_irq, host);
4349 sdiowakeup_irq_free:
4350 wake_lock_destroy(&host->sdio_suspend_wlock);
4351 if (plat->sdiowakeup_irq)
4352 free_irq(plat->sdiowakeup_irq, host);
4353 pio_irq_free:
4354 if (plat->sdiowakeup_irq)
4355 wake_lock_destroy(&host->sdio_wlock);
4356 free_irq(core_irqres->start, host);
4357 irq_free:
4358 free_irq(core_irqres->start, host);
4359 dml_exit:
4360 if (host->is_sps_mode)
4361 msmsdcc_dml_exit(host);
4362 sps_exit:
4363 if (host->is_sps_mode)
4364 msmsdcc_sps_exit(host);
4365 vreg_deinit:
4366 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004367 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368 clk_disable(host->clk);
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304369 if (host->plat->swfi_latency)
4370 pm_qos_remove_request(&host->pm_qos_req_dma);
San Mehat9d2bd732009-09-22 16:44:22 -07004371 clk_put:
4372 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004373 pclk_disable:
4374 if (!IS_ERR(host->pclk))
4375 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004376 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004377 if (!IS_ERR(host->pclk))
4378 clk_put(host->pclk);
4379 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4380 clk_disable(host->dfab_pclk);
4381 dfab_pclk_put:
4382 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4383 clk_put(host->dfab_pclk);
4384 dma_free:
4385 if (host->is_dma_mode) {
4386 if (host->dmares)
4387 dma_free_coherent(NULL,
4388 sizeof(struct msmsdcc_nc_dmadata),
4389 host->dma.nc, host->dma.nc_busaddr);
4390 }
4391 ioremap_free:
4392 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004393 host_free:
4394 mmc_free_host(mmc);
4395 out:
4396 return ret;
4397}
4398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004399static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004400{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004401 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4402 struct mmc_platform_data *plat;
4403 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004405 if (!mmc)
4406 return -ENXIO;
4407
4408 if (pm_runtime_suspended(&(pdev)->dev))
4409 pm_runtime_resume(&(pdev)->dev);
4410
4411 host = mmc_priv(mmc);
4412
4413 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4414 plat = host->plat;
4415
4416 if (!plat->status_irq)
4417 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4418
4419 del_timer_sync(&host->req_tout_timer);
4420 tasklet_kill(&host->dma_tlet);
4421 tasklet_kill(&host->sps.tlet);
4422 mmc_remove_host(mmc);
4423
4424 if (plat->status_irq)
4425 free_irq(plat->status_irq, host);
4426
4427 wake_lock_destroy(&host->sdio_suspend_wlock);
4428 if (plat->sdiowakeup_irq) {
4429 wake_lock_destroy(&host->sdio_wlock);
4430 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4431 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004432 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004433
4434 free_irq(host->core_irqres->start, host);
4435 free_irq(host->core_irqres->start, host);
4436
4437 clk_put(host->clk);
4438 if (!IS_ERR(host->pclk))
4439 clk_put(host->pclk);
4440 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4441 clk_put(host->dfab_pclk);
4442
Subhash Jadavani933e6a62011-12-26 18:05:04 +05304443 if (host->plat->swfi_latency)
4444 pm_qos_remove_request(&host->pm_qos_req_dma);
4445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004446 msmsdcc_vreg_init(host, false);
4447
4448 if (host->is_dma_mode) {
4449 if (host->dmares)
4450 dma_free_coherent(NULL,
4451 sizeof(struct msmsdcc_nc_dmadata),
4452 host->dma.nc, host->dma.nc_busaddr);
4453 }
4454
4455 if (host->is_sps_mode) {
4456 msmsdcc_dml_exit(host);
4457 msmsdcc_sps_exit(host);
4458 }
4459
4460 iounmap(host->base);
4461 mmc_free_host(mmc);
4462
4463#ifdef CONFIG_HAS_EARLYSUSPEND
4464 unregister_early_suspend(&host->early_suspend);
4465#endif
4466 pm_runtime_disable(&(pdev)->dev);
4467 pm_runtime_set_suspended(&(pdev)->dev);
4468
4469 return 0;
4470}
4471
4472#ifdef CONFIG_MSM_SDIO_AL
4473int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4474{
4475 struct msmsdcc_host *host = mmc_priv(mmc);
4476 unsigned long flags;
4477
4478 spin_lock_irqsave(&host->lock, flags);
4479 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4480 enable ? "En" : "Dis");
4481
4482 if (enable) {
4483 if (!host->sdcc_irq_disabled) {
4484 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304485 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004486 host->sdcc_irq_disabled = 1;
4487 }
4488
4489 if (host->clks_on) {
4490 msmsdcc_setup_clocks(host, false);
4491 host->clks_on = 0;
4492 }
4493
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304494 if (host->plat->sdio_lpm_gpio_setup &&
4495 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004496 spin_unlock_irqrestore(&host->lock, flags);
4497 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4498 spin_lock_irqsave(&host->lock, flags);
4499 host->sdio_gpio_lpm = 1;
4500 }
4501
4502 if (host->sdio_irq_disabled) {
4503 msmsdcc_enable_irq_wake(host);
4504 enable_irq(host->plat->sdiowakeup_irq);
4505 host->sdio_irq_disabled = 0;
4506 }
4507 } else {
4508 if (!host->sdio_irq_disabled) {
4509 disable_irq_nosync(host->plat->sdiowakeup_irq);
4510 host->sdio_irq_disabled = 1;
4511 msmsdcc_disable_irq_wake(host);
4512 }
4513
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304514 if (host->plat->sdio_lpm_gpio_setup &&
4515 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004516 spin_unlock_irqrestore(&host->lock, flags);
4517 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4518 spin_lock_irqsave(&host->lock, flags);
4519 host->sdio_gpio_lpm = 0;
4520 }
4521
4522 if (!host->clks_on) {
4523 msmsdcc_setup_clocks(host, true);
4524 host->clks_on = 1;
4525 }
4526
4527 if (host->sdcc_irq_disabled) {
4528 writel_relaxed(host->mci_irqenable,
4529 host->base + MMCIMASK0);
4530 mb();
4531 enable_irq(host->core_irqres->start);
4532 host->sdcc_irq_disabled = 0;
4533 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004534 }
4535 spin_unlock_irqrestore(&host->lock, flags);
4536 return 0;
4537}
4538#else
4539int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4540{
4541 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004542}
4543#endif
4544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004546static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004547msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004548{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004549 struct mmc_host *mmc = dev_get_drvdata(dev);
4550 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004551 int rc = 0;
4552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 if (host->plat->is_sdio_al_client)
4554 return 0;
Sahitya Tummala7661a452011-07-18 13:28:35 +05304555 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004556 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557 host->sdcc_suspending = 1;
4558 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004560 /*
4561 * If the clocks are already turned off by SDIO clients (as
4562 * part of LPM), then clocks should be turned on before
4563 * calling mmc_suspend_host() because mmc_suspend_host might
4564 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304565 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566 * cards, clocks will be turned on before mmc_suspend_host
4567 * and turned off after mmc_suspend_host.
4568 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304569 if (mmc->card && mmc_card_sdio(mmc->card)) {
4570 mmc->ios.clock = host->clk_rate;
4571 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4572 }
San Mehat9d2bd732009-09-22 16:44:22 -07004573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004574 /*
4575 * MMC core thinks that host is disabled by now since
4576 * runtime suspend is scheduled after msmsdcc_disable()
4577 * is called. Thus, MMC core will try to enable the host
4578 * while suspending it. This results in a synchronous
4579 * runtime resume request while in runtime suspending
4580 * context and hence inorder to complete this resume
4581 * requet, it will wait for suspend to be complete,
4582 * but runtime suspend also can not proceed further
4583 * until the host is resumed. Thus, it leads to a hang.
4584 * Hence, increase the pm usage count before suspending
4585 * the host so that any resume requests after this will
4586 * simple become pm usage counter increment operations.
4587 */
4588 pm_runtime_get_noresume(dev);
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304589 /* If there is pending detect work abort runtime suspend */
4590 if (unlikely(work_busy(&mmc->detect.work)))
4591 rc = -EAGAIN;
4592 else
4593 rc = mmc_suspend_host(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004594 pm_runtime_put_noidle(dev);
4595
4596 if (!rc) {
4597 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4598 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4599 disable_irq(host->core_irqres->start);
4600 host->sdcc_irq_disabled = 1;
4601
4602 /*
4603 * If MMC core level suspend is not supported,
4604 * turn off clocks to allow deep sleep (TCXO
4605 * shutdown).
4606 */
4607 mmc->ios.clock = 0;
4608 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4609 enable_irq(host->core_irqres->start);
4610 host->sdcc_irq_disabled = 0;
4611
4612 if (host->plat->sdiowakeup_irq) {
4613 host->sdio_irq_disabled = 0;
4614 msmsdcc_enable_irq_wake(host);
4615 enable_irq(host->plat->sdiowakeup_irq);
4616 }
4617 }
4618 }
4619 host->sdcc_suspending = 0;
4620 mmc->suspend_task = NULL;
4621 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4622 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004623 }
Sujit Reddy Thumma19859ef2011-12-14 21:17:08 +05304624 pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
San Mehat9d2bd732009-09-22 16:44:22 -07004625 return rc;
4626}
4627
4628static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004629msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004630{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004631 struct mmc_host *mmc = dev_get_drvdata(dev);
4632 struct msmsdcc_host *host = mmc_priv(mmc);
4633 unsigned long flags;
4634
4635 if (host->plat->is_sdio_al_client)
4636 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004637
Sahitya Tummala7661a452011-07-18 13:28:35 +05304638 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004639 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4641 if (host->sdcc_irq_disabled) {
4642 enable_irq(host->core_irqres->start);
4643 host->sdcc_irq_disabled = 0;
4644 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304645 mmc->ios.clock = host->clk_rate;
4646 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004647
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304648 spin_lock_irqsave(&host->lock, flags);
4649 writel_relaxed(host->mci_irqenable,
4650 host->base + MMCIMASK0);
4651 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004652
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304653 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4654 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004655 if (host->plat->sdiowakeup_irq) {
4656 disable_irq_nosync(
4657 host->plat->sdiowakeup_irq);
4658 msmsdcc_disable_irq_wake(host);
4659 host->sdio_irq_disabled = 1;
4660 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304661 }
San Mehat9d2bd732009-09-22 16:44:22 -07004662
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304663 spin_unlock_irqrestore(&host->lock, flags);
4664 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665
4666 mmc_resume_host(mmc);
4667
4668 /*
4669 * FIXME: Clearing of flags must be handled in clients
4670 * resume handler.
4671 */
4672 spin_lock_irqsave(&host->lock, flags);
4673 mmc->pm_flags = 0;
4674 spin_unlock_irqrestore(&host->lock, flags);
4675
4676 /*
4677 * After resuming the host wait for sometime so that
4678 * the SDIO work will be processed.
4679 */
4680 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4681 if ((host->plat->cfg_mpm_sdiowakeup ||
4682 host->plat->sdiowakeup_irq) &&
4683 wake_lock_active(&host->sdio_wlock))
4684 wake_lock_timeout(&host->sdio_wlock, 1);
4685 }
4686
4687 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004688 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304689 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004690 return 0;
4691}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004692
4693static int msmsdcc_runtime_idle(struct device *dev)
4694{
4695 struct mmc_host *mmc = dev_get_drvdata(dev);
4696 struct msmsdcc_host *host = mmc_priv(mmc);
4697
4698 if (host->plat->is_sdio_al_client)
4699 return 0;
4700
4701 /* Idle timeout is not configurable for now */
4702 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4703
4704 return -EAGAIN;
4705}
4706
4707static int msmsdcc_pm_suspend(struct device *dev)
4708{
4709 struct mmc_host *mmc = dev_get_drvdata(dev);
4710 struct msmsdcc_host *host = mmc_priv(mmc);
4711 int rc = 0;
4712
4713 if (host->plat->is_sdio_al_client)
4714 return 0;
4715
4716
4717 if (host->plat->status_irq)
4718 disable_irq(host->plat->status_irq);
4719
4720 if (!pm_runtime_suspended(dev))
4721 rc = msmsdcc_runtime_suspend(dev);
4722
4723 return rc;
4724}
4725
4726static int msmsdcc_pm_resume(struct device *dev)
4727{
4728 struct mmc_host *mmc = dev_get_drvdata(dev);
4729 struct msmsdcc_host *host = mmc_priv(mmc);
4730 int rc = 0;
4731
4732 if (host->plat->is_sdio_al_client)
4733 return 0;
4734
Sahitya Tummalafb486372011-09-02 19:01:49 +05304735 if (!pm_runtime_suspended(dev))
4736 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737 if (host->plat->status_irq) {
4738 msmsdcc_check_status((unsigned long)host);
4739 enable_irq(host->plat->status_irq);
4740 }
4741
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 return rc;
4743}
4744
Daniel Walker08ecfde2010-06-23 12:32:20 -07004745#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004746#define msmsdcc_runtime_suspend NULL
4747#define msmsdcc_runtime_resume NULL
4748#define msmsdcc_runtime_idle NULL
4749#define msmsdcc_pm_suspend NULL
4750#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004751#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004753static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4754 .runtime_suspend = msmsdcc_runtime_suspend,
4755 .runtime_resume = msmsdcc_runtime_resume,
4756 .runtime_idle = msmsdcc_runtime_idle,
4757 .suspend = msmsdcc_pm_suspend,
4758 .resume = msmsdcc_pm_resume,
4759};
4760
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304761static const struct of_device_id msmsdcc_dt_match[] = {
4762 {.compatible = "qcom,msm-sdcc"},
4763
4764};
4765MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4766
San Mehat9d2bd732009-09-22 16:44:22 -07004767static struct platform_driver msmsdcc_driver = {
4768 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004769 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004770 .driver = {
4771 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004772 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304773 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004774 },
4775};
4776
4777static int __init msmsdcc_init(void)
4778{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004779#if defined(CONFIG_DEBUG_FS)
4780 int ret = 0;
4781 ret = msmsdcc_dbg_init();
4782 if (ret) {
4783 pr_err("Failed to create debug fs dir \n");
4784 return ret;
4785 }
4786#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004787 return platform_driver_register(&msmsdcc_driver);
4788}
4789
4790static void __exit msmsdcc_exit(void)
4791{
4792 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004793
4794#if defined(CONFIG_DEBUG_FS)
4795 debugfs_remove(debugfs_file);
4796 debugfs_remove(debugfs_dir);
4797#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004798}
4799
4800module_init(msmsdcc_init);
4801module_exit(msmsdcc_exit);
4802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004803MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004804MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004805
4806#if defined(CONFIG_DEBUG_FS)
4807
4808static int
4809msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4810{
4811 file->private_data = inode->i_private;
4812 return 0;
4813}
4814
4815static ssize_t
4816msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4817 size_t count, loff_t *ppos)
4818{
4819 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
Stephen Boyd0a665852011-12-15 00:20:53 -08004820 char buf[200];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 int max, i;
4822
4823 i = 0;
4824 max = sizeof(buf) - 1;
4825
4826 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4827 host->curr.cmd, host->curr.data);
4828 if (host->curr.cmd) {
4829 struct mmc_command *cmd = host->curr.cmd;
4830
4831 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4832 cmd->opcode, cmd->arg, cmd->flags);
4833 }
4834 if (host->curr.data) {
4835 struct mmc_data *data = host->curr.data;
4836 i += scnprintf(buf + i, max - i,
4837 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4838 data->timeout_ns, data->timeout_clks,
4839 data->blksz, data->blocks, data->error,
4840 data->flags);
4841 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4842 host->curr.xfer_size, host->curr.xfer_remain,
4843 host->curr.data_xfered, host->dma.sg);
4844 }
4845
4846 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4847}
4848
4849static const struct file_operations msmsdcc_dbg_state_ops = {
4850 .read = msmsdcc_dbg_state_read,
4851 .open = msmsdcc_dbg_state_open,
4852};
4853
4854static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4855{
4856 if (debugfs_dir) {
4857 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4858 0644, debugfs_dir, host,
4859 &msmsdcc_dbg_state_ops);
4860 }
4861}
4862
4863static int __init msmsdcc_dbg_init(void)
4864{
4865 int err;
4866
4867 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4868 if (IS_ERR(debugfs_dir)) {
4869 err = PTR_ERR(debugfs_dir);
4870 debugfs_dir = NULL;
4871 return err;
4872 }
4873
4874 return 0;
4875}
4876#endif