blob: 1ce089d0cb485b56a11990ac275d5d6ca3415ae5 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
22#include <linux/device.h>
23#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070025#include <linux/delay.h>
26#include <linux/err.h>
27#include <linux/highmem.h>
28#include <linux/log2.h>
29#include <linux/mmc/host.h>
30#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080032#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070033#include <linux/clk.h>
34#include <linux/scatterlist.h>
35#include <linux/platform_device.h>
36#include <linux/dma-mapping.h>
37#include <linux/debugfs.h>
38#include <linux/io.h>
39#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/pm_runtime.h>
41#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053042#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043#include <linux/regulator/consumer.h>
44#include <linux/slab.h>
45#include <linux/mmc/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070046
47#include <asm/cacheflush.h>
48#include <asm/div64.h>
49#include <asm/sizes.h>
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070052#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053053#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054#include <mach/dma.h>
55#include <mach/htc_pwrsink.h>
56#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070057
San Mehat9d2bd732009-09-22 16:44:22 -070058#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070060
61#define DRIVER_NAME "msm-sdcc"
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define DBG(host, fmt, args...) \
64 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
65
66#define IRQ_DEBUG 0
67#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
68#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
69#define SPS_CONS_PERIPHERAL 0
70#define SPS_PROD_PERIPHERAL 1
71/* 16 KB */
72#define SPS_MAX_DESC_SIZE (16 * 1024)
73
74#if defined(CONFIG_DEBUG_FS)
75static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
76static struct dentry *debugfs_dir;
77static struct dentry *debugfs_file;
78static int msmsdcc_dbg_init(void);
79#endif
80
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);
136
San Mehat9d2bd732009-09-22 16:44:22 -0700137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
139static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
140 struct msmsdcc_sps_ep_conn_data *ep);
141static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
142 struct msmsdcc_sps_ep_conn_data *ep);
143#else
144static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
145 struct msmsdcc_sps_ep_conn_data *ep,
146 bool is_producer) { return 0; }
147static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
148 struct msmsdcc_sps_ep_conn_data *ep) { }
149static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
150 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530151{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 return 0;
153}
154static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
155 struct msmsdcc_sps_ep_conn_data *ep)
156{
157 return 0;
158}
159static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
160static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
161#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530164 * Apply soft reset to all SDCC BAM pipes
165 *
166 * This function applies soft reset to SDCC BAM pipe.
167 *
168 * This function should be called to recover from error
169 * conditions encountered during CMD/DATA tranfsers with card.
170 *
171 * @host - Pointer to driver's host structure
172 *
173 */
174static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
175{
176 int rc;
177
178 /* Reset all SDCC BAM pipes */
179 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
180 if (rc)
181 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
182 mmc_hostname(host->mmc), rc);
183 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
184 if (rc)
185 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
186 mmc_hostname(host->mmc), rc);
187
188 /* Restore all BAM pipes connections */
189 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
190 if (rc)
191 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
192 mmc_hostname(host->mmc), rc);
193 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
194 if (rc)
195 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
196 mmc_hostname(host->mmc), rc);
197}
198
199/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 * Apply soft reset
201 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530202 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 *
204 * This function should be called to recover from error
205 * conditions encountered with CMD/DATA tranfsers with card.
206 *
207 * Soft reset should only be used with SDCC controller v4.
208 *
209 * @host - Pointer to driver's host structure
210 *
211 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530212static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214 /*
215 * Reset SDCC controller's DPSM (data path state machine
216 * and CPSM (command path state machine).
217 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530219 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530221 msmsdcc_delay(host);
222}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530223
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530224static void msmsdcc_hard_reset(struct msmsdcc_host *host)
225{
226 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530227
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530228 /* Reset the controller */
229 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
230 if (ret)
231 pr_err("%s: Clock assert failed at %u Hz"
232 " with err %d\n", mmc_hostname(host->mmc),
233 host->clk_rate, ret);
234
235 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
236 if (ret)
237 pr_err("%s: Clock deassert failed at %u Hz"
238 " with err %d\n", mmc_hostname(host->mmc),
239 host->clk_rate, ret);
240
241 /* Give some delay for clock reset to propogate to controller */
242 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530243}
244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
246{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530247 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530248 if (host->is_sps_mode) {
249 /* Reset DML first */
250 msmsdcc_dml_reset(host);
251 /*
252 * delay the SPS pipe reset in thread context as
253 * sps_connect/sps_disconnect APIs can be called
254 * only from non-atomic context.
255 */
256 host->sps.pipe_reset_pending = true;
257 }
258 mb();
259 msmsdcc_soft_reset(host);
260
261 pr_debug("%s: Applied soft reset to Controller\n",
262 mmc_hostname(host->mmc));
263
264 if (host->is_sps_mode)
265 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 } else {
267 /* Give Clock reset (hard reset) to controller */
268 u32 mci_clk = 0;
269 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271 /* Save the controller state */
272 mci_clk = readl_relaxed(host->base + MMCICLOCK);
273 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530276 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 pr_debug("%s: Controller has been reinitialized\n",
278 mmc_hostname(host->mmc));
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 /* Restore the contoller state */
281 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530282 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530284 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530286 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530288
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700289 if (host->dummy_52_needed)
290 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291}
292
293static int
San Mehat9d2bd732009-09-22 16:44:22 -0700294msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
295{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 int retval = 0;
297
San Mehat9d2bd732009-09-22 16:44:22 -0700298 BUG_ON(host->curr.data);
299
300 host->curr.mrq = NULL;
301 host->curr.cmd = NULL;
302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 del_timer(&host->req_tout_timer);
304
San Mehat9d2bd732009-09-22 16:44:22 -0700305 if (mrq->data)
306 mrq->data->bytes_xfered = host->curr.data_xfered;
307 if (mrq->cmd->error == -ETIMEDOUT)
308 mdelay(5);
309
310 /*
311 * Need to drop the host lock here; mmc_request_done may call
312 * back into the driver...
313 */
314 spin_unlock(&host->lock);
315 mmc_request_done(host->mmc, mrq);
316 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317
318 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700319}
320
321static void
322msmsdcc_stop_data(struct msmsdcc_host *host)
323{
San Mehat9d2bd732009-09-22 16:44:22 -0700324 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530325 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530326 host->curr.wait_for_auto_prog_done = 0;
327 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700328 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
329 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700330 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700331}
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700334{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 return host->core_memres->start + MMCIFIFO;
336}
337
338static inline unsigned int msmsdcc_get_min_sup_clk_rate(
339 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341static inline void msmsdcc_delay(struct msmsdcc_host *host)
342{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530343 ktime_t start, diff;
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530346 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530347
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530348 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530349 (readl_relaxed(host->base + MCI_STATUS2) &
350 MCI_MCLK_REG_WR_ACTIVE)) {
351 start = ktime_get();
352 while (readl_relaxed(host->base + MCI_STATUS2) &
353 MCI_MCLK_REG_WR_ACTIVE) {
354 diff = ktime_sub(ktime_get(), start);
355 /* poll for max. 1 ms */
356 if (ktime_to_us(diff) > 1000) {
357 pr_warning("%s: previous reg. write is"
358 " still active\n",
359 mmc_hostname(host->mmc));
360 break;
361 }
362 }
363 }
San Mehat9d2bd732009-09-22 16:44:22 -0700364}
365
San Mehat56a8b5b2009-11-21 12:29:46 -0800366static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
368{
369 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530371 /*
372 * As after sending the command, we don't write any of the
373 * controller registers and just wait for the
374 * CMD_RESPOND_END/CMD_SENT/Command failure notication
375 * from Controller.
376 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800378}
379
380static void
381msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
382{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
386 writel_relaxed((unsigned int)host->curr.xfer_size,
387 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
389 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800390
San Mehat6ac9ea62009-12-02 17:24:58 -0800391 if (host->cmd_cmd) {
392 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800394 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800395}
396
San Mehat9d2bd732009-09-22 16:44:22 -0700397static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530398msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700399{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530400 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700401 unsigned long flags;
402 struct mmc_request *mrq;
403
404 spin_lock_irqsave(&host->lock, flags);
405 mrq = host->curr.mrq;
406 BUG_ON(!mrq);
407
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530408 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700409 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700410 goto out;
411 }
412
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530413 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700414 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700416 } else {
417 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530418 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700419 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530420 mmc_hostname(host->mmc), host->dma.result);
421 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700422 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530423 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530424 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 host->dma.err.flush[0], host->dma.err.flush[1],
426 host->dma.err.flush[2], host->dma.err.flush[3],
427 host->dma.err.flush[4],
428 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530429 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700430 if (!mrq->data->error)
431 mrq->data->error = -EIO;
432 }
San Mehat9d2bd732009-09-22 16:44:22 -0700433 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
434 host->dma.dir);
435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 if (host->curr.user_pages) {
437 struct scatterlist *sg = host->dma.sg;
438 int i;
439
440 for (i = 0; i < host->dma.num_ents; i++, sg++)
441 flush_dcache_page(sg_page(sg));
442 }
443
San Mehat9d2bd732009-09-22 16:44:22 -0700444 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800445 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700446
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530447 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
448 (host->curr.wait_for_auto_prog_done &&
449 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700450 /*
451 * If we've already gotten our DATAEND / DATABLKEND
452 * for this request, then complete it through here.
453 */
San Mehat9d2bd732009-09-22 16:44:22 -0700454
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700456 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 host->curr.xfer_remain -= host->curr.xfer_size;
458 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700459 if (host->dummy_52_needed) {
460 mrq->data->bytes_xfered = host->curr.data_xfered;
461 host->dummy_52_sent = 1;
462 msmsdcc_start_command(host, &dummy52cmd,
463 MCI_CPSM_PROGENA);
464 goto out;
465 }
466 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530467 if (!mrq->data->stop || mrq->cmd->error ||
468 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700469 host->curr.mrq = NULL;
470 host->curr.cmd = NULL;
471 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700473 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474
San Mehat9d2bd732009-09-22 16:44:22 -0700475 mmc_request_done(host->mmc, mrq);
476 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530477 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
478 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700479 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530480 }
San Mehat9d2bd732009-09-22 16:44:22 -0700481 }
482
483out:
484 spin_unlock_irqrestore(&host->lock, flags);
485 return;
486}
487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
489/**
490 * Callback notification from SPS driver
491 *
492 * This callback function gets triggered called from
493 * SPS driver when requested SPS data transfer is
494 * completed.
495 *
496 * SPS driver invokes this callback in BAM irq context so
497 * SDCC driver schedule a tasklet for further processing
498 * this callback notification at later point of time in
499 * tasklet context and immediately returns control back
500 * to SPS driver.
501 *
502 * @nofity - Pointer to sps event notify sturcture
503 *
504 */
505static void
506msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
507{
508 struct msmsdcc_host *host =
509 (struct msmsdcc_host *)
510 ((struct sps_event_notify *)notify)->user;
511
512 host->sps.notify = *notify;
513 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
514 mmc_hostname(host->mmc), __func__, notify->event_id,
515 notify->data.transfer.iovec.addr,
516 notify->data.transfer.iovec.size,
517 notify->data.transfer.iovec.flags);
518 /* Schedule a tasklet for completing data transfer */
519 tasklet_schedule(&host->sps.tlet);
520}
521
522/**
523 * Tasklet handler for processing SPS callback event
524 *
525 * This function processing SPS event notification and
526 * checks if the SPS transfer is completed or not and
527 * then accordingly notifies status to MMC core layer.
528 *
529 * This function is called in tasklet context.
530 *
531 * @data - Pointer to sdcc driver data
532 *
533 */
534static void msmsdcc_sps_complete_tlet(unsigned long data)
535{
536 unsigned long flags;
537 int i, rc;
538 u32 data_xfered = 0;
539 struct mmc_request *mrq;
540 struct sps_iovec iovec;
541 struct sps_pipe *sps_pipe_handle;
542 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
543 struct sps_event_notify *notify = &host->sps.notify;
544
545 spin_lock_irqsave(&host->lock, flags);
546 if (host->sps.dir == DMA_FROM_DEVICE)
547 sps_pipe_handle = host->sps.prod.pipe_handle;
548 else
549 sps_pipe_handle = host->sps.cons.pipe_handle;
550 mrq = host->curr.mrq;
551
552 if (!mrq) {
553 spin_unlock_irqrestore(&host->lock, flags);
554 return;
555 }
556
557 pr_debug("%s: %s: sps event_id=%d\n",
558 mmc_hostname(host->mmc), __func__,
559 notify->event_id);
560
561 if (msmsdcc_is_dml_busy(host)) {
562 /* oops !!! this should never happen. */
563 pr_err("%s: %s: Received SPS EOT event"
564 " but DML HW is still busy !!!\n",
565 mmc_hostname(host->mmc), __func__);
566 }
567 /*
568 * Got End of transfer event!!! Check if all of the data
569 * has been transferred?
570 */
571 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
572 rc = sps_get_iovec(sps_pipe_handle, &iovec);
573 if (rc) {
574 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
575 mmc_hostname(host->mmc), __func__, rc, i);
576 break;
577 }
578 data_xfered += iovec.size;
579 }
580
581 if (data_xfered == host->curr.xfer_size) {
582 host->curr.data_xfered = host->curr.xfer_size;
583 host->curr.xfer_remain -= host->curr.xfer_size;
584 pr_debug("%s: Data xfer success. data_xfered=0x%x",
585 mmc_hostname(host->mmc),
586 host->curr.xfer_size);
587 } else {
588 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
589 " xfer_size=%d", mmc_hostname(host->mmc),
590 data_xfered, host->curr.xfer_size);
591 msmsdcc_reset_and_restore(host);
592 if (!mrq->data->error)
593 mrq->data->error = -EIO;
594 }
595
596 /* Unmap sg buffers */
597 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
598 host->sps.dir);
599
600 host->sps.sg = NULL;
601 host->sps.busy = 0;
602
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530603 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
604 (host->curr.wait_for_auto_prog_done &&
605 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 /*
607 * If we've already gotten our DATAEND / DATABLKEND
608 * for this request, then complete it through here.
609 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610
611 if (!mrq->data->error) {
612 host->curr.data_xfered = host->curr.xfer_size;
613 host->curr.xfer_remain -= host->curr.xfer_size;
614 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700615 if (host->dummy_52_needed) {
616 mrq->data->bytes_xfered = host->curr.data_xfered;
617 host->dummy_52_sent = 1;
618 msmsdcc_start_command(host, &dummy52cmd,
619 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700620 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700621 return;
622 }
623 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530624 if (!mrq->data->stop || mrq->cmd->error ||
625 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 host->curr.mrq = NULL;
627 host->curr.cmd = NULL;
628 mrq->data->bytes_xfered = host->curr.data_xfered;
629 del_timer(&host->req_tout_timer);
630 spin_unlock_irqrestore(&host->lock, flags);
631
632 mmc_request_done(host->mmc, mrq);
633 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530634 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
635 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 msmsdcc_start_command(host, mrq->data->stop, 0);
637 }
638 }
639 spin_unlock_irqrestore(&host->lock, flags);
640}
641
642/**
643 * Exit from current SPS data transfer
644 *
645 * This function exits from current SPS data transfer.
646 *
647 * This function should be called when error condition
648 * is encountered during data transfer.
649 *
650 * @host - Pointer to sdcc host structure
651 *
652 */
653static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
654{
655 struct mmc_request *mrq;
656
657 mrq = host->curr.mrq;
658 BUG_ON(!mrq);
659
660 msmsdcc_reset_and_restore(host);
661 if (!mrq->data->error)
662 mrq->data->error = -EIO;
663
664 /* Unmap sg buffers */
665 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
666 host->sps.dir);
667
668 host->sps.sg = NULL;
669 host->sps.busy = 0;
670 if (host->curr.data)
671 msmsdcc_stop_data(host);
672
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530673 if (!mrq->data->stop || mrq->cmd->error ||
674 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530676 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
677 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678 msmsdcc_start_command(host, mrq->data->stop, 0);
679
680}
681#else
682static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
683static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
684static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
685#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
686
687static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
688
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530689static void
690msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
691 unsigned int result,
692 struct msm_dmov_errdata *err)
693{
694 struct msmsdcc_dma_data *dma_data =
695 container_of(cmd, struct msmsdcc_dma_data, hdr);
696 struct msmsdcc_host *host = dma_data->host;
697
698 dma_data->result = result;
699 if (err)
700 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
701
702 tasklet_schedule(&host->dma_tlet);
703}
704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700706{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
708 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700709 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 else
711 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700712}
713
714static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
715{
716 struct msmsdcc_nc_dmadata *nc;
717 dmov_box *box;
718 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700719 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700721 struct scatterlist *sg = data->sg;
722
Krishna Konda25786ec2011-07-25 16:21:36 -0700723 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700725
Krishna Konda25786ec2011-07-25 16:21:36 -0700726 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
727
San Mehat9d2bd732009-09-22 16:44:22 -0700728 host->dma.sg = data->sg;
729 host->dma.num_ents = data->sg_len;
730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800732
San Mehat9d2bd732009-09-22 16:44:22 -0700733 nc = host->dma.nc;
734
San Mehat9d2bd732009-09-22 16:44:22 -0700735 if (data->flags & MMC_DATA_READ)
736 host->dma.dir = DMA_FROM_DEVICE;
737 else
738 host->dma.dir = DMA_TO_DEVICE;
739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700741 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700742 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700744 box->cmd = CMD_MODE_BOX;
745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 /* Initialize sg dma address */
747 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
748 page_to_pfn(sg_page(sg)))
749 + sg->offset;
750
751 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700752 box->cmd |= CMD_LC;
753 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
754 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
755 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
756
757 if (data->flags & MMC_DATA_READ) {
758 box->src_row_addr = msmsdcc_fifo_addr(host);
759 box->dst_row_addr = sg_dma_address(sg);
760
761 box->src_dst_len = (MCI_FIFOSIZE << 16) |
762 (MCI_FIFOSIZE);
763 box->row_offset = MCI_FIFOSIZE;
764
765 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700766 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700767 } else {
768 box->src_row_addr = sg_dma_address(sg);
769 box->dst_row_addr = msmsdcc_fifo_addr(host);
770
771 box->src_dst_len = (MCI_FIFOSIZE << 16) |
772 (MCI_FIFOSIZE);
773 box->row_offset = (MCI_FIFOSIZE << 16);
774
775 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700776 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700777 }
778 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 sg++;
780 }
781
782 /* location of command block must be 64 bit aligned */
783 BUG_ON(host->dma.cmd_busaddr & 0x07);
784
785 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
786 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
787 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
788 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789
790 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
791 host->dma.num_ents, host->dma.dir);
792 /* dsb inside dma_map_sg will write nc out to mem as well */
793
794 if (n != host->dma.num_ents) {
795 pr_err("%s: Unable to map in all sg elements\n",
796 mmc_hostname(host->mmc));
797 host->dma.sg = NULL;
798 host->dma.num_ents = 0;
799 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800800 }
San Mehat9d2bd732009-09-22 16:44:22 -0700801
802 return 0;
803}
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
806/**
807 * Submits data transfer request to SPS driver
808 *
809 * This function make sg (scatter gather) data buffers
810 * DMA ready and then submits them to SPS driver for
811 * transfer.
812 *
813 * @host - Pointer to sdcc host structure
814 * @data - Pointer to mmc_data structure
815 *
816 * @return 0 if success else negative value
817 */
818static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
819 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800820{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 int rc = 0;
822 u32 flags;
823 int i;
824 u32 addr, len, data_cnt;
825 struct scatterlist *sg = data->sg;
826 struct sps_pipe *sps_pipe_handle;
827
828 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
829
830 host->sps.sg = data->sg;
831 host->sps.num_ents = data->sg_len;
832 host->sps.xfer_req_cnt = 0;
833 if (data->flags & MMC_DATA_READ) {
834 host->sps.dir = DMA_FROM_DEVICE;
835 sps_pipe_handle = host->sps.prod.pipe_handle;
836 } else {
837 host->sps.dir = DMA_TO_DEVICE;
838 sps_pipe_handle = host->sps.cons.pipe_handle;
839 }
840
841 /* Make sg buffers DMA ready */
842 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
843 host->sps.dir);
844
845 if (rc != data->sg_len) {
846 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
847 mmc_hostname(host->mmc), rc);
848 host->sps.sg = NULL;
849 host->sps.num_ents = 0;
850 rc = -ENOMEM;
851 goto dma_map_err;
852 }
853
854 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
855 mmc_hostname(host->mmc), __func__,
856 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
857 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
858
859 for (i = 0; i < data->sg_len; i++) {
860 /*
861 * Check if this is the last buffer to transfer?
862 * If yes then set the INT and EOT flags.
863 */
864 len = sg_dma_len(sg);
865 addr = sg_dma_address(sg);
866 flags = 0;
867 while (len > 0) {
868 if (len > SPS_MAX_DESC_SIZE) {
869 data_cnt = SPS_MAX_DESC_SIZE;
870 } else {
871 data_cnt = len;
872 if (i == data->sg_len - 1)
873 flags = SPS_IOVEC_FLAG_INT |
874 SPS_IOVEC_FLAG_EOT;
875 }
876 rc = sps_transfer_one(sps_pipe_handle, addr,
877 data_cnt, host, flags);
878 if (rc) {
879 pr_err("%s: sps_transfer_one() error! rc=%d,"
880 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
881 mmc_hostname(host->mmc), rc,
882 (u32)sps_pipe_handle, (u32)sg, i);
883 goto dma_map_err;
884 }
885 addr += data_cnt;
886 len -= data_cnt;
887 host->sps.xfer_req_cnt++;
888 }
889 sg++;
890 }
891 goto out;
892
893dma_map_err:
894 /* unmap sg buffers */
895 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
896 host->sps.dir);
897out:
898 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700899}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900#else
901static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
902 struct mmc_data *data) { return 0; }
903#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700904
905static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800906msmsdcc_start_command_deferred(struct msmsdcc_host *host,
907 struct mmc_command *cmd, u32 *c)
908{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 DBG(host, "op %02x arg %08x flags %08x\n",
910 cmd->opcode, cmd->arg, cmd->flags);
911
San Mehat56a8b5b2009-11-21 12:29:46 -0800912 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
913
914 if (cmd->flags & MMC_RSP_PRESENT) {
915 if (cmd->flags & MMC_RSP_136)
916 *c |= MCI_CPSM_LONGRSP;
917 *c |= MCI_CPSM_RESPONSE;
918 }
919
920 if (/*interrupt*/0)
921 *c |= MCI_CPSM_INTERRUPT;
922
923 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
924 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
925 (cmd->opcode == 53))
926 *c |= MCI_CSPM_DATCMD;
927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530929 if (host->tuning_needed) {
930 /*
931 * For open ended block read operation (without CMD23),
932 * AUTO_CMD19 bit should be set while sending the READ command.
933 * For close ended block read operation (with CMD23),
934 * AUTO_CMD19 bit should be set while sending CMD23.
935 */
936 if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
937 host->curr.mrq->cmd->opcode == 18)) ||
938 (!host->curr.mrq->sbc &&
939 (cmd->opcode == 17 || cmd->opcode == 18))) {
940 msmsdcc_enable_cdr_cm_sdc4_dll(host);
941 *c |= MCI_CSPM_AUTO_CMD19;
942 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 }
944
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530945 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530946 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530948 }
949
San Mehat56a8b5b2009-11-21 12:29:46 -0800950 if (cmd == cmd->mrq->stop)
951 *c |= MCI_CSPM_MCIABORT;
952
San Mehat56a8b5b2009-11-21 12:29:46 -0800953 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 pr_err("%s: Overlapping command requests\n",
955 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800956 }
957 host->curr.cmd = cmd;
958}
959
960static void
961msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
962 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700963{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530964 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700965 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700967 unsigned int pio_irqmask = 0;
968
969 host->curr.data = data;
970 host->curr.xfer_size = data->blksz * data->blocks;
971 host->curr.xfer_remain = host->curr.xfer_size;
972 host->curr.data_xfered = 0;
973 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530974 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700975
976 memset(&host->pio, 0, sizeof(host->pio));
977
San Mehat9d2bd732009-09-22 16:44:22 -0700978 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
979
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530980 if (host->curr.wait_for_auto_prog_done)
981 datactrl |= MCI_AUTO_PROG_DONE;
982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 if (!msmsdcc_check_dma_op_req(data)) {
984 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
985 datactrl |= MCI_DPSM_DMAENABLE;
986 } else if (host->is_sps_mode) {
987 if (!msmsdcc_is_dml_busy(host)) {
988 if (!msmsdcc_sps_start_xfer(host, data)) {
989 /* Now kick start DML transfer */
990 mb();
991 msmsdcc_dml_start_xfer(host, data);
992 datactrl |= MCI_DPSM_DMAENABLE;
993 host->sps.busy = 1;
994 }
995 } else {
996 /*
997 * Can't proceed with new transfer as
998 * previous trasnfer is already in progress.
999 * There is no point of going into PIO mode
1000 * as well. Is this a time to do kernel panic?
1001 */
1002 pr_err("%s: %s: DML HW is busy!!!"
1003 " Can't perform new SPS transfers"
1004 " now\n", mmc_hostname(host->mmc),
1005 __func__);
1006 }
1007 }
1008 }
1009
1010 /* Is data transfer in PIO mode required? */
1011 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001012 host->pio.sg = data->sg;
1013 host->pio.sg_len = data->sg_len;
1014 host->pio.sg_off = 0;
1015
1016 if (data->flags & MMC_DATA_READ) {
1017 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1018 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1019 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1020 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1022 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001023 }
1024
1025 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301026 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001027
San Mehat56a8b5b2009-11-21 12:29:46 -08001028 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001030 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1033 /* Use ADM (Application Data Mover) HW for Data transfer */
1034 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001035 host->cmd_timeout = timeout;
1036 host->cmd_pio_irqmask = pio_irqmask;
1037 host->cmd_datactrl = datactrl;
1038 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1041 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001042 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001043
1044 if (cmd) {
1045 msmsdcc_start_command_deferred(host, cmd, &c);
1046 host->cmd_c = c;
1047 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1049 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1050 host->base + MMCIMASK0);
1051 mb();
1052 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001053 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1060 (~(MCI_IRQ_PIO))) | pio_irqmask,
1061 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301063 /*
1064 * We don't need delay after writing to DATA_CTRL register
1065 * if we are not writing to CMD register immediately after
1066 * this. As we already have delay before sending the
1067 * command, we just need mb() here.
1068 */
1069 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001070
1071 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001073 /* Daisy-chain the command if requested */
1074 msmsdcc_start_command(host, cmd, c);
1075 }
San Mehat9d2bd732009-09-22 16:44:22 -07001076 }
1077}
1078
1079static void
1080msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1081{
San Mehat56a8b5b2009-11-21 12:29:46 -08001082 msmsdcc_start_command_deferred(host, cmd, &c);
1083 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001084}
1085
1086static void
1087msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1088 unsigned int status)
1089{
1090 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1092 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1093 pr_err("%s: Data CRC error\n",
1094 mmc_hostname(host->mmc));
1095 pr_err("%s: opcode 0x%.8x\n", __func__,
1096 data->mrq->cmd->opcode);
1097 pr_err("%s: blksz %d, blocks %d\n", __func__,
1098 data->blksz, data->blocks);
1099 data->error = -EILSEQ;
1100 }
San Mehat9d2bd732009-09-22 16:44:22 -07001101 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 /* CRC is optional for the bus test commands, not all
1103 * cards respond back with CRC. However controller
1104 * waits for the CRC and times out. Hence ignore the
1105 * data timeouts during the Bustest.
1106 */
1107 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1108 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1109 pr_err("%s: Data timeout\n",
1110 mmc_hostname(host->mmc));
1111 data->error = -ETIMEDOUT;
1112 }
San Mehat9d2bd732009-09-22 16:44:22 -07001113 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001114 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001115 data->error = -EIO;
1116 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001117 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001118 data->error = -EIO;
1119 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001120 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001122 data->error = -EIO;
1123 }
San Mehat9d2bd732009-09-22 16:44:22 -07001124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001126 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 host->dummy_52_needed = 0;
1128}
San Mehat9d2bd732009-09-22 16:44:22 -07001129
1130static int
1131msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1132{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001134 uint32_t *ptr = (uint32_t *) buffer;
1135 int count = 0;
1136
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301137 if (remain % 4)
1138 remain = ((remain >> 2) + 1) << 2;
1139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1141
1142 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001143 ptr++;
1144 count += sizeof(uint32_t);
1145
1146 remain -= sizeof(uint32_t);
1147 if (remain == 0)
1148 break;
1149 }
1150 return count;
1151}
1152
1153static int
1154msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001156{
1157 void __iomem *base = host->base;
1158 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 while (readl_relaxed(base + MMCISTATUS) &
1162 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1163 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001164
San Mehat9d2bd732009-09-22 16:44:22 -07001165 count = min(remain, maxcnt);
1166
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301167 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1168 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001169 ptr += count;
1170 remain -= count;
1171
1172 if (remain == 0)
1173 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 }
1175 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001176
1177 return ptr - buffer;
1178}
1179
San Mehat1cd22962010-02-03 12:59:29 -08001180static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001181msmsdcc_pio_irq(int irq, void *dev_id)
1182{
1183 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001185 uint32_t status;
1186
Murali Palnati36448a42011-09-02 15:06:18 +05301187 spin_lock(&host->lock);
1188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301192 (MCI_IRQ_PIO)) == 0) {
1193 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196
1197#if IRQ_DEBUG
1198 msmsdcc_print_status(host, "irq1-r", status);
1199#endif
1200
San Mehat9d2bd732009-09-22 16:44:22 -07001201 do {
1202 unsigned long flags;
1203 unsigned int remain, len;
1204 char *buffer;
1205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1207 | MCI_RXDATAAVLBL)))
1208 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001209
1210 /* Map the current scatter buffer */
1211 local_irq_save(flags);
1212 buffer = kmap_atomic(sg_page(host->pio.sg),
1213 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1214 buffer += host->pio.sg_off;
1215 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216
San Mehat9d2bd732009-09-22 16:44:22 -07001217 len = 0;
1218 if (status & MCI_RXACTIVE)
1219 len = msmsdcc_pio_read(host, buffer, remain);
1220 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001222
1223 /* Unmap the buffer */
1224 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1225 local_irq_restore(flags);
1226
1227 host->pio.sg_off += len;
1228 host->curr.xfer_remain -= len;
1229 host->curr.data_xfered += len;
1230 remain -= len;
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 if (remain) /* Done with this page? */
1233 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 if (status & MCI_RXACTIVE && host->curr.user_pages)
1236 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238 if (!--host->pio.sg_len) {
1239 memset(&host->pio, 0, sizeof(host->pio));
1240 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001241 }
1242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 /* Advance to next sg */
1244 host->pio.sg++;
1245 host->pio.sg_off = 0;
1246
1247 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001248 } while (1);
1249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1251 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1252 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1253 host->base + MMCIMASK0);
1254 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301255 /*
1256 * back to back write to MASK0 register don't need
1257 * synchronization delay.
1258 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1260 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1261 }
1262 mb();
1263 } else if (!host->curr.xfer_remain) {
1264 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1265 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1266 mb();
1267 }
San Mehat9d2bd732009-09-22 16:44:22 -07001268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001270
1271 return IRQ_HANDLED;
1272}
1273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274static void
1275msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1276
1277static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1278 struct mmc_data *data)
1279{
1280 u32 loop_cnt = 0;
1281
1282 /*
1283 * For read commands with data less than fifo size, it is possible to
1284 * get DATAEND first and RXDATA_AVAIL might be set later because of
1285 * synchronization delay through the asynchronous RX FIFO. Thus, for
1286 * such cases, even after DATAEND interrupt is received software
1287 * should poll for RXDATA_AVAIL until the requested data is read out
1288 * of FIFO. This change is needed to get around this abnormal but
1289 * sometimes expected behavior of SDCC3 controller.
1290 *
1291 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1292 * after the data is loaded into RX FIFO. This would amount to less
1293 * than a microsecond and thus looping for 1000 times is good enough
1294 * for that delay.
1295 */
1296 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1297 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1298 spin_unlock(&host->lock);
1299 msmsdcc_pio_irq(1, host);
1300 spin_lock(&host->lock);
1301 }
1302 }
1303 if (loop_cnt == 1000) {
1304 pr_info("%s: Timed out while polling for Rx Data\n",
1305 mmc_hostname(host->mmc));
1306 data->error = -ETIMEDOUT;
1307 msmsdcc_reset_and_restore(host);
1308 }
1309}
1310
San Mehat9d2bd732009-09-22 16:44:22 -07001311static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1312{
1313 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001314
1315 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1317 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1318 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1319 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301322 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001323 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1325 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001326 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001327 cmd->error = -EILSEQ;
1328 }
1329
1330 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 if (host->curr.data && host->dma.sg &&
1332 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001333 msm_dmov_stop_cmd(host->dma.channel,
1334 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 else if (host->curr.data && host->sps.sg &&
1336 host->is_sps_mode){
1337 /* Stop current SPS transfer */
1338 msmsdcc_sps_exit_curr_xfer(host);
1339 }
San Mehat9d2bd732009-09-22 16:44:22 -07001340 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301341 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001342 msmsdcc_stop_data(host);
1343 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301344 } else { /* host->data == NULL */
1345 if (!cmd->error && host->prog_enable) {
1346 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301348 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301350 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301351 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301352 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001353 if (host->dummy_52_needed)
1354 host->dummy_52_needed = 0;
1355 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301357 msmsdcc_request_end(host, cmd->mrq);
1358 }
1359 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301360 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1361 if (cmd->data->flags & MMC_DATA_READ)
1362 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1363 else
1364 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301365 } else if (cmd->data) {
1366 if (!(cmd->data->flags & MMC_DATA_READ))
1367 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001368 }
1369}
1370
San Mehat9d2bd732009-09-22 16:44:22 -07001371static irqreturn_t
1372msmsdcc_irq(int irq, void *dev_id)
1373{
1374 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001375 u32 status;
1376 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001378
1379 spin_lock(&host->lock);
1380
1381 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 struct mmc_command *cmd;
1383 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 if (timer) {
1386 timer = 0;
1387 msmsdcc_delay(host);
1388 }
San Mehat865c8062009-11-13 13:42:06 -08001389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 if (!host->clks_on) {
1391 pr_debug("%s: %s: SDIO async irq received\n",
1392 mmc_hostname(host->mmc), __func__);
1393 host->mmc->ios.clock = host->clk_rate;
1394 spin_unlock(&host->lock);
1395 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1396 spin_lock(&host->lock);
1397 if (host->plat->cfg_mpm_sdiowakeup &&
1398 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1399 wake_lock(&host->sdio_wlock);
1400 /* only ansyc interrupt can come when clocks are off */
1401 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301402 if (host->clk_rate <=
1403 msmsdcc_get_min_sup_clk_rate(host))
1404 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 }
1406
1407 status = readl_relaxed(host->base + MMCISTATUS);
1408
1409 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1410 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001411 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413#if IRQ_DEBUG
1414 msmsdcc_print_status(host, "irq0-r", status);
1415#endif
1416 status &= readl_relaxed(host->base + MMCIMASK0);
1417 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301418 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301419 if (host->clk_rate <=
1420 msmsdcc_get_min_sup_clk_rate(host))
1421 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422#if IRQ_DEBUG
1423 msmsdcc_print_status(host, "irq0-p", status);
1424#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1427 if (status & MCI_SDIOINTROPE) {
1428 if (host->sdcc_suspending)
1429 wake_lock(&host->sdio_suspend_wlock);
1430 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001433 data = host->curr.data;
1434
1435 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1437 MCI_CMDTIMEOUT)) {
1438 if (status & MCI_CMDTIMEOUT)
1439 pr_debug("%s: dummy CMD52 timeout\n",
1440 mmc_hostname(host->mmc));
1441 if (status & MCI_CMDCRCFAIL)
1442 pr_debug("%s: dummy CMD52 CRC failed\n",
1443 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001444 host->dummy_52_sent = 0;
1445 host->dummy_52_needed = 0;
1446 if (data) {
1447 msmsdcc_stop_data(host);
1448 msmsdcc_request_end(host, data->mrq);
1449 }
1450 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 spin_unlock(&host->lock);
1452 return IRQ_HANDLED;
1453 }
1454 break;
1455 }
1456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 /*
1458 * Check for proper command response
1459 */
1460 cmd = host->curr.cmd;
1461 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1462 MCI_CMDTIMEOUT | MCI_PROGDONE |
1463 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1464 msmsdcc_do_cmdirq(host, status);
1465 }
1466
1467 if (data) {
1468 /* Check for data errors */
1469 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1470 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1471 msmsdcc_data_err(host, data, status);
1472 host->curr.data_xfered = 0;
1473 if (host->dma.sg && host->is_dma_mode)
1474 msm_dmov_stop_cmd(host->dma.channel,
1475 &host->dma.hdr, 0);
1476 else if (host->sps.sg && host->is_sps_mode) {
1477 /* Stop current SPS transfer */
1478 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301479 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 msmsdcc_reset_and_restore(host);
1481 if (host->curr.data)
1482 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301483 if (!data->stop || (host->curr.mrq->sbc
1484 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 timer |=
1486 msmsdcc_request_end(host,
1487 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301488 else if ((host->curr.mrq->sbc
1489 && data->error) ||
1490 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 msmsdcc_start_command(host,
1492 data->stop,
1493 0);
1494 timer = 1;
1495 }
1496 }
1497 }
1498
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301499 /* Check for prog done */
1500 if (host->curr.wait_for_auto_prog_done &&
1501 (status & MCI_PROGDONE))
1502 host->curr.got_auto_prog_done = 1;
1503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 /* Check for data done */
1505 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1506 host->curr.got_dataend = 1;
1507
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301508 if (host->curr.got_dataend &&
1509 (!host->curr.wait_for_auto_prog_done ||
1510 (host->curr.wait_for_auto_prog_done &&
1511 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 /*
1513 * If DMA is still in progress, we complete
1514 * via the completion handler
1515 */
1516 if (!host->dma.busy && !host->sps.busy) {
1517 /*
1518 * There appears to be an issue in the
1519 * controller where if you request a
1520 * small block transfer (< fifo size),
1521 * you may get your DATAEND/DATABLKEND
1522 * irq without the PIO data irq.
1523 *
1524 * Check to see if theres still data
1525 * to be read, and simulate a PIO irq.
1526 */
1527 if (data->flags & MMC_DATA_READ)
1528 msmsdcc_wait_for_rxdata(host,
1529 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 if (!data->error) {
1531 host->curr.data_xfered =
1532 host->curr.xfer_size;
1533 host->curr.xfer_remain -=
1534 host->curr.xfer_size;
1535 }
1536
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001537 if (!host->dummy_52_needed) {
1538 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301539 if (!data->stop ||
1540 (host->curr.mrq->sbc
1541 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001542 msmsdcc_request_end(
1543 host,
1544 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301545 else if ((host->curr.mrq->sbc
1546 && data->error) ||
1547 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001548 msmsdcc_start_command(
1549 host,
1550 data->stop, 0);
1551 timer = 1;
1552 }
1553 } else {
1554 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001556 &dummy52cmd,
1557 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 }
1559 }
1560 }
1561 }
1562
San Mehat9d2bd732009-09-22 16:44:22 -07001563 ret = 1;
1564 } while (status);
1565
1566 spin_unlock(&host->lock);
1567
San Mehat9d2bd732009-09-22 16:44:22 -07001568 return IRQ_RETVAL(ret);
1569}
1570
1571static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1573{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301574 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301576 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301577 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1578 else
1579 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 } else {
1581 msmsdcc_start_command(host, mrq->cmd, 0);
1582 }
1583}
1584
1585static void
San Mehat9d2bd732009-09-22 16:44:22 -07001586msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1587{
1588 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 /*
1592 * Get the SDIO AL client out of LPM.
1593 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001594 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 if (host->plat->is_sdio_al_client)
1596 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001597
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301598 /* check if sps pipe reset is pending? */
1599 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1600 msmsdcc_sps_pipes_reset_and_restore(host);
1601 host->sps.pipe_reset_pending = false;
1602 }
1603
San Mehat9d2bd732009-09-22 16:44:22 -07001604 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 WARN(host->curr.mrq, "Request in progress\n");
1606 WARN(!host->pwr, "SDCC power is turned off\n");
1607 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1608 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001609
1610 if (host->eject) {
1611 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1612 mrq->cmd->error = 0;
1613 mrq->data->bytes_xfered = mrq->data->blksz *
1614 mrq->data->blocks;
1615 } else
1616 mrq->cmd->error = -ENOMEDIUM;
1617
1618 spin_unlock_irqrestore(&host->lock, flags);
1619 mmc_request_done(mmc, mrq);
1620 return;
1621 }
1622
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301623 /*
1624 * Kick the software command timeout timer here.
1625 * Timer expires in 10 secs.
1626 */
1627 mod_timer(&host->req_tout_timer,
1628 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001629
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301630 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301631 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301632 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1633 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301634 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301636 else
1637 /*
1638 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1639 * write operations using CMD53 and CMD54.
1640 * Setting this bit with CMD53 would
1641 * automatically triggers PROG_DONE interrupt
1642 * without the need of sending dummy CMD52.
1643 */
1644 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 }
San Mehat9d2bd732009-09-22 16:44:22 -07001646 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301647
Pratibhasagar V00b94332011-10-18 14:57:27 +05301648 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301649 mrq->sbc->mrq = mrq;
1650 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301651 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301652 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301653 msmsdcc_start_command(host, mrq->sbc, 0);
1654 } else {
1655 msmsdcc_request_start(host, mrq);
1656 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301657 } else {
1658 msmsdcc_request_start(host, mrq);
1659 }
1660
San Mehat9d2bd732009-09-22 16:44:22 -07001661 spin_unlock_irqrestore(&host->lock, flags);
1662}
1663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1665 int min_uV, int max_uV)
1666{
1667 int rc = 0;
1668
1669 if (vreg->set_voltage_sup) {
1670 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1671 if (rc) {
1672 pr_err("%s: regulator_set_voltage(%s) failed."
1673 " min_uV=%d, max_uV=%d, rc=%d\n",
1674 __func__, vreg->name, min_uV, max_uV, rc);
1675 }
1676 }
1677
1678 return rc;
1679}
1680
1681static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1682 int uA_load)
1683{
1684 int rc = 0;
1685
Krishna Kondafea60182011-11-01 16:01:34 -07001686 /* regulators that do not support regulator_set_voltage also
1687 do not support regulator_set_optimum_mode */
1688 if (vreg->set_voltage_sup) {
1689 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1690 if (rc < 0)
1691 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1692 "uA_load=%d) failed. rc=%d\n", __func__,
1693 vreg->name, uA_load, rc);
1694 else
1695 /* regulator_set_optimum_mode() can return non zero
1696 * value even for success case.
1697 */
1698 rc = 0;
1699 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700
1701 return rc;
1702}
1703
1704static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1705 struct device *dev)
1706{
1707 int rc = 0;
1708
1709 /* check if regulator is already initialized? */
1710 if (vreg->reg)
1711 goto out;
1712
1713 /* Get the regulator handle */
1714 vreg->reg = regulator_get(dev, vreg->name);
1715 if (IS_ERR(vreg->reg)) {
1716 rc = PTR_ERR(vreg->reg);
1717 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1718 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001719 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001721
1722 if (regulator_count_voltages(vreg->reg) > 0)
1723 vreg->set_voltage_sup = 1;
1724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725out:
1726 return rc;
1727}
1728
1729static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1730{
1731 if (vreg->reg)
1732 regulator_put(vreg->reg);
1733}
1734
1735/* This init function should be called only once for each SDCC slot */
1736static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1737{
1738 int rc = 0;
1739 struct msm_mmc_slot_reg_data *curr_slot;
1740 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1741 struct device *dev = mmc_dev(host->mmc);
1742
1743 curr_slot = host->plat->vreg_data;
1744 if (!curr_slot)
1745 goto out;
1746
1747 curr_vdd_reg = curr_slot->vdd_data;
1748 curr_vccq_reg = curr_slot->vccq_data;
1749 curr_vddp_reg = curr_slot->vddp_data;
1750
1751 if (is_init) {
1752 /*
1753 * Get the regulator handle from voltage regulator framework
1754 * and then try to set the voltage level for the regulator
1755 */
1756 if (curr_vdd_reg) {
1757 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1758 if (rc)
1759 goto out;
1760 }
1761 if (curr_vccq_reg) {
1762 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1763 if (rc)
1764 goto vdd_reg_deinit;
1765 }
1766 if (curr_vddp_reg) {
1767 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1768 if (rc)
1769 goto vccq_reg_deinit;
1770 }
1771 goto out;
1772 } else {
1773 /* Deregister all regulators from regulator framework */
1774 goto vddp_reg_deinit;
1775 }
1776vddp_reg_deinit:
1777 if (curr_vddp_reg)
1778 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1779vccq_reg_deinit:
1780 if (curr_vccq_reg)
1781 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1782vdd_reg_deinit:
1783 if (curr_vdd_reg)
1784 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1785out:
1786 return rc;
1787}
1788
1789static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1790{
1791 int rc = 0;
1792
Subhash Jadavanicc922692011-08-01 23:05:01 +05301793 /* Put regulator in HPM (high power mode) */
1794 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1795 if (rc < 0)
1796 goto out;
1797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 if (!vreg->is_enabled) {
1799 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301800 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1801 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 if (rc)
1803 goto out;
1804
1805 rc = regulator_enable(vreg->reg);
1806 if (rc) {
1807 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1808 __func__, vreg->name, rc);
1809 goto out;
1810 }
1811 vreg->is_enabled = true;
1812 }
1813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814out:
1815 return rc;
1816}
1817
1818static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1819{
1820 int rc = 0;
1821
1822 /* Never disable regulator marked as always_on */
1823 if (vreg->is_enabled && !vreg->always_on) {
1824 rc = regulator_disable(vreg->reg);
1825 if (rc) {
1826 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1827 __func__, vreg->name, rc);
1828 goto out;
1829 }
1830 vreg->is_enabled = false;
1831
1832 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1833 if (rc < 0)
1834 goto out;
1835
1836 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301837 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838 if (rc)
1839 goto out;
1840 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1841 /* Put always_on regulator in LPM (low power mode) */
1842 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1843 if (rc < 0)
1844 goto out;
1845 }
1846out:
1847 return rc;
1848}
1849
1850static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1851{
1852 int rc = 0, i;
1853 struct msm_mmc_slot_reg_data *curr_slot;
1854 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1855 struct msm_mmc_reg_data *vreg_table[3];
1856
1857 curr_slot = host->plat->vreg_data;
1858 if (!curr_slot)
1859 goto out;
1860
1861 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1862 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1863 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1864
1865 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1866 if (vreg_table[i]) {
1867 if (enable)
1868 rc = msmsdcc_vreg_enable(vreg_table[i]);
1869 else
1870 rc = msmsdcc_vreg_disable(vreg_table[i]);
1871 if (rc)
1872 goto out;
1873 }
1874 }
1875out:
1876 return rc;
1877}
1878
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301879static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880{
1881 int rc = 0;
1882
1883 if (host->plat->vreg_data) {
1884 struct msm_mmc_reg_data *vddp_reg =
1885 host->plat->vreg_data->vddp_data;
1886
1887 if (vddp_reg && vddp_reg->is_enabled)
1888 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1889 }
1890
1891 return rc;
1892}
1893
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301894static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1895{
1896 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1897 int rc = 0;
1898
1899 if (curr_slot && curr_slot->vddp_data) {
1900 rc = msmsdcc_set_vddp_level(host,
1901 curr_slot->vddp_data->low_vol_level);
1902
1903 if (rc)
1904 pr_err("%s: %s: failed to change vddp level to %d",
1905 mmc_hostname(host->mmc), __func__,
1906 curr_slot->vddp_data->low_vol_level);
1907 }
1908
1909 return rc;
1910}
1911
1912static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1913{
1914 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1915 int rc = 0;
1916
1917 if (curr_slot && curr_slot->vddp_data) {
1918 rc = msmsdcc_set_vddp_level(host,
1919 curr_slot->vddp_data->high_vol_level);
1920
1921 if (rc)
1922 pr_err("%s: %s: failed to change vddp level to %d",
1923 mmc_hostname(host->mmc), __func__,
1924 curr_slot->vddp_data->high_vol_level);
1925 }
1926
1927 return rc;
1928}
1929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1931{
1932 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1933 return 1;
1934 return 0;
1935}
1936
1937static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1938{
1939 if (enable) {
1940 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1941 clk_enable(host->dfab_pclk);
1942 if (!IS_ERR(host->pclk))
1943 clk_enable(host->pclk);
1944 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301945 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301947 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 clk_disable(host->clk);
1949 if (!IS_ERR(host->pclk))
1950 clk_disable(host->pclk);
1951 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1952 clk_disable(host->dfab_pclk);
1953 }
1954}
1955
1956static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1957 unsigned int req_clk)
1958{
1959 unsigned int sel_clk = -1;
1960
1961 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1962 unsigned char cnt;
1963
1964 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1965 if (host->plat->sup_clk_table[cnt] > req_clk)
1966 break;
1967 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1968 sel_clk = host->plat->sup_clk_table[cnt];
1969 break;
1970 } else
1971 sel_clk = host->plat->sup_clk_table[cnt];
1972 }
1973 } else {
1974 if ((req_clk < host->plat->msmsdcc_fmax) &&
1975 (req_clk > host->plat->msmsdcc_fmid))
1976 sel_clk = host->plat->msmsdcc_fmid;
1977 else
1978 sel_clk = req_clk;
1979 }
1980
1981 return sel_clk;
1982}
1983
1984static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1985 struct msmsdcc_host *host)
1986{
1987 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1988 return host->plat->sup_clk_table[0];
1989 else
1990 return host->plat->msmsdcc_fmin;
1991}
1992
1993static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1994 struct msmsdcc_host *host)
1995{
1996 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1997 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
1998 else
1999 return host->plat->msmsdcc_fmax;
2000}
2001
2002static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302003{
2004 struct msm_mmc_gpio_data *curr;
2005 int i, rc = 0;
2006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302008 for (i = 0; i < curr->size; i++) {
2009 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 if (curr->gpio[i].is_always_on &&
2011 curr->gpio[i].is_enabled)
2012 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302013 rc = gpio_request(curr->gpio[i].no,
2014 curr->gpio[i].name);
2015 if (rc) {
2016 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2017 mmc_hostname(host->mmc),
2018 curr->gpio[i].no,
2019 curr->gpio[i].name, rc);
2020 goto free_gpios;
2021 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302023 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 if (curr->gpio[i].is_always_on)
2025 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302026 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302028 }
2029 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002030 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302031
2032free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302034 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002035 curr->gpio[i].is_enabled = false;
2036 }
2037out:
2038 return rc;
2039}
2040
2041static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2042{
2043 struct msm_mmc_pad_data *curr;
2044 int i;
2045
2046 curr = host->plat->pin_data->pad_data;
2047 for (i = 0; i < curr->drv->size; i++) {
2048 if (enable)
2049 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2050 curr->drv->on[i].val);
2051 else
2052 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2053 curr->drv->off[i].val);
2054 }
2055
2056 for (i = 0; i < curr->pull->size; i++) {
2057 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002058 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 curr->pull->on[i].val);
2060 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002061 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 curr->pull->off[i].val);
2063 }
2064
2065 return 0;
2066}
2067
2068static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2069{
2070 int rc = 0;
2071
2072 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2073 return 0;
2074
2075 if (host->plat->pin_data->is_gpio)
2076 rc = msmsdcc_setup_gpio(host, enable);
2077 else
2078 rc = msmsdcc_setup_pad(host, enable);
2079
2080 if (!rc)
2081 host->plat->pin_data->cfg_sts = enable;
2082
2083 return rc;
2084}
2085
2086static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2087{
2088 unsigned int wakeup_irq;
2089
2090 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2091 host->plat->sdiowakeup_irq :
2092 host->core_irqres->start;
2093
2094 if (!host->irq_wake_enabled) {
2095 enable_irq_wake(wakeup_irq);
2096 host->irq_wake_enabled = true;
2097 }
2098}
2099
2100static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2101{
2102 unsigned int wakeup_irq;
2103
2104 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2105 host->plat->sdiowakeup_irq :
2106 host->core_irqres->start;
2107
2108 if (host->irq_wake_enabled) {
2109 disable_irq_wake(wakeup_irq);
2110 host->irq_wake_enabled = false;
2111 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302112}
2113
San Mehat9d2bd732009-09-22 16:44:22 -07002114static void
2115msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2116{
2117 struct msmsdcc_host *host = mmc_priv(mmc);
2118 u32 clk = 0, pwr = 0;
2119 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002120 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002123 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302124
San Mehat9d2bd732009-09-22 16:44:22 -07002125 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002126 spin_lock_irqsave(&host->lock, flags);
2127 if (!host->clks_on) {
2128 msmsdcc_setup_clocks(host, true);
2129 host->clks_on = 1;
2130 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2131 if (!host->plat->sdiowakeup_irq) {
2132 writel_relaxed(host->mci_irqenable,
2133 host->base + MMCIMASK0);
2134 mb();
2135 if (host->plat->cfg_mpm_sdiowakeup &&
2136 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2137 host->plat->cfg_mpm_sdiowakeup(
2138 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2139 msmsdcc_disable_irq_wake(host);
2140 } else if (!(mmc->pm_flags &
2141 MMC_PM_WAKE_SDIO_IRQ)) {
2142 writel_relaxed(host->mci_irqenable,
2143 host->base + MMCIMASK0);
2144 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302145 } else {
2146 writel_relaxed(host->mci_irqenable,
2147 host->base + MMCIMASK0);
2148 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149 }
San Mehat9d2bd732009-09-22 16:44:22 -07002150 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 spin_unlock_irqrestore(&host->lock, flags);
2152
2153 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2154 /*
2155 * For DDR50 mode, controller needs clock rate to be
2156 * double than what is required on the SD card CLK pin.
2157 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302158 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159 /*
2160 * Make sure that we don't double the clock if
2161 * doubled clock rate is already set
2162 */
2163 if (!host->ddr_doubled_clk_rate ||
2164 (host->ddr_doubled_clk_rate &&
2165 (host->ddr_doubled_clk_rate != ios->clock))) {
2166 host->ddr_doubled_clk_rate =
2167 msmsdcc_get_sup_clk_rate(
2168 host, (ios->clock * 2));
2169 clock = host->ddr_doubled_clk_rate;
2170 }
2171 } else {
2172 host->ddr_doubled_clk_rate = 0;
2173 }
2174
2175 if (clock != host->clk_rate) {
2176 rc = clk_set_rate(host->clk, clock);
2177 if (rc < 0)
2178 pr_debug("%s: failed to set clk rate %u\n",
2179 mmc_hostname(mmc), clock);
2180 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302181 host->reg_write_delay =
2182 (1 + ((3 * USEC_PER_SEC) /
2183 (host->clk_rate ? host->clk_rate :
2184 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 }
2186 /*
2187 * give atleast 2 MCLK cycles delay for clocks
2188 * and SDCC core to stabilize
2189 */
2190 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002191 clk |= MCI_CLK_ENABLE;
2192 }
2193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 if (ios->bus_width == MMC_BUS_WIDTH_8)
2195 clk |= MCI_CLK_WIDEBUS_8;
2196 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2197 clk |= MCI_CLK_WIDEBUS_4;
2198 else
2199 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 if (msmsdcc_is_pwrsave(host))
2202 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 host->tuning_needed = 0;
2207 /*
2208 * Select the controller timing mode according
2209 * to current bus speed mode
2210 */
2211 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2212 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2213 clk |= (4 << 14);
2214 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302215 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 clk |= (3 << 14);
2217 } else {
2218 clk |= (2 << 14); /* feedback clock */
2219 }
2220
2221 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2222 clk |= (2 << 23);
2223
2224 if (host->io_pad_pwr_switch)
2225 clk |= IO_PAD_PWR_SWITCH;
2226
2227 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002228 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2230 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002231
2232 switch (ios->power_mode) {
2233 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2235 if (!host->sdcc_irq_disabled) {
2236 if (host->plat->cfg_mpm_sdiowakeup)
2237 host->plat->cfg_mpm_sdiowakeup(
2238 mmc_dev(mmc), SDC_DAT1_DISABLE);
2239 disable_irq(host->core_irqres->start);
2240 host->sdcc_irq_disabled = 1;
2241 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302242 /*
2243 * As VDD pad rail is always on, set low voltage for VDD
2244 * pad rail when slot is unused (when card is not present
2245 * or during system suspend).
2246 */
2247 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002249 break;
2250 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302251 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002252 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 if (host->sdcc_irq_disabled) {
2254 if (host->plat->cfg_mpm_sdiowakeup)
2255 host->plat->cfg_mpm_sdiowakeup(
2256 mmc_dev(mmc), SDC_DAT1_ENABLE);
2257 enable_irq(host->core_irqres->start);
2258 host->sdcc_irq_disabled = 0;
2259 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302260 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002262 break;
2263 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002265 pwr |= MCI_PWR_ON;
2266 break;
2267 }
2268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 spin_lock_irqsave(&host->lock, flags);
2270 if (!host->clks_on) {
2271 /* force the clocks to be on */
2272 msmsdcc_setup_clocks(host, true);
2273 /*
2274 * give atleast 2 MCLK cycles delay for clocks
2275 * and SDCC core to stabilize
2276 */
2277 msmsdcc_delay(host);
2278 }
2279 writel_relaxed(clk, host->base + MMCICLOCK);
2280 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002281
2282 if (host->pwr != pwr) {
2283 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302285 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002286 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 if (!host->clks_on) {
2288 /* force the clocks to be off */
2289 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290 }
2291
2292 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2293 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2294 if (!host->plat->sdiowakeup_irq) {
2295 writel_relaxed(MCI_SDIOINTMASK,
2296 host->base + MMCIMASK0);
2297 mb();
2298 if (host->plat->cfg_mpm_sdiowakeup &&
2299 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2300 host->plat->cfg_mpm_sdiowakeup(
2301 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2302 msmsdcc_enable_irq_wake(host);
2303 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2304 writel_relaxed(0, host->base + MMCIMASK0);
2305 } else {
2306 writel_relaxed(MCI_SDIOINTMASK,
2307 host->base + MMCIMASK0);
2308 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302309 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 }
2311 msmsdcc_setup_clocks(host, false);
2312 host->clks_on = 0;
2313 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002314 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002315}
2316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2318{
2319 struct msmsdcc_host *host = mmc_priv(mmc);
2320 u32 clk;
2321
2322 clk = readl_relaxed(host->base + MMCICLOCK);
2323 pr_debug("Changing to pwr_save=%d", pwrsave);
2324 if (pwrsave && msmsdcc_is_pwrsave(host))
2325 clk |= MCI_CLK_PWRSAVE;
2326 else
2327 clk &= ~MCI_CLK_PWRSAVE;
2328 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302329 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330
2331 return 0;
2332}
2333
2334static int msmsdcc_get_ro(struct mmc_host *mmc)
2335{
2336 int status = -ENOSYS;
2337 struct msmsdcc_host *host = mmc_priv(mmc);
2338
2339 if (host->plat->wpswitch) {
2340 status = host->plat->wpswitch(mmc_dev(mmc));
2341 } else if (host->plat->wpswitch_gpio) {
2342 status = gpio_request(host->plat->wpswitch_gpio,
2343 "SD_WP_Switch");
2344 if (status) {
2345 pr_err("%s: %s: Failed to request GPIO %d\n",
2346 mmc_hostname(mmc), __func__,
2347 host->plat->wpswitch_gpio);
2348 } else {
2349 status = gpio_direction_input(
2350 host->plat->wpswitch_gpio);
2351 if (!status) {
2352 /*
2353 * Wait for atleast 300ms as debounce
2354 * time for GPIO input to stabilize.
2355 */
2356 msleep(300);
2357 status = gpio_get_value_cansleep(
2358 host->plat->wpswitch_gpio);
2359 status ^= !host->plat->wpswitch_polarity;
2360 }
2361 gpio_free(host->plat->wpswitch_gpio);
2362 }
2363 }
2364
2365 if (status < 0)
2366 status = -ENOSYS;
2367 pr_debug("%s: Card read-only status %d\n", __func__, status);
2368
2369 return status;
2370}
2371
2372#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002373static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2374{
2375 struct msmsdcc_host *host = mmc_priv(mmc);
2376 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377
2378 if (enable) {
2379 spin_lock_irqsave(&host->lock, flags);
2380 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2381 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2382 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2383 spin_unlock_irqrestore(&host->lock, flags);
2384 } else {
2385 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2386 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2387 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2388 }
2389 mb();
2390}
2391#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2392
2393#ifdef CONFIG_PM_RUNTIME
2394static int msmsdcc_enable(struct mmc_host *mmc)
2395{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302396 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002397 struct device *dev = mmc->parent;
2398
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302399 if (dev->power.runtime_status == RPM_SUSPENDING) {
2400 if (mmc->suspend_task == current) {
2401 pm_runtime_get_noresume(dev);
2402 goto out;
2403 }
2404 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302406 rc = pm_runtime_get_sync(dev);
2407
2408 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2410 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302411 return rc;
2412 }
2413out:
2414 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415}
2416
2417static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2418{
2419 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302420 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302422 if (host->plat->disable_runtime_pm)
2423 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2425 return -ENOTSUPP;
2426
2427 rc = pm_runtime_put_sync(mmc->parent);
2428
2429 if (rc < 0)
2430 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2431 __func__, rc);
2432 return rc;
2433}
2434#else
2435#define msmsdcc_enable NULL
2436#define msmsdcc_disable NULL
2437#endif
2438
2439static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2440 struct mmc_ios *ios)
2441{
2442 struct msmsdcc_host *host = mmc_priv(mmc);
2443 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302444 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445
2446 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2447 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302448 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002449 goto out;
2450 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2451 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302452 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 goto out;
2454 }
San Mehat9d2bd732009-09-22 16:44:22 -07002455
2456 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 /*
2458 * If we are here means voltage switch from high voltage to
2459 * low voltage is required
2460 */
2461
2462 /*
2463 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2464 * register until they become all zeros.
2465 */
2466 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302467 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2469 mmc_hostname(mmc), __func__);
2470 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002471 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472
2473 /* Stop SD CLK output. */
2474 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2475 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302476 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002477 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002478
2479 /*
2480 * Switch VDDPX from high voltage to low voltage
2481 * to change the VDD of the SD IO pads.
2482 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302483 rc = msmsdcc_set_vddp_low_vol(host);
2484 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486
2487 spin_lock_irqsave(&host->lock, flags);
2488 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2489 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302490 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 host->io_pad_pwr_switch = 1;
2492 spin_unlock_irqrestore(&host->lock, flags);
2493
2494 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2495 usleep_range(5000, 5500);
2496
2497 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302498 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2500 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302501 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002502 spin_unlock_irqrestore(&host->lock, flags);
2503
2504 /*
2505 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2506 * don't become all ones within 1 ms then a Voltage Switch
2507 * sequence has failed and a power cycle to the card is required.
2508 * Otherwise Voltage Switch sequence is completed successfully.
2509 */
2510 usleep_range(1000, 1500);
2511
2512 spin_lock_irqsave(&host->lock, flags);
2513 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2514 != (0xF << 1)) {
2515 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2516 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302517 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518 goto out_unlock;
2519 }
2520
2521out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302522 /* Enable PWRSAVE */
2523 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2524 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 spin_unlock_irqrestore(&host->lock, flags);
2526out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302527 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002528}
2529
2530static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2531 u8 phase);
2532/* Initialize the DLL (Programmable Delay Line ) */
2533static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2534{
2535 int rc = 0;
2536 u32 wait_timeout;
2537
2538 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2539 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2540 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2541
2542 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2543 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2544 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2545
2546 msmsdcc_delay(host);
2547
2548 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2549 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2550 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2551
2552 /* Initialize the phase to 0 */
2553 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2554 if (rc)
2555 goto out;
2556
2557 wait_timeout = 1000;
2558 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2559 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2560 /* max. wait for 1 sec for LOCK bit to be set */
2561 if (--wait_timeout == 0) {
2562 pr_err("%s: %s: DLL failed to lock at phase: %d",
2563 mmc_hostname(host->mmc), __func__, 0);
2564 rc = -1;
2565 goto out;
2566 }
2567 /* wait for 1ms */
2568 usleep_range(1000, 1500);
2569 }
2570out:
2571 return rc;
2572}
2573
2574/*
2575 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2576 * calibration sequence. This function should be called before
2577 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2578 * commands (CMD17/CMD18).
2579 */
2580static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2581{
2582 /* Set CDR_EN bit to 1. */
2583 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2584 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2585
2586 /* Set CDR_EXT_EN bit to 0. */
2587 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2588 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2589
2590 /* Set CK_OUT_EN bit to 0. */
2591 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2592 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2593
2594 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2595 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2596 ;
2597
2598 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2599 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2600 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2601
2602 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2603 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2604 ;
2605}
2606
2607static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2608 u8 phase)
2609{
2610 int rc = 0;
2611 u32 mclk_freq = 0;
2612 u32 wait_timeout;
2613
2614 /* Set CDR_EN bit to 0. */
2615 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2616 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2617
2618 /* Set CDR_EXT_EN bit to 1. */
2619 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2620 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2621
2622 /* Program the MCLK value to MCLK_FREQ bit field */
2623 if (host->clk_rate <= 112000000)
2624 mclk_freq = 0;
2625 else if (host->clk_rate <= 125000000)
2626 mclk_freq = 1;
2627 else if (host->clk_rate <= 137000000)
2628 mclk_freq = 2;
2629 else if (host->clk_rate <= 150000000)
2630 mclk_freq = 3;
2631 else if (host->clk_rate <= 162000000)
2632 mclk_freq = 4;
2633 else if (host->clk_rate <= 175000000)
2634 mclk_freq = 5;
2635 else if (host->clk_rate <= 187000000)
2636 mclk_freq = 6;
2637 else if (host->clk_rate <= 200000000)
2638 mclk_freq = 7;
2639
2640 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2641 & ~(7 << 24)) | (mclk_freq << 24)),
2642 host->base + MCI_DLL_CONFIG);
2643
2644 /* Set CK_OUT_EN bit to 0. */
2645 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2646 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2647
2648 /* Set DLL_EN bit to 1. */
2649 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2650 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2651
2652 wait_timeout = 1000;
2653 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2654 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2655 /* max. wait for 1 sec for LOCK bit for be set */
2656 if (--wait_timeout == 0) {
2657 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2658 mmc_hostname(host->mmc), __func__, phase);
2659 rc = -1;
2660 goto out;
2661 }
2662 /* wait for 1ms */
2663 usleep_range(1000, 1500);
2664 }
2665
2666 /*
2667 * Write the selected DLL clock output phase (0 ... 15)
2668 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2669 */
2670 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2671 & ~(0xF << 20)) | (phase << 20)),
2672 host->base + MCI_DLL_CONFIG);
2673
2674 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2675 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2676 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2677
2678 wait_timeout = 1000;
2679 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2680 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2681 /* max. wait for 1 sec for LOCK bit for be set */
2682 if (--wait_timeout == 0) {
2683 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2684 mmc_hostname(host->mmc), __func__, phase);
2685 rc = -1;
2686 goto out;
2687 }
2688 /* wait for 1ms */
2689 usleep_range(1000, 1500);
2690 }
2691out:
2692 return rc;
2693}
2694
2695static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2696{
2697 struct msmsdcc_host *host = mmc_priv(mmc);
2698 u8 phase;
2699 u8 *data_buf;
2700 u8 tuned_phases[16], tuned_phase_cnt = 0;
2701 int rc = 0;
2702
2703 /* Tuning is only required for SDR50 & SDR104 modes */
2704 if (!host->tuning_needed) {
2705 rc = 0;
2706 goto out;
2707 }
2708
2709 host->cmd19_tuning_in_progress = 1;
2710 /*
2711 * Make sure that clock is always enabled when DLL
2712 * tuning is in progress. Keeping PWRSAVE ON may
2713 * turn off the clock. So let's disable the PWRSAVE
2714 * here and re-enable it once tuning is completed.
2715 */
2716 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2717 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302718 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 /* first of all reset the tuning block */
2720 rc = msmsdcc_init_cm_sdc4_dll(host);
2721 if (rc)
2722 goto out;
2723
2724 data_buf = kmalloc(64, GFP_KERNEL);
2725 if (!data_buf) {
2726 rc = -ENOMEM;
2727 goto out;
2728 }
2729
2730 phase = 0;
2731 do {
2732 struct mmc_command cmd = {0};
2733 struct mmc_data data = {0};
2734 struct mmc_request mrq = {
2735 .cmd = &cmd,
2736 .data = &data
2737 };
2738 struct scatterlist sg;
2739
2740 /* set the phase in delay line hw block */
2741 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2742 if (rc)
2743 goto kfree;
2744
2745 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2746 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2747
2748 data.blksz = 64;
2749 data.blocks = 1;
2750 data.flags = MMC_DATA_READ;
2751 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2752
2753 data.sg = &sg;
2754 data.sg_len = 1;
2755 sg_init_one(&sg, data_buf, 64);
2756 memset(data_buf, 0, 64);
2757 mmc_wait_for_req(mmc, &mrq);
2758
2759 if (!cmd.error && !data.error &&
2760 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2761 /* tuning is successful with this tuning point */
2762 tuned_phases[tuned_phase_cnt++] = phase;
2763 }
2764 } while (++phase < 16);
2765
2766 kfree(data_buf);
2767
2768 if (tuned_phase_cnt) {
2769 tuned_phase_cnt--;
2770 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2771 phase = tuned_phases[tuned_phase_cnt];
2772 /*
2773 * Finally set the selected phase in delay
2774 * line hw block.
2775 */
2776 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2777 if (rc)
2778 goto out;
2779 } else {
2780 /* tuning failed */
2781 rc = -EAGAIN;
2782 pr_err("%s: %s: no tuning point found",
2783 mmc_hostname(mmc), __func__);
2784 }
2785 goto out;
2786
2787kfree:
2788 kfree(data_buf);
2789out:
2790 /* re-enable PWESAVE */
2791 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2792 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302793 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 host->cmd19_tuning_in_progress = 0;
2795 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002796}
2797
2798static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 .enable = msmsdcc_enable,
2800 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002801 .request = msmsdcc_request,
2802 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803 .get_ro = msmsdcc_get_ro,
2804#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002805 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806#endif
2807 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2808 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002809};
2810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811static unsigned int
2812msmsdcc_slot_status(struct msmsdcc_host *host)
2813{
2814 int status;
2815 unsigned int gpio_no = host->plat->status_gpio;
2816
2817 status = gpio_request(gpio_no, "SD_HW_Detect");
2818 if (status) {
2819 pr_err("%s: %s: Failed to request GPIO %d\n",
2820 mmc_hostname(host->mmc), __func__, gpio_no);
2821 } else {
2822 status = gpio_direction_input(gpio_no);
2823 if (!status)
2824 status = !gpio_get_value_cansleep(gpio_no);
2825 gpio_free(gpio_no);
2826 }
2827 return status;
2828}
2829
San Mehat9d2bd732009-09-22 16:44:22 -07002830static void
2831msmsdcc_check_status(unsigned long data)
2832{
2833 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2834 unsigned int status;
2835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836 if (host->plat->status || host->plat->status_gpio) {
2837 if (host->plat->status)
2838 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002839 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 status = msmsdcc_slot_status(host);
2841
2842 host->eject = !status;
2843 if (status ^ host->oldstat) {
2844 pr_info("%s: Slot status change detected (%d -> %d)\n",
2845 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002846 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847 }
2848 host->oldstat = status;
2849 } else {
2850 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002851 }
San Mehat9d2bd732009-09-22 16:44:22 -07002852}
2853
2854static irqreturn_t
2855msmsdcc_platform_status_irq(int irq, void *dev_id)
2856{
2857 struct msmsdcc_host *host = dev_id;
2858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002859 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002860 msmsdcc_check_status((unsigned long) host);
2861 return IRQ_HANDLED;
2862}
2863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002864static irqreturn_t
2865msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2866{
2867 struct msmsdcc_host *host = dev_id;
2868
2869 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2870 spin_lock(&host->lock);
2871 if (!host->sdio_irq_disabled) {
2872 disable_irq_nosync(irq);
2873 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2874 wake_lock(&host->sdio_wlock);
2875 msmsdcc_disable_irq_wake(host);
2876 }
2877 host->sdio_irq_disabled = 1;
2878 }
2879 if (host->plat->is_sdio_al_client) {
2880 if (!host->clks_on) {
2881 msmsdcc_setup_clocks(host, true);
2882 host->clks_on = 1;
2883 }
2884 if (host->sdcc_irq_disabled) {
2885 writel_relaxed(host->mci_irqenable,
2886 host->base + MMCIMASK0);
2887 mb();
2888 enable_irq(host->core_irqres->start);
2889 host->sdcc_irq_disabled = 0;
2890 }
2891 wake_lock(&host->sdio_wlock);
2892 }
2893 spin_unlock(&host->lock);
2894
2895 return IRQ_HANDLED;
2896}
2897
San Mehat9d2bd732009-09-22 16:44:22 -07002898static void
2899msmsdcc_status_notify_cb(int card_present, void *dev_id)
2900{
2901 struct msmsdcc_host *host = dev_id;
2902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002904 card_present);
2905 msmsdcc_check_status((unsigned long) host);
2906}
2907
San Mehat9d2bd732009-09-22 16:44:22 -07002908static int
2909msmsdcc_init_dma(struct msmsdcc_host *host)
2910{
2911 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2912 host->dma.host = host;
2913 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002914 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002915
2916 if (!host->dmares)
2917 return -ENODEV;
2918
2919 host->dma.nc = dma_alloc_coherent(NULL,
2920 sizeof(struct msmsdcc_nc_dmadata),
2921 &host->dma.nc_busaddr,
2922 GFP_KERNEL);
2923 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002924 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002925 return -ENOMEM;
2926 }
2927 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2928 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2929 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2930 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2931 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002932 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002933
2934 return 0;
2935}
2936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002937#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2938/**
2939 * Allocate and Connect a SDCC peripheral's SPS endpoint
2940 *
2941 * This function allocates endpoint context and
2942 * connect it with memory endpoint by calling
2943 * appropriate SPS driver APIs.
2944 *
2945 * Also registers a SPS callback function with
2946 * SPS driver
2947 *
2948 * This function should only be called once typically
2949 * during driver probe.
2950 *
2951 * @host - Pointer to sdcc host structure
2952 * @ep - Pointer to sps endpoint data structure
2953 * @is_produce - 1 means Producer endpoint
2954 * 0 means Consumer endpoint
2955 *
2956 * @return - 0 if successful else negative value.
2957 *
2958 */
2959static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2960 struct msmsdcc_sps_ep_conn_data *ep,
2961 bool is_producer)
2962{
2963 int rc = 0;
2964 struct sps_pipe *sps_pipe_handle;
2965 struct sps_connect *sps_config = &ep->config;
2966 struct sps_register_event *sps_event = &ep->event;
2967
2968 /* Allocate endpoint context */
2969 sps_pipe_handle = sps_alloc_endpoint();
2970 if (!sps_pipe_handle) {
2971 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2972 mmc_hostname(host->mmc), is_producer);
2973 rc = -ENOMEM;
2974 goto out;
2975 }
2976
2977 /* Get default connection configuration for an endpoint */
2978 rc = sps_get_config(sps_pipe_handle, sps_config);
2979 if (rc) {
2980 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2981 " rc=%d", mmc_hostname(host->mmc),
2982 (u32)sps_pipe_handle, rc);
2983 goto get_config_err;
2984 }
2985
2986 /* Modify the default connection configuration */
2987 if (is_producer) {
2988 /*
2989 * For SDCC producer transfer, source should be
2990 * SDCC peripheral where as destination should
2991 * be system memory.
2992 */
2993 sps_config->source = host->sps.bam_handle;
2994 sps_config->destination = SPS_DEV_HANDLE_MEM;
2995 /* Producer pipe will handle this connection */
2996 sps_config->mode = SPS_MODE_SRC;
2997 sps_config->options =
2998 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
2999 } else {
3000 /*
3001 * For SDCC consumer transfer, source should be
3002 * system memory where as destination should
3003 * SDCC peripheral
3004 */
3005 sps_config->source = SPS_DEV_HANDLE_MEM;
3006 sps_config->destination = host->sps.bam_handle;
3007 sps_config->mode = SPS_MODE_DEST;
3008 sps_config->options =
3009 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3010 }
3011
3012 /* Producer pipe index */
3013 sps_config->src_pipe_index = host->sps.src_pipe_index;
3014 /* Consumer pipe index */
3015 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3016 /*
3017 * This event thresold value is only significant for BAM-to-BAM
3018 * transfer. It's ignored for BAM-to-System mode transfer.
3019 */
3020 sps_config->event_thresh = 0x10;
3021 /*
3022 * Max. no of scatter/gather buffers that can
3023 * be passed by block layer = 32 (NR_SG).
3024 * Each BAM descritor needs 64 bits (8 bytes).
3025 * One BAM descriptor is required per buffer transfer.
3026 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3027 * But due to HW limitation we need to allocate atleast one extra
3028 * descriptor memory (256 bytes + 8 bytes). But in order to be
3029 * in power of 2, we are allocating 512 bytes of memory.
3030 */
3031 sps_config->desc.size = 512;
3032 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3033 sps_config->desc.size,
3034 &sps_config->desc.phys_base,
3035 GFP_KERNEL);
3036
Pratibhasagar V00b94332011-10-18 14:57:27 +05303037 if (!sps_config->desc.base) {
3038 rc = -ENOMEM;
3039 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3040 , mmc_hostname(host->mmc));
3041 goto get_config_err;
3042 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003043 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3044
3045 /* Establish connection between peripheral and memory endpoint */
3046 rc = sps_connect(sps_pipe_handle, sps_config);
3047 if (rc) {
3048 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3049 " rc=%d", mmc_hostname(host->mmc),
3050 (u32)sps_pipe_handle, rc);
3051 goto sps_connect_err;
3052 }
3053
3054 sps_event->mode = SPS_TRIGGER_CALLBACK;
3055 sps_event->options = SPS_O_EOT;
3056 sps_event->callback = msmsdcc_sps_complete_cb;
3057 sps_event->xfer_done = NULL;
3058 sps_event->user = (void *)host;
3059
3060 /* Register callback event for EOT (End of transfer) event. */
3061 rc = sps_register_event(sps_pipe_handle, sps_event);
3062 if (rc) {
3063 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3064 " rc=%d", mmc_hostname(host->mmc),
3065 (u32)sps_pipe_handle, rc);
3066 goto reg_event_err;
3067 }
3068 /* Now save the sps pipe handle */
3069 ep->pipe_handle = sps_pipe_handle;
3070 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3071 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3072 __func__, is_producer ? "READ" : "WRITE",
3073 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3074 goto out;
3075
3076reg_event_err:
3077 sps_disconnect(sps_pipe_handle);
3078sps_connect_err:
3079 dma_free_coherent(mmc_dev(host->mmc),
3080 sps_config->desc.size,
3081 sps_config->desc.base,
3082 sps_config->desc.phys_base);
3083get_config_err:
3084 sps_free_endpoint(sps_pipe_handle);
3085out:
3086 return rc;
3087}
3088
3089/**
3090 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3091 *
3092 * This function disconnect endpoint and deallocates
3093 * endpoint context.
3094 *
3095 * This function should only be called once typically
3096 * during driver remove.
3097 *
3098 * @host - Pointer to sdcc host structure
3099 * @ep - Pointer to sps endpoint data structure
3100 *
3101 */
3102static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3103 struct msmsdcc_sps_ep_conn_data *ep)
3104{
3105 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3106 struct sps_connect *sps_config = &ep->config;
3107 struct sps_register_event *sps_event = &ep->event;
3108
3109 sps_event->xfer_done = NULL;
3110 sps_event->callback = NULL;
3111 sps_register_event(sps_pipe_handle, sps_event);
3112 sps_disconnect(sps_pipe_handle);
3113 dma_free_coherent(mmc_dev(host->mmc),
3114 sps_config->desc.size,
3115 sps_config->desc.base,
3116 sps_config->desc.phys_base);
3117 sps_free_endpoint(sps_pipe_handle);
3118}
3119
3120/**
3121 * Reset SDCC peripheral's SPS endpoint
3122 *
3123 * This function disconnects an endpoint.
3124 *
3125 * This function should be called for reseting
3126 * SPS endpoint when data transfer error is
3127 * encountered during data transfer. This
3128 * can be considered as soft reset to endpoint.
3129 *
3130 * This function should only be called if
3131 * msmsdcc_sps_init() is already called.
3132 *
3133 * @host - Pointer to sdcc host structure
3134 * @ep - Pointer to sps endpoint data structure
3135 *
3136 * @return - 0 if successful else negative value.
3137 */
3138static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3139 struct msmsdcc_sps_ep_conn_data *ep)
3140{
3141 int rc = 0;
3142 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3143
3144 rc = sps_disconnect(sps_pipe_handle);
3145 if (rc) {
3146 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3147 " rc=%d", mmc_hostname(host->mmc), __func__,
3148 (u32)sps_pipe_handle, rc);
3149 goto out;
3150 }
3151 out:
3152 return rc;
3153}
3154
3155/**
3156 * Restore SDCC peripheral's SPS endpoint
3157 *
3158 * This function connects an endpoint.
3159 *
3160 * This function should be called for restoring
3161 * SPS endpoint after data transfer error is
3162 * encountered during data transfer. This
3163 * can be considered as soft reset to endpoint.
3164 *
3165 * This function should only be called if
3166 * msmsdcc_sps_reset_ep() is called before.
3167 *
3168 * @host - Pointer to sdcc host structure
3169 * @ep - Pointer to sps endpoint data structure
3170 *
3171 * @return - 0 if successful else negative value.
3172 */
3173static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3174 struct msmsdcc_sps_ep_conn_data *ep)
3175{
3176 int rc = 0;
3177 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3178 struct sps_connect *sps_config = &ep->config;
3179 struct sps_register_event *sps_event = &ep->event;
3180
3181 /* Establish connection between peripheral and memory endpoint */
3182 rc = sps_connect(sps_pipe_handle, sps_config);
3183 if (rc) {
3184 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3185 " rc=%d", mmc_hostname(host->mmc), __func__,
3186 (u32)sps_pipe_handle, rc);
3187 goto out;
3188 }
3189
3190 /* Register callback event for EOT (End of transfer) event. */
3191 rc = sps_register_event(sps_pipe_handle, sps_event);
3192 if (rc) {
3193 pr_err("%s: %s: sps_register_event() failed!!!"
3194 " pipe_handle=0x%x, rc=%d",
3195 mmc_hostname(host->mmc), __func__,
3196 (u32)sps_pipe_handle, rc);
3197 goto reg_event_err;
3198 }
3199 goto out;
3200
3201reg_event_err:
3202 sps_disconnect(sps_pipe_handle);
3203out:
3204 return rc;
3205}
3206
3207/**
3208 * Initialize SPS HW connected with SDCC core
3209 *
3210 * This function register BAM HW resources with
3211 * SPS driver and then initialize 2 SPS endpoints
3212 *
3213 * This function should only be called once typically
3214 * during driver probe.
3215 *
3216 * @host - Pointer to sdcc host structure
3217 *
3218 * @return - 0 if successful else negative value.
3219 *
3220 */
3221static int msmsdcc_sps_init(struct msmsdcc_host *host)
3222{
3223 int rc = 0;
3224 struct sps_bam_props bam = {0};
3225
3226 host->bam_base = ioremap(host->bam_memres->start,
3227 resource_size(host->bam_memres));
3228 if (!host->bam_base) {
3229 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3230 " size=0x%x", mmc_hostname(host->mmc),
3231 host->bam_memres->start,
3232 (host->bam_memres->end -
3233 host->bam_memres->start));
3234 rc = -ENOMEM;
3235 goto out;
3236 }
3237
3238 bam.phys_addr = host->bam_memres->start;
3239 bam.virt_addr = host->bam_base;
3240 /*
3241 * This event thresold value is only significant for BAM-to-BAM
3242 * transfer. It's ignored for BAM-to-System mode transfer.
3243 */
3244 bam.event_threshold = 0x10; /* Pipe event threshold */
3245 /*
3246 * This threshold controls when the BAM publish
3247 * the descriptor size on the sideband interface.
3248 * SPS HW will only be used when
3249 * data transfer size > MCI_FIFOSIZE (64 bytes).
3250 * PIO mode will be used when
3251 * data transfer size < MCI_FIFOSIZE (64 bytes).
3252 * So set this thresold value to 64 bytes.
3253 */
3254 bam.summing_threshold = 64;
3255 /* SPS driver wll handle the SDCC BAM IRQ */
3256 bam.irq = (u32)host->bam_irqres->start;
3257 bam.manage = SPS_BAM_MGR_LOCAL;
3258
3259 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3260 (u32)bam.phys_addr);
3261 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3262 (u32)bam.virt_addr);
3263
3264 /* Register SDCC Peripheral BAM device to SPS driver */
3265 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3266 if (rc) {
3267 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3268 mmc_hostname(host->mmc), rc);
3269 goto reg_bam_err;
3270 }
3271 pr_info("%s: BAM device registered. bam_handle=0x%x",
3272 mmc_hostname(host->mmc), host->sps.bam_handle);
3273
3274 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3275 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3276
3277 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3278 SPS_PROD_PERIPHERAL);
3279 if (rc)
3280 goto sps_reset_err;
3281 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3282 SPS_CONS_PERIPHERAL);
3283 if (rc)
3284 goto cons_conn_err;
3285
3286 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3287 mmc_hostname(host->mmc),
3288 (unsigned long long)host->bam_memres->start,
3289 (unsigned int)host->bam_irqres->start);
3290 goto out;
3291
3292cons_conn_err:
3293 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3294sps_reset_err:
3295 sps_deregister_bam_device(host->sps.bam_handle);
3296reg_bam_err:
3297 iounmap(host->bam_base);
3298out:
3299 return rc;
3300}
3301
3302/**
3303 * De-initialize SPS HW connected with SDCC core
3304 *
3305 * This function deinitialize SPS endpoints and then
3306 * deregisters BAM resources from SPS driver.
3307 *
3308 * This function should only be called once typically
3309 * during driver remove.
3310 *
3311 * @host - Pointer to sdcc host structure
3312 *
3313 */
3314static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3315{
3316 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3317 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3318 sps_deregister_bam_device(host->sps.bam_handle);
3319 iounmap(host->bam_base);
3320}
3321#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3322
3323static ssize_t
3324show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3325{
3326 struct mmc_host *mmc = dev_get_drvdata(dev);
3327 struct msmsdcc_host *host = mmc_priv(mmc);
3328 int poll;
3329 unsigned long flags;
3330
3331 spin_lock_irqsave(&host->lock, flags);
3332 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3333 spin_unlock_irqrestore(&host->lock, flags);
3334
3335 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3336}
3337
3338static ssize_t
3339set_polling(struct device *dev, struct device_attribute *attr,
3340 const char *buf, size_t count)
3341{
3342 struct mmc_host *mmc = dev_get_drvdata(dev);
3343 struct msmsdcc_host *host = mmc_priv(mmc);
3344 int value;
3345 unsigned long flags;
3346
3347 sscanf(buf, "%d", &value);
3348
3349 spin_lock_irqsave(&host->lock, flags);
3350 if (value) {
3351 mmc->caps |= MMC_CAP_NEEDS_POLL;
3352 mmc_detect_change(host->mmc, 0);
3353 } else {
3354 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3355 }
3356#ifdef CONFIG_HAS_EARLYSUSPEND
3357 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3358#endif
3359 spin_unlock_irqrestore(&host->lock, flags);
3360 return count;
3361}
3362
3363static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3364 show_polling, set_polling);
3365static struct attribute *dev_attrs[] = {
3366 &dev_attr_polling.attr,
3367 NULL,
3368};
3369static struct attribute_group dev_attr_grp = {
3370 .attrs = dev_attrs,
3371};
3372
3373#ifdef CONFIG_HAS_EARLYSUSPEND
3374static void msmsdcc_early_suspend(struct early_suspend *h)
3375{
3376 struct msmsdcc_host *host =
3377 container_of(h, struct msmsdcc_host, early_suspend);
3378 unsigned long flags;
3379
3380 spin_lock_irqsave(&host->lock, flags);
3381 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3382 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3383 spin_unlock_irqrestore(&host->lock, flags);
3384};
3385static void msmsdcc_late_resume(struct early_suspend *h)
3386{
3387 struct msmsdcc_host *host =
3388 container_of(h, struct msmsdcc_host, early_suspend);
3389 unsigned long flags;
3390
3391 if (host->polling_enabled) {
3392 spin_lock_irqsave(&host->lock, flags);
3393 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3394 mmc_detect_change(host->mmc, 0);
3395 spin_unlock_irqrestore(&host->lock, flags);
3396 }
3397};
3398#endif
3399
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303400void msmsdcc_print_regs(const char *name, void __iomem *base,
3401 unsigned int no_of_regs)
3402{
3403 unsigned int i;
3404
3405 if (!base)
3406 return;
3407 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3408 name, (u32)base);
3409 for (i = 0; i < no_of_regs; i = i + 4) {
3410 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3411 (u32)readl_relaxed(base + i*4),
3412 (u32)readl_relaxed(base + ((i+1)*4)),
3413 (u32)readl_relaxed(base + ((i+2)*4)),
3414 (u32)readl_relaxed(base + ((i+3)*4)));
3415 }
3416}
3417
3418static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3419{
3420 /* Dump current state of SDCC clocks, power and irq */
3421 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3422 (host->pwr ? "ON" : "OFF"));
3423 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3424 mmc_hostname(host->mmc),
3425 (host->clks_on ? "ON" : "OFF"),
3426 (u32)clk_get_rate(host->clk));
3427 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3428 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3429
3430 /* Now dump SDCC registers. Don't print FIFO registers */
3431 if (host->clks_on)
3432 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3433
3434 if (host->curr.data) {
3435 if (msmsdcc_check_dma_op_req(host->curr.data))
3436 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3437 else if (host->is_dma_mode)
3438 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3439 mmc_hostname(host->mmc), host->dma.busy,
3440 host->dma.channel, host->dma.crci);
3441 else if (host->is_sps_mode)
3442 pr_info("%s: SPS mode: busy=%d\n",
3443 mmc_hostname(host->mmc), host->sps.busy);
3444
3445 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3446 mmc_hostname(host->mmc), host->curr.xfer_size,
3447 host->curr.data_xfered, host->curr.xfer_remain);
3448 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3449 " wait_for_auto_prog_done=%d,"
3450 " got_auto_prog_done=%d\n",
3451 mmc_hostname(host->mmc), host->curr.got_dataend,
3452 host->prog_enable, host->curr.wait_for_auto_prog_done,
3453 host->curr.got_auto_prog_done);
3454 }
3455
3456}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3458{
3459 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3460 struct mmc_request *mrq;
3461 unsigned long flags;
3462
3463 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003464 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 pr_info("%s: %s: dummy CMD52 timeout\n",
3466 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003467 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003468 }
3469
3470 mrq = host->curr.mrq;
3471
3472 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303473 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3474 mrq->cmd->opcode);
3475 msmsdcc_dump_sdcc_state(host);
3476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 if (!mrq->cmd->error)
3478 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303479 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003480 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481 if (mrq->data && !mrq->data->error)
3482 mrq->data->error = -ETIMEDOUT;
3483 host->curr.data_xfered = 0;
3484 if (host->dma.sg && host->is_dma_mode) {
3485 msm_dmov_stop_cmd(host->dma.channel,
3486 &host->dma.hdr, 0);
3487 } else if (host->sps.sg && host->is_sps_mode) {
3488 /* Stop current SPS transfer */
3489 msmsdcc_sps_exit_curr_xfer(host);
3490 } else {
3491 msmsdcc_reset_and_restore(host);
3492 msmsdcc_stop_data(host);
3493 if (mrq->data && mrq->data->stop)
3494 msmsdcc_start_command(host,
3495 mrq->data->stop, 0);
3496 else
3497 msmsdcc_request_end(host, mrq);
3498 }
3499 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303500 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003501 msmsdcc_reset_and_restore(host);
3502 msmsdcc_request_end(host, mrq);
3503 }
3504 }
3505 spin_unlock_irqrestore(&host->lock, flags);
3506}
3507
San Mehat9d2bd732009-09-22 16:44:22 -07003508static int
3509msmsdcc_probe(struct platform_device *pdev)
3510{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511 struct mmc_platform_data *plat = pdev->dev.platform_data;
San Mehat9d2bd732009-09-22 16:44:22 -07003512 struct msmsdcc_host *host;
3513 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 unsigned long flags;
3515 struct resource *core_irqres = NULL;
3516 struct resource *bam_irqres = NULL;
3517 struct resource *core_memres = NULL;
3518 struct resource *dml_memres = NULL;
3519 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003520 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003521 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303522 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003523 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003524
3525 /* must have platform data */
3526 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003527 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003528 ret = -EINVAL;
3529 goto out;
3530 }
3531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003532 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003533 return -EINVAL;
3534
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303535 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3536 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3537 return -EINVAL;
3538 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539
San Mehat9d2bd732009-09-22 16:44:22 -07003540 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003541 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003542 return -ENXIO;
3543 }
3544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545 for (i = 0; i < pdev->num_resources; i++) {
3546 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3547 if (!strcmp(pdev->resource[i].name,
3548 "sdcc_dml_addr"))
3549 dml_memres = &pdev->resource[i];
3550 else if (!strcmp(pdev->resource[i].name,
3551 "sdcc_bam_addr"))
3552 bam_memres = &pdev->resource[i];
3553 else
3554 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003556 }
3557 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3558 if (!strcmp(pdev->resource[i].name,
3559 "sdcc_bam_irq"))
3560 bam_irqres = &pdev->resource[i];
3561 else
3562 core_irqres = &pdev->resource[i];
3563 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003564 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3565 if (!strncmp(pdev->resource[i].name,
3566 "sdcc_dma_chnl",
3567 sizeof("sdcc_dma_chnl")))
3568 dmares = &pdev->resource[i];
3569 else if (!strncmp(pdev->resource[i].name,
3570 "sdcc_dma_crci",
3571 sizeof("sdcc_dma_crci")))
3572 dma_crci_res = &pdev->resource[i];
3573 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574 }
3575
3576 if (!core_irqres || !core_memres) {
3577 pr_err("%s: Invalid sdcc core resource\n", __func__);
3578 return -ENXIO;
3579 }
3580
3581 /*
3582 * Both BAM and DML memory resource should be preset.
3583 * BAM IRQ resource should also be present.
3584 */
3585 if ((bam_memres && !dml_memres) ||
3586 (!bam_memres && dml_memres) ||
3587 ((bam_memres && dml_memres) && !bam_irqres)) {
3588 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003589 return -ENXIO;
3590 }
3591
3592 /*
3593 * Setup our host structure
3594 */
San Mehat9d2bd732009-09-22 16:44:22 -07003595 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3596 if (!mmc) {
3597 ret = -ENOMEM;
3598 goto out;
3599 }
3600
3601 host = mmc_priv(mmc);
3602 host->pdev_id = pdev->id;
3603 host->plat = plat;
3604 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003605 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303606
3607 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608 host->is_sps_mode = 1;
3609 else if (dmares)
3610 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 host->base = ioremap(core_memres->start,
3613 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003614 if (!host->base) {
3615 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003617 }
3618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619 host->core_irqres = core_irqres;
3620 host->bam_irqres = bam_irqres;
3621 host->core_memres = core_memres;
3622 host->dml_memres = dml_memres;
3623 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003624 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003625 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003626 spin_lock_init(&host->lock);
3627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003628#ifdef CONFIG_MMC_EMBEDDED_SDIO
3629 if (plat->embedded_sdio)
3630 mmc_set_embedded_sdio_data(mmc,
3631 &plat->embedded_sdio->cis,
3632 &plat->embedded_sdio->cccr,
3633 plat->embedded_sdio->funcs,
3634 plat->embedded_sdio->num_funcs);
3635#endif
3636
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303637 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3638 (unsigned long)host);
3639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003640 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3641 (unsigned long)host);
3642 if (host->is_dma_mode) {
3643 /* Setup DMA */
3644 ret = msmsdcc_init_dma(host);
3645 if (ret)
3646 goto ioremap_free;
3647 } else {
3648 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003649 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003650 }
3651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003652 /*
3653 * Setup SDCC clock if derived from Dayatona
3654 * fabric core clock.
3655 */
3656 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003657 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003658 if (!IS_ERR(host->dfab_pclk)) {
3659 /* Set the clock rate to 64MHz for max. performance */
3660 ret = clk_set_rate(host->dfab_pclk, 64000000);
3661 if (ret)
3662 goto dfab_pclk_put;
3663 ret = clk_enable(host->dfab_pclk);
3664 if (ret)
3665 goto dfab_pclk_put;
3666 } else
3667 goto dma_free;
3668 }
3669
3670 /*
3671 * Setup main peripheral bus clock
3672 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003673 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674 if (!IS_ERR(host->pclk)) {
3675 ret = clk_enable(host->pclk);
3676 if (ret)
3677 goto pclk_put;
3678
3679 host->pclk_rate = clk_get_rate(host->pclk);
3680 }
3681
3682 /*
3683 * Setup SDC MMC clock
3684 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003685 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003686 if (IS_ERR(host->clk)) {
3687 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003689 }
3690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3692 if (ret) {
3693 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3694 goto clk_put;
3695 }
3696
3697 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003698 if (ret)
3699 goto clk_put;
3700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303702 if (!host->clk_rate)
3703 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303704
3705 /*
3706 * Lookup the Controller Version, to identify the supported features
3707 * Version number read as 0 would indicate SDCC3 or earlier versions
3708 */
3709 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3710 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3711 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303712 /*
3713 * Set the register write delay according to min. clock frequency
3714 * supported and update later when the host->clk_rate changes.
3715 */
3716 host->reg_write_delay =
3717 (1 + ((3 * USEC_PER_SEC) /
3718 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003719
3720 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303721 /* Apply Hard reset to SDCC to put it in power on default state */
3722 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003723
3724 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003725 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003727 goto clk_disable;
3728 }
3729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730
3731 /* Clocks has to be running before accessing SPS/DML HW blocks */
3732 if (host->is_sps_mode) {
3733 /* Initialize SPS */
3734 ret = msmsdcc_sps_init(host);
3735 if (ret)
3736 goto vreg_deinit;
3737 /* Initialize DML */
3738 ret = msmsdcc_dml_init(host);
3739 if (ret)
3740 goto sps_exit;
3741 }
San Mehat9d2bd732009-09-22 16:44:22 -07003742
San Mehat9d2bd732009-09-22 16:44:22 -07003743 /*
3744 * Setup MMC host structure
3745 */
3746 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3748 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003749 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3751 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003752
San Mehat9d2bd732009-09-22 16:44:22 -07003753 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303754 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303755
3756 /*
3757 * If we send the CMD23 before multi block write/read command
3758 * then we need not to send CMD12 at the end of the transfer.
3759 * If we don't send the CMD12 then only way to detect the PROG_DONE
3760 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3761 * controller. So let's enable the CMD23 for SDCC4 only.
3762 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303763 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303764 mmc->caps |= MMC_CAP_CMD23;
3765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003766 mmc->caps |= plat->uhs_caps;
3767 /*
3768 * XPC controls the maximum current in the default speed mode of SDXC
3769 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3770 * XPC=1 means 150mA (max.) and speed class is supported.
3771 */
3772 if (plat->xpc_cap)
3773 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3774 MMC_CAP_SET_XPC_180);
3775
3776 if (plat->nonremovable)
3777 mmc->caps |= MMC_CAP_NONREMOVABLE;
3778#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3779 mmc->caps |= MMC_CAP_SDIO_IRQ;
3780#endif
3781
3782 if (plat->is_sdio_al_client)
3783 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003784
Martin K. Petersena36274e2010-09-10 01:33:59 -04003785 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003786 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003788
3789 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3790 mmc->max_seg_size = mmc->max_req_size;
3791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003792 writel_relaxed(0, host->base + MMCIMASK0);
3793 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3796 mb();
3797 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3800 DRIVER_NAME " (cmd)", host);
3801 if (ret)
3802 goto dml_exit;
3803
3804 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3805 DRIVER_NAME " (pio)", host);
3806 if (ret)
3807 goto irq_free;
3808
3809 /*
3810 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3811 * IRQ is un-necessarily being monitored by MPM (Modem power
3812 * management block) during idle-power collapse. The MPM will be
3813 * configured to monitor the DATA1 GPIO line with level-low trigger
3814 * and thus depending on the GPIO status, it prevents TCXO shutdown
3815 * during idle-power collapse.
3816 */
3817 disable_irq(core_irqres->start);
3818 host->sdcc_irq_disabled = 1;
3819
3820 if (plat->sdiowakeup_irq) {
3821 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3822 mmc_hostname(mmc));
3823 ret = request_irq(plat->sdiowakeup_irq,
3824 msmsdcc_platform_sdiowakeup_irq,
3825 IRQF_SHARED | IRQF_TRIGGER_LOW,
3826 DRIVER_NAME "sdiowakeup", host);
3827 if (ret) {
3828 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3829 plat->sdiowakeup_irq, ret);
3830 goto pio_irq_free;
3831 } else {
3832 spin_lock_irqsave(&host->lock, flags);
3833 if (!host->sdio_irq_disabled) {
3834 disable_irq_nosync(plat->sdiowakeup_irq);
3835 host->sdio_irq_disabled = 1;
3836 }
3837 spin_unlock_irqrestore(&host->lock, flags);
3838 }
3839 }
3840
3841 if (plat->cfg_mpm_sdiowakeup) {
3842 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3843 mmc_hostname(mmc));
3844 }
3845
3846 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3847 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003848 /*
3849 * Setup card detect change
3850 */
3851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852 if (plat->status || plat->status_gpio) {
3853 if (plat->status)
3854 host->oldstat = plat->status(mmc_dev(host->mmc));
3855 else
3856 host->oldstat = msmsdcc_slot_status(host);
3857 host->eject = !host->oldstat;
3858 }
San Mehat9d2bd732009-09-22 16:44:22 -07003859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860 if (plat->status_irq) {
3861 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003862 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003864 DRIVER_NAME " (slot)",
3865 host);
3866 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003867 pr_err("Unable to get slot IRQ %d (%d)\n",
3868 plat->status_irq, ret);
3869 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003870 }
3871 } else if (plat->register_status_notify) {
3872 plat->register_status_notify(msmsdcc_status_notify_cb, host);
3873 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003874 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07003875 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003876
3877 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878
3879 ret = pm_runtime_set_active(&(pdev)->dev);
3880 if (ret < 0)
3881 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
3882 __func__, ret);
3883 /*
3884 * There is no notion of suspend/resume for SD/MMC/SDIO
3885 * cards. So host can be suspended/resumed with out
3886 * worrying about its children.
3887 */
3888 pm_suspend_ignore_children(&(pdev)->dev, true);
3889
3890 /*
3891 * MMC/SD/SDIO bus suspend/resume operations are defined
3892 * only for the slots that will be used for non-removable
3893 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
3894 * defined. Otherwise, they simply become card removal and
3895 * insertion events during suspend and resume respectively.
3896 * Hence, enable run-time PM only for slots for which bus
3897 * suspend/resume operations are defined.
3898 */
3899#ifdef CONFIG_MMC_UNSAFE_RESUME
3900 /*
3901 * If this capability is set, MMC core will enable/disable host
3902 * for every claim/release operation on a host. We use this
3903 * notification to increment/decrement runtime pm usage count.
3904 */
3905 mmc->caps |= MMC_CAP_DISABLE;
3906 pm_runtime_enable(&(pdev)->dev);
3907#else
3908 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
3909 mmc->caps |= MMC_CAP_DISABLE;
3910 pm_runtime_enable(&(pdev)->dev);
3911 }
3912#endif
3913 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
3914 (unsigned long)host);
3915
San Mehat9d2bd732009-09-22 16:44:22 -07003916 mmc_add_host(mmc);
3917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918#ifdef CONFIG_HAS_EARLYSUSPEND
3919 host->early_suspend.suspend = msmsdcc_early_suspend;
3920 host->early_suspend.resume = msmsdcc_late_resume;
3921 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
3922 register_early_suspend(&host->early_suspend);
3923#endif
San Mehat9d2bd732009-09-22 16:44:22 -07003924
Krishna Konda25786ec2011-07-25 16:21:36 -07003925 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
3926 " dmacrcri %d\n", mmc_hostname(mmc),
3927 (unsigned long long)core_memres->start,
3928 (unsigned int) core_irqres->start,
3929 (unsigned int) plat->status_irq, host->dma.channel,
3930 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931
3932 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
3933 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
3934 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
3935 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
3936 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
3937 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
3938 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
3939 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
3940 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
3941 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
3942 host->eject);
3943 pr_info("%s: Power save feature enable = %d\n",
3944 mmc_hostname(mmc), msmsdcc_pwrsave);
3945
Krishna Konda25786ec2011-07-25 16:21:36 -07003946 if (host->is_dma_mode && host->dma.channel != -1
3947 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003948 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003950 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 mmc_hostname(mmc), host->dma.cmd_busaddr,
3952 host->dma.cmdptr_busaddr);
3953 } else if (host->is_sps_mode) {
3954 pr_info("%s: SPS-BAM data transfer mode available\n",
3955 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003956 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003957 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003959#if defined(CONFIG_DEBUG_FS)
3960 msmsdcc_dbg_createhost(host);
3961#endif
3962 if (!plat->status_irq) {
3963 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
3964 if (ret)
3965 goto platform_irq_free;
3966 }
San Mehat9d2bd732009-09-22 16:44:22 -07003967 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968
3969 platform_irq_free:
3970 del_timer_sync(&host->req_tout_timer);
3971 pm_runtime_disable(&(pdev)->dev);
3972 pm_runtime_set_suspended(&(pdev)->dev);
3973
3974 if (plat->status_irq)
3975 free_irq(plat->status_irq, host);
3976 sdiowakeup_irq_free:
3977 wake_lock_destroy(&host->sdio_suspend_wlock);
3978 if (plat->sdiowakeup_irq)
3979 free_irq(plat->sdiowakeup_irq, host);
3980 pio_irq_free:
3981 if (plat->sdiowakeup_irq)
3982 wake_lock_destroy(&host->sdio_wlock);
3983 free_irq(core_irqres->start, host);
3984 irq_free:
3985 free_irq(core_irqres->start, host);
3986 dml_exit:
3987 if (host->is_sps_mode)
3988 msmsdcc_dml_exit(host);
3989 sps_exit:
3990 if (host->is_sps_mode)
3991 msmsdcc_sps_exit(host);
3992 vreg_deinit:
3993 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07003994 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003995 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003996 clk_put:
3997 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998 pclk_disable:
3999 if (!IS_ERR(host->pclk))
4000 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004001 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004002 if (!IS_ERR(host->pclk))
4003 clk_put(host->pclk);
4004 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4005 clk_disable(host->dfab_pclk);
4006 dfab_pclk_put:
4007 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4008 clk_put(host->dfab_pclk);
4009 dma_free:
4010 if (host->is_dma_mode) {
4011 if (host->dmares)
4012 dma_free_coherent(NULL,
4013 sizeof(struct msmsdcc_nc_dmadata),
4014 host->dma.nc, host->dma.nc_busaddr);
4015 }
4016 ioremap_free:
4017 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004018 host_free:
4019 mmc_free_host(mmc);
4020 out:
4021 return ret;
4022}
4023
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004024static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004025{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4027 struct mmc_platform_data *plat;
4028 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 if (!mmc)
4031 return -ENXIO;
4032
4033 if (pm_runtime_suspended(&(pdev)->dev))
4034 pm_runtime_resume(&(pdev)->dev);
4035
4036 host = mmc_priv(mmc);
4037
4038 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4039 plat = host->plat;
4040
4041 if (!plat->status_irq)
4042 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4043
4044 del_timer_sync(&host->req_tout_timer);
4045 tasklet_kill(&host->dma_tlet);
4046 tasklet_kill(&host->sps.tlet);
4047 mmc_remove_host(mmc);
4048
4049 if (plat->status_irq)
4050 free_irq(plat->status_irq, host);
4051
4052 wake_lock_destroy(&host->sdio_suspend_wlock);
4053 if (plat->sdiowakeup_irq) {
4054 wake_lock_destroy(&host->sdio_wlock);
4055 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4056 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004057 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004058
4059 free_irq(host->core_irqres->start, host);
4060 free_irq(host->core_irqres->start, host);
4061
4062 clk_put(host->clk);
4063 if (!IS_ERR(host->pclk))
4064 clk_put(host->pclk);
4065 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4066 clk_put(host->dfab_pclk);
4067
4068 msmsdcc_vreg_init(host, false);
4069
4070 if (host->is_dma_mode) {
4071 if (host->dmares)
4072 dma_free_coherent(NULL,
4073 sizeof(struct msmsdcc_nc_dmadata),
4074 host->dma.nc, host->dma.nc_busaddr);
4075 }
4076
4077 if (host->is_sps_mode) {
4078 msmsdcc_dml_exit(host);
4079 msmsdcc_sps_exit(host);
4080 }
4081
4082 iounmap(host->base);
4083 mmc_free_host(mmc);
4084
4085#ifdef CONFIG_HAS_EARLYSUSPEND
4086 unregister_early_suspend(&host->early_suspend);
4087#endif
4088 pm_runtime_disable(&(pdev)->dev);
4089 pm_runtime_set_suspended(&(pdev)->dev);
4090
4091 return 0;
4092}
4093
4094#ifdef CONFIG_MSM_SDIO_AL
4095int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4096{
4097 struct msmsdcc_host *host = mmc_priv(mmc);
4098 unsigned long flags;
4099
4100 spin_lock_irqsave(&host->lock, flags);
4101 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4102 enable ? "En" : "Dis");
4103
4104 if (enable) {
4105 if (!host->sdcc_irq_disabled) {
4106 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304107 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 host->sdcc_irq_disabled = 1;
4109 }
4110
4111 if (host->clks_on) {
4112 msmsdcc_setup_clocks(host, false);
4113 host->clks_on = 0;
4114 }
4115
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304116 if (host->plat->sdio_lpm_gpio_setup &&
4117 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004118 spin_unlock_irqrestore(&host->lock, flags);
4119 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4120 spin_lock_irqsave(&host->lock, flags);
4121 host->sdio_gpio_lpm = 1;
4122 }
4123
4124 if (host->sdio_irq_disabled) {
4125 msmsdcc_enable_irq_wake(host);
4126 enable_irq(host->plat->sdiowakeup_irq);
4127 host->sdio_irq_disabled = 0;
4128 }
4129 } else {
4130 if (!host->sdio_irq_disabled) {
4131 disable_irq_nosync(host->plat->sdiowakeup_irq);
4132 host->sdio_irq_disabled = 1;
4133 msmsdcc_disable_irq_wake(host);
4134 }
4135
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304136 if (host->plat->sdio_lpm_gpio_setup &&
4137 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 spin_unlock_irqrestore(&host->lock, flags);
4139 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4140 spin_lock_irqsave(&host->lock, flags);
4141 host->sdio_gpio_lpm = 0;
4142 }
4143
4144 if (!host->clks_on) {
4145 msmsdcc_setup_clocks(host, true);
4146 host->clks_on = 1;
4147 }
4148
4149 if (host->sdcc_irq_disabled) {
4150 writel_relaxed(host->mci_irqenable,
4151 host->base + MMCIMASK0);
4152 mb();
4153 enable_irq(host->core_irqres->start);
4154 host->sdcc_irq_disabled = 0;
4155 }
4156 wake_lock_timeout(&host->sdio_wlock, 1);
4157 }
4158 spin_unlock_irqrestore(&host->lock, flags);
4159 return 0;
4160}
4161#else
4162int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4163{
4164 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004165}
4166#endif
4167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004169static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004170msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004171{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172 struct mmc_host *mmc = dev_get_drvdata(dev);
4173 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004174 int rc = 0;
4175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176 if (host->plat->is_sdio_al_client)
4177 return 0;
4178
Sahitya Tummala7661a452011-07-18 13:28:35 +05304179 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004180 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004181 host->sdcc_suspending = 1;
4182 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 /*
4185 * If the clocks are already turned off by SDIO clients (as
4186 * part of LPM), then clocks should be turned on before
4187 * calling mmc_suspend_host() because mmc_suspend_host might
4188 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304189 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190 * cards, clocks will be turned on before mmc_suspend_host
4191 * and turned off after mmc_suspend_host.
4192 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304193 if (mmc->card && mmc_card_sdio(mmc->card)) {
4194 mmc->ios.clock = host->clk_rate;
4195 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4196 }
San Mehat9d2bd732009-09-22 16:44:22 -07004197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004198 /*
4199 * MMC core thinks that host is disabled by now since
4200 * runtime suspend is scheduled after msmsdcc_disable()
4201 * is called. Thus, MMC core will try to enable the host
4202 * while suspending it. This results in a synchronous
4203 * runtime resume request while in runtime suspending
4204 * context and hence inorder to complete this resume
4205 * requet, it will wait for suspend to be complete,
4206 * but runtime suspend also can not proceed further
4207 * until the host is resumed. Thus, it leads to a hang.
4208 * Hence, increase the pm usage count before suspending
4209 * the host so that any resume requests after this will
4210 * simple become pm usage counter increment operations.
4211 */
4212 pm_runtime_get_noresume(dev);
4213 rc = mmc_suspend_host(mmc);
4214 pm_runtime_put_noidle(dev);
4215
4216 if (!rc) {
4217 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4218 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4219 disable_irq(host->core_irqres->start);
4220 host->sdcc_irq_disabled = 1;
4221
4222 /*
4223 * If MMC core level suspend is not supported,
4224 * turn off clocks to allow deep sleep (TCXO
4225 * shutdown).
4226 */
4227 mmc->ios.clock = 0;
4228 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4229 enable_irq(host->core_irqres->start);
4230 host->sdcc_irq_disabled = 0;
4231
4232 if (host->plat->sdiowakeup_irq) {
4233 host->sdio_irq_disabled = 0;
4234 msmsdcc_enable_irq_wake(host);
4235 enable_irq(host->plat->sdiowakeup_irq);
4236 }
4237 }
4238 }
4239 host->sdcc_suspending = 0;
4240 mmc->suspend_task = NULL;
4241 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4242 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004243 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304244 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004245 return rc;
4246}
4247
4248static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004250{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 struct mmc_host *mmc = dev_get_drvdata(dev);
4252 struct msmsdcc_host *host = mmc_priv(mmc);
4253 unsigned long flags;
4254
4255 if (host->plat->is_sdio_al_client)
4256 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004257
Sahitya Tummala7661a452011-07-18 13:28:35 +05304258 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004259 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004260 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4261 if (host->sdcc_irq_disabled) {
4262 enable_irq(host->core_irqres->start);
4263 host->sdcc_irq_disabled = 0;
4264 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304265 mmc->ios.clock = host->clk_rate;
4266 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004267
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304268 spin_lock_irqsave(&host->lock, flags);
4269 writel_relaxed(host->mci_irqenable,
4270 host->base + MMCIMASK0);
4271 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004272
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304273 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4274 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275 if (host->plat->sdiowakeup_irq) {
4276 disable_irq_nosync(
4277 host->plat->sdiowakeup_irq);
4278 msmsdcc_disable_irq_wake(host);
4279 host->sdio_irq_disabled = 1;
4280 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304281 }
San Mehat9d2bd732009-09-22 16:44:22 -07004282
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304283 spin_unlock_irqrestore(&host->lock, flags);
4284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004285
4286 mmc_resume_host(mmc);
4287
4288 /*
4289 * FIXME: Clearing of flags must be handled in clients
4290 * resume handler.
4291 */
4292 spin_lock_irqsave(&host->lock, flags);
4293 mmc->pm_flags = 0;
4294 spin_unlock_irqrestore(&host->lock, flags);
4295
4296 /*
4297 * After resuming the host wait for sometime so that
4298 * the SDIO work will be processed.
4299 */
4300 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4301 if ((host->plat->cfg_mpm_sdiowakeup ||
4302 host->plat->sdiowakeup_irq) &&
4303 wake_lock_active(&host->sdio_wlock))
4304 wake_lock_timeout(&host->sdio_wlock, 1);
4305 }
4306
4307 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004308 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304309 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004310 return 0;
4311}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004312
4313static int msmsdcc_runtime_idle(struct device *dev)
4314{
4315 struct mmc_host *mmc = dev_get_drvdata(dev);
4316 struct msmsdcc_host *host = mmc_priv(mmc);
4317
4318 if (host->plat->is_sdio_al_client)
4319 return 0;
4320
4321 /* Idle timeout is not configurable for now */
4322 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4323
4324 return -EAGAIN;
4325}
4326
4327static int msmsdcc_pm_suspend(struct device *dev)
4328{
4329 struct mmc_host *mmc = dev_get_drvdata(dev);
4330 struct msmsdcc_host *host = mmc_priv(mmc);
4331 int rc = 0;
4332
4333 if (host->plat->is_sdio_al_client)
4334 return 0;
4335
4336
4337 if (host->plat->status_irq)
4338 disable_irq(host->plat->status_irq);
4339
4340 if (!pm_runtime_suspended(dev))
4341 rc = msmsdcc_runtime_suspend(dev);
4342
4343 return rc;
4344}
4345
4346static int msmsdcc_pm_resume(struct device *dev)
4347{
4348 struct mmc_host *mmc = dev_get_drvdata(dev);
4349 struct msmsdcc_host *host = mmc_priv(mmc);
4350 int rc = 0;
4351
4352 if (host->plat->is_sdio_al_client)
4353 return 0;
4354
Sahitya Tummalafb486372011-09-02 19:01:49 +05304355 if (!pm_runtime_suspended(dev))
4356 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357 if (host->plat->status_irq) {
4358 msmsdcc_check_status((unsigned long)host);
4359 enable_irq(host->plat->status_irq);
4360 }
4361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 return rc;
4363}
4364
Daniel Walker08ecfde2010-06-23 12:32:20 -07004365#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366#define msmsdcc_runtime_suspend NULL
4367#define msmsdcc_runtime_resume NULL
4368#define msmsdcc_runtime_idle NULL
4369#define msmsdcc_pm_suspend NULL
4370#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004371#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004373static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4374 .runtime_suspend = msmsdcc_runtime_suspend,
4375 .runtime_resume = msmsdcc_runtime_resume,
4376 .runtime_idle = msmsdcc_runtime_idle,
4377 .suspend = msmsdcc_pm_suspend,
4378 .resume = msmsdcc_pm_resume,
4379};
4380
San Mehat9d2bd732009-09-22 16:44:22 -07004381static struct platform_driver msmsdcc_driver = {
4382 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004383 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004384 .driver = {
4385 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004386 .pm = &msmsdcc_dev_pm_ops,
San Mehat9d2bd732009-09-22 16:44:22 -07004387 },
4388};
4389
4390static int __init msmsdcc_init(void)
4391{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392#if defined(CONFIG_DEBUG_FS)
4393 int ret = 0;
4394 ret = msmsdcc_dbg_init();
4395 if (ret) {
4396 pr_err("Failed to create debug fs dir \n");
4397 return ret;
4398 }
4399#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004400 return platform_driver_register(&msmsdcc_driver);
4401}
4402
4403static void __exit msmsdcc_exit(void)
4404{
4405 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004406
4407#if defined(CONFIG_DEBUG_FS)
4408 debugfs_remove(debugfs_file);
4409 debugfs_remove(debugfs_dir);
4410#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004411}
4412
4413module_init(msmsdcc_init);
4414module_exit(msmsdcc_exit);
4415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004416MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004417MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004418
4419#if defined(CONFIG_DEBUG_FS)
4420
4421static int
4422msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4423{
4424 file->private_data = inode->i_private;
4425 return 0;
4426}
4427
4428static ssize_t
4429msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4430 size_t count, loff_t *ppos)
4431{
4432 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4433 char buf[1024];
4434 int max, i;
4435
4436 i = 0;
4437 max = sizeof(buf) - 1;
4438
4439 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4440 host->curr.cmd, host->curr.data);
4441 if (host->curr.cmd) {
4442 struct mmc_command *cmd = host->curr.cmd;
4443
4444 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4445 cmd->opcode, cmd->arg, cmd->flags);
4446 }
4447 if (host->curr.data) {
4448 struct mmc_data *data = host->curr.data;
4449 i += scnprintf(buf + i, max - i,
4450 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4451 data->timeout_ns, data->timeout_clks,
4452 data->blksz, data->blocks, data->error,
4453 data->flags);
4454 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4455 host->curr.xfer_size, host->curr.xfer_remain,
4456 host->curr.data_xfered, host->dma.sg);
4457 }
4458
4459 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4460}
4461
4462static const struct file_operations msmsdcc_dbg_state_ops = {
4463 .read = msmsdcc_dbg_state_read,
4464 .open = msmsdcc_dbg_state_open,
4465};
4466
4467static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4468{
4469 if (debugfs_dir) {
4470 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4471 0644, debugfs_dir, host,
4472 &msmsdcc_dbg_state_ops);
4473 }
4474}
4475
4476static int __init msmsdcc_dbg_init(void)
4477{
4478 int err;
4479
4480 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4481 if (IS_ERR(debugfs_dir)) {
4482 err = PTR_ERR(debugfs_dir);
4483 debugfs_dir = NULL;
4484 return err;
4485 }
4486
4487 return 0;
4488}
4489#endif