blob: 612726c439043bde55bbc7a4d4dde5617959b5c7 [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +053022#include <linux/of.h>
San Mehat9d2bd732009-09-22 16:44:22 -070023#include <linux/device.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/irq.h>
San Mehat9d2bd732009-09-22 16:44:22 -070026#include <linux/delay.h>
27#include <linux/err.h>
28#include <linux/highmem.h>
29#include <linux/log2.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/card.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/mmc/mmc.h>
San Mehatb3fa5792009-11-02 18:46:09 -080033#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070034#include <linux/clk.h>
35#include <linux/scatterlist.h>
36#include <linux/platform_device.h>
37#include <linux/dma-mapping.h>
38#include <linux/debugfs.h>
39#include <linux/io.h>
40#include <linux/memory.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/pm_runtime.h>
42#include <linux/wakelock.h>
Sahitya Tummala7a892482011-01-18 11:22:49 +053043#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#include <linux/regulator/consumer.h>
45#include <linux/slab.h>
46#include <linux/mmc/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070047
48#include <asm/cacheflush.h>
49#include <asm/div64.h>
50#include <asm/sizes.h>
51
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#include <asm/mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070053#include <mach/msm_iomap.h>
Sahitya Tummalab08bb352010-12-08 15:03:05 +053054#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#include <mach/dma.h>
56#include <mach/htc_pwrsink.h>
57#include <mach/sdio_al.h>
San Mehat9d2bd732009-09-22 16:44:22 -070058
San Mehat9d2bd732009-09-22 16:44:22 -070059#include "msm_sdcc.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#include "msm_sdcc_dml.h"
San Mehat9d2bd732009-09-22 16:44:22 -070061
62#define DRIVER_NAME "msm-sdcc"
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#define DBG(host, fmt, args...) \
65 pr_debug("%s: %s: " fmt "\n", mmc_hostname(host->mmc), __func__ , args)
66
67#define IRQ_DEBUG 0
68#define SPS_SDCC_PRODUCER_PIPE_INDEX 1
69#define SPS_SDCC_CONSUMER_PIPE_INDEX 2
70#define SPS_CONS_PERIPHERAL 0
71#define SPS_PROD_PERIPHERAL 1
72/* 16 KB */
73#define SPS_MAX_DESC_SIZE (16 * 1024)
74
75#if defined(CONFIG_DEBUG_FS)
76static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
77static struct dentry *debugfs_dir;
78static struct dentry *debugfs_file;
79static int msmsdcc_dbg_init(void);
80#endif
81
San Mehat9d2bd732009-09-22 16:44:22 -070082static unsigned int msmsdcc_pwrsave = 1;
San Mehat9d2bd732009-09-22 16:44:22 -070083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084static struct mmc_command dummy52cmd;
85static struct mmc_request dummy52mrq = {
86 .cmd = &dummy52cmd,
87 .data = NULL,
88 .stop = NULL,
89};
90static struct mmc_command dummy52cmd = {
91 .opcode = SD_IO_RW_DIRECT,
92 .flags = MMC_RSP_PRESENT,
93 .data = NULL,
94 .mrq = &dummy52mrq,
95};
96/*
97 * An array holding the Tuning pattern to compare with when
98 * executing a tuning cycle.
99 */
100static const u32 cmd19_tuning_block[16] = {
101 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
102 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
103 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
104 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
105};
San Mehat865c8062009-11-13 13:42:06 -0800106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107#if IRQ_DEBUG == 1
108static char *irq_status_bits[] = { "cmdcrcfail", "datcrcfail", "cmdtimeout",
109 "dattimeout", "txunderrun", "rxoverrun",
110 "cmdrespend", "cmdsent", "dataend", NULL,
111 "datablkend", "cmdactive", "txactive",
112 "rxactive", "txhalfempty", "rxhalffull",
113 "txfifofull", "rxfifofull", "txfifoempty",
114 "rxfifoempty", "txdataavlbl", "rxdataavlbl",
115 "sdiointr", "progdone", "atacmdcompl",
116 "sdiointrope", "ccstimeout", NULL, NULL,
117 NULL, NULL, NULL };
118
119static void
120msmsdcc_print_status(struct msmsdcc_host *host, char *hdr, uint32_t status)
San Mehat865c8062009-11-13 13:42:06 -0800121{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 int i;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 pr_debug("%s-%s ", mmc_hostname(host->mmc), hdr);
125 for (i = 0; i < 32; i++) {
126 if (status & (1 << i))
127 pr_debug("%s ", irq_status_bits[i]);
San Mehat865c8062009-11-13 13:42:06 -0800128 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 pr_debug("\n");
San Mehatc7fc9372009-11-22 17:19:07 -0800130}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131#endif
San Mehat865c8062009-11-13 13:42:06 -0800132
San Mehat9d2bd732009-09-22 16:44:22 -0700133static void
134msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
135 u32 c);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530136static inline void msmsdcc_delay(struct msmsdcc_host *host);
137
San Mehat9d2bd732009-09-22 16:44:22 -0700138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
140static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
141 struct msmsdcc_sps_ep_conn_data *ep);
142static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
143 struct msmsdcc_sps_ep_conn_data *ep);
144#else
145static inline int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
146 struct msmsdcc_sps_ep_conn_data *ep,
147 bool is_producer) { return 0; }
148static inline void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
149 struct msmsdcc_sps_ep_conn_data *ep) { }
150static inline int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
151 struct msmsdcc_sps_ep_conn_data *ep)
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530152{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 return 0;
154}
155static inline int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
156 struct msmsdcc_sps_ep_conn_data *ep)
157{
158 return 0;
159}
160static inline int msmsdcc_sps_init(struct msmsdcc_host *host) { return 0; }
161static inline void msmsdcc_sps_exit(struct msmsdcc_host *host) {}
162#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164/**
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530165 * Apply soft reset to all SDCC BAM pipes
166 *
167 * This function applies soft reset to SDCC BAM pipe.
168 *
169 * This function should be called to recover from error
170 * conditions encountered during CMD/DATA tranfsers with card.
171 *
172 * @host - Pointer to driver's host structure
173 *
174 */
175static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
176{
177 int rc;
178
179 /* Reset all SDCC BAM pipes */
180 rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
181 if (rc)
182 pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
183 mmc_hostname(host->mmc), rc);
184 rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
185 if (rc)
186 pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
187 mmc_hostname(host->mmc), rc);
188
189 /* Restore all BAM pipes connections */
190 rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
191 if (rc)
192 pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
193 mmc_hostname(host->mmc), rc);
194 rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
195 if (rc)
196 pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
197 mmc_hostname(host->mmc), rc);
198}
199
200/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 * Apply soft reset
202 *
Subhash Jadavanib5b07742011-08-29 17:48:07 +0530203 * This function applies soft reset to SDCC core and DML core.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 *
205 * This function should be called to recover from error
206 * conditions encountered with CMD/DATA tranfsers with card.
207 *
208 * Soft reset should only be used with SDCC controller v4.
209 *
210 * @host - Pointer to driver's host structure
211 *
212 */
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530213static void msmsdcc_soft_reset(struct msmsdcc_host *host)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 /*
216 * Reset SDCC controller's DPSM (data path state machine
217 * and CPSM (command path state machine).
218 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 writel_relaxed(0, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530220 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 writel_relaxed(0, host->base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530222 msmsdcc_delay(host);
223}
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530224
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530225static void msmsdcc_hard_reset(struct msmsdcc_host *host)
226{
227 int ret;
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530228
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530229 /* Reset the controller */
230 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
231 if (ret)
232 pr_err("%s: Clock assert failed at %u Hz"
233 " with err %d\n", mmc_hostname(host->mmc),
234 host->clk_rate, ret);
235
236 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
237 if (ret)
238 pr_err("%s: Clock deassert failed at %u Hz"
239 " with err %d\n", mmc_hostname(host->mmc),
240 host->clk_rate, ret);
241
242 /* Give some delay for clock reset to propogate to controller */
243 msmsdcc_delay(host);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530244}
245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
247{
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530248 if (host->sdcc_version) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530249 if (host->is_sps_mode) {
250 /* Reset DML first */
251 msmsdcc_dml_reset(host);
252 /*
253 * delay the SPS pipe reset in thread context as
254 * sps_connect/sps_disconnect APIs can be called
255 * only from non-atomic context.
256 */
257 host->sps.pipe_reset_pending = true;
258 }
259 mb();
260 msmsdcc_soft_reset(host);
261
262 pr_debug("%s: Applied soft reset to Controller\n",
263 mmc_hostname(host->mmc));
264
265 if (host->is_sps_mode)
266 msmsdcc_dml_init(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 } else {
268 /* Give Clock reset (hard reset) to controller */
269 u32 mci_clk = 0;
270 u32 mci_mask0 = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271
272 /* Save the controller state */
273 mci_clk = readl_relaxed(host->base + MMCICLOCK);
274 mci_mask0 = readl_relaxed(host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530277 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 pr_debug("%s: Controller has been reinitialized\n",
279 mmc_hostname(host->mmc));
280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 /* Restore the contoller state */
282 writel_relaxed(host->pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530283 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 writel_relaxed(mci_clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530285 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 writel_relaxed(mci_mask0, host->base + MMCIMASK0);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530287 mb(); /* no delay required after writing to MASK0 register */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530289
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700290 if (host->dummy_52_needed)
291 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292}
293
294static int
San Mehat9d2bd732009-09-22 16:44:22 -0700295msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
296{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 int retval = 0;
298
San Mehat9d2bd732009-09-22 16:44:22 -0700299 BUG_ON(host->curr.data);
300
301 host->curr.mrq = NULL;
302 host->curr.cmd = NULL;
303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 del_timer(&host->req_tout_timer);
305
San Mehat9d2bd732009-09-22 16:44:22 -0700306 if (mrq->data)
307 mrq->data->bytes_xfered = host->curr.data_xfered;
308 if (mrq->cmd->error == -ETIMEDOUT)
309 mdelay(5);
310
311 /*
312 * Need to drop the host lock here; mmc_request_done may call
313 * back into the driver...
314 */
315 spin_unlock(&host->lock);
316 mmc_request_done(host->mmc, mrq);
317 spin_lock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318
319 return retval;
San Mehat9d2bd732009-09-22 16:44:22 -0700320}
321
322static void
323msmsdcc_stop_data(struct msmsdcc_host *host)
324{
San Mehat9d2bd732009-09-22 16:44:22 -0700325 host->curr.data = NULL;
Sahitya Tummala0c521cc2010-12-08 15:03:07 +0530326 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530327 host->curr.wait_for_auto_prog_done = 0;
328 host->curr.got_auto_prog_done = 0;
Krishna Konda3f5d48f2011-07-27 10:47:31 -0700329 writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
330 (~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
Krishna Konda3e5c4d02011-07-11 16:31:45 -0700331 msmsdcc_delay(host); /* Allow the DPSM to be reset */
San Mehat9d2bd732009-09-22 16:44:22 -0700332}
333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334static inline uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
San Mehat9d2bd732009-09-22 16:44:22 -0700335{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 return host->core_memres->start + MMCIFIFO;
337}
338
339static inline unsigned int msmsdcc_get_min_sup_clk_rate(
340 struct msmsdcc_host *host);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342static inline void msmsdcc_delay(struct msmsdcc_host *host)
343{
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530344 ktime_t start, diff;
345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 mb();
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +0530347 udelay(host->reg_write_delay);
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530348
Pratibhasagar V1c11da62011-11-14 12:36:35 +0530349 if (host->sdcc_version &&
Subhash Jadavani8f13e5b2011-08-04 21:15:11 +0530350 (readl_relaxed(host->base + MCI_STATUS2) &
351 MCI_MCLK_REG_WR_ACTIVE)) {
352 start = ktime_get();
353 while (readl_relaxed(host->base + MCI_STATUS2) &
354 MCI_MCLK_REG_WR_ACTIVE) {
355 diff = ktime_sub(ktime_get(), start);
356 /* poll for max. 1 ms */
357 if (ktime_to_us(diff) > 1000) {
358 pr_warning("%s: previous reg. write is"
359 " still active\n",
360 mmc_hostname(host->mmc));
361 break;
362 }
363 }
364 }
San Mehat9d2bd732009-09-22 16:44:22 -0700365}
366
San Mehat56a8b5b2009-11-21 12:29:46 -0800367static inline void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c)
369{
370 writel_relaxed(arg, host->base + MMCIARGUMENT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 writel_relaxed(c, host->base + MMCICOMMAND);
Subhash Jadavani15f29db2011-10-13 09:57:13 +0530372 /*
373 * As after sending the command, we don't write any of the
374 * controller registers and just wait for the
375 * CMD_RESPOND_END/CMD_SENT/Command failure notication
376 * from Controller.
377 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -0800379}
380
381static void
382msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
383{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->user;
San Mehat56a8b5b2009-11-21 12:29:46 -0800385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 writel_relaxed(host->cmd_timeout, host->base + MMCIDATATIMER);
387 writel_relaxed((unsigned int)host->curr.xfer_size,
388 host->base + MMCIDATALENGTH);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 writel_relaxed(host->cmd_datactrl, host->base + MMCIDATACTRL);
390 msmsdcc_delay(host); /* Force delay prior to ADM or command */
San Mehat56a8b5b2009-11-21 12:29:46 -0800391
San Mehat6ac9ea62009-12-02 17:24:58 -0800392 if (host->cmd_cmd) {
393 msmsdcc_start_command_exec(host,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
San Mehat6ac9ea62009-12-02 17:24:58 -0800395 }
San Mehat56a8b5b2009-11-21 12:29:46 -0800396}
397
San Mehat9d2bd732009-09-22 16:44:22 -0700398static void
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530399msmsdcc_dma_complete_tlet(unsigned long data)
San Mehat9d2bd732009-09-22 16:44:22 -0700400{
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530401 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
San Mehat9d2bd732009-09-22 16:44:22 -0700402 unsigned long flags;
403 struct mmc_request *mrq;
404
405 spin_lock_irqsave(&host->lock, flags);
406 mrq = host->curr.mrq;
407 BUG_ON(!mrq);
408
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530409 if (!(host->dma.result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700410 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700411 goto out;
412 }
413
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530414 if (host->dma.result & DMOV_RSLT_DONE) {
San Mehat9d2bd732009-09-22 16:44:22 -0700415 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 host->curr.xfer_remain -= host->curr.xfer_size;
San Mehat9d2bd732009-09-22 16:44:22 -0700417 } else {
418 /* Error or flush */
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530419 if (host->dma.result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700420 pr_err("%s: DMA error (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530421 mmc_hostname(host->mmc), host->dma.result);
422 if (host->dma.result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700423 pr_err("%s: DMA channel flushed (0x%.8x)\n",
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530424 mmc_hostname(host->mmc), host->dma.result);
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530425 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 host->dma.err.flush[0], host->dma.err.flush[1],
427 host->dma.err.flush[2], host->dma.err.flush[3],
428 host->dma.err.flush[4],
429 host->dma.err.flush[5]);
Sahitya Tummalab08bb352010-12-08 15:03:05 +0530430 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -0700431 if (!mrq->data->error)
432 mrq->data->error = -EIO;
433 }
San Mehat9d2bd732009-09-22 16:44:22 -0700434 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
435 host->dma.dir);
436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 if (host->curr.user_pages) {
438 struct scatterlist *sg = host->dma.sg;
439 int i;
440
441 for (i = 0; i < host->dma.num_ents; i++, sg++)
442 flush_dcache_page(sg_page(sg));
443 }
444
San Mehat9d2bd732009-09-22 16:44:22 -0700445 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800446 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700447
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530448 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
449 (host->curr.wait_for_auto_prog_done &&
450 host->curr.got_auto_prog_done))) || mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700451 /*
452 * If we've already gotten our DATAEND / DATABLKEND
453 * for this request, then complete it through here.
454 */
San Mehat9d2bd732009-09-22 16:44:22 -0700455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700456 if (!mrq->data->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700457 host->curr.data_xfered = host->curr.xfer_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 host->curr.xfer_remain -= host->curr.xfer_size;
459 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700460 if (host->dummy_52_needed) {
461 mrq->data->bytes_xfered = host->curr.data_xfered;
462 host->dummy_52_sent = 1;
463 msmsdcc_start_command(host, &dummy52cmd,
464 MCI_CPSM_PROGENA);
465 goto out;
466 }
467 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530468 if (!mrq->data->stop || mrq->cmd->error ||
469 (mrq->sbc && !mrq->data->error)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700470 host->curr.mrq = NULL;
471 host->curr.cmd = NULL;
472 mrq->data->bytes_xfered = host->curr.data_xfered;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 del_timer(&host->req_tout_timer);
San Mehat9d2bd732009-09-22 16:44:22 -0700474 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475
San Mehat9d2bd732009-09-22 16:44:22 -0700476 mmc_request_done(host->mmc, mrq);
477 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530478 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
479 || !mrq->sbc)) {
San Mehat9d2bd732009-09-22 16:44:22 -0700480 msmsdcc_start_command(host, mrq->data->stop, 0);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530481 }
San Mehat9d2bd732009-09-22 16:44:22 -0700482 }
483
484out:
485 spin_unlock_irqrestore(&host->lock, flags);
486 return;
487}
488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
490/**
491 * Callback notification from SPS driver
492 *
493 * This callback function gets triggered called from
494 * SPS driver when requested SPS data transfer is
495 * completed.
496 *
497 * SPS driver invokes this callback in BAM irq context so
498 * SDCC driver schedule a tasklet for further processing
499 * this callback notification at later point of time in
500 * tasklet context and immediately returns control back
501 * to SPS driver.
502 *
503 * @nofity - Pointer to sps event notify sturcture
504 *
505 */
506static void
507msmsdcc_sps_complete_cb(struct sps_event_notify *notify)
508{
509 struct msmsdcc_host *host =
510 (struct msmsdcc_host *)
511 ((struct sps_event_notify *)notify)->user;
512
513 host->sps.notify = *notify;
514 pr_debug("%s: %s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
515 mmc_hostname(host->mmc), __func__, notify->event_id,
516 notify->data.transfer.iovec.addr,
517 notify->data.transfer.iovec.size,
518 notify->data.transfer.iovec.flags);
519 /* Schedule a tasklet for completing data transfer */
520 tasklet_schedule(&host->sps.tlet);
521}
522
523/**
524 * Tasklet handler for processing SPS callback event
525 *
526 * This function processing SPS event notification and
527 * checks if the SPS transfer is completed or not and
528 * then accordingly notifies status to MMC core layer.
529 *
530 * This function is called in tasklet context.
531 *
532 * @data - Pointer to sdcc driver data
533 *
534 */
535static void msmsdcc_sps_complete_tlet(unsigned long data)
536{
537 unsigned long flags;
538 int i, rc;
539 u32 data_xfered = 0;
540 struct mmc_request *mrq;
541 struct sps_iovec iovec;
542 struct sps_pipe *sps_pipe_handle;
543 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
544 struct sps_event_notify *notify = &host->sps.notify;
545
546 spin_lock_irqsave(&host->lock, flags);
547 if (host->sps.dir == DMA_FROM_DEVICE)
548 sps_pipe_handle = host->sps.prod.pipe_handle;
549 else
550 sps_pipe_handle = host->sps.cons.pipe_handle;
551 mrq = host->curr.mrq;
552
553 if (!mrq) {
554 spin_unlock_irqrestore(&host->lock, flags);
555 return;
556 }
557
558 pr_debug("%s: %s: sps event_id=%d\n",
559 mmc_hostname(host->mmc), __func__,
560 notify->event_id);
561
562 if (msmsdcc_is_dml_busy(host)) {
563 /* oops !!! this should never happen. */
564 pr_err("%s: %s: Received SPS EOT event"
565 " but DML HW is still busy !!!\n",
566 mmc_hostname(host->mmc), __func__);
567 }
568 /*
569 * Got End of transfer event!!! Check if all of the data
570 * has been transferred?
571 */
572 for (i = 0; i < host->sps.xfer_req_cnt; i++) {
573 rc = sps_get_iovec(sps_pipe_handle, &iovec);
574 if (rc) {
575 pr_err("%s: %s: sps_get_iovec() failed rc=%d, i=%d",
576 mmc_hostname(host->mmc), __func__, rc, i);
577 break;
578 }
579 data_xfered += iovec.size;
580 }
581
582 if (data_xfered == host->curr.xfer_size) {
583 host->curr.data_xfered = host->curr.xfer_size;
584 host->curr.xfer_remain -= host->curr.xfer_size;
585 pr_debug("%s: Data xfer success. data_xfered=0x%x",
586 mmc_hostname(host->mmc),
587 host->curr.xfer_size);
588 } else {
589 pr_err("%s: Data xfer failed. data_xfered=0x%x,"
590 " xfer_size=%d", mmc_hostname(host->mmc),
591 data_xfered, host->curr.xfer_size);
592 msmsdcc_reset_and_restore(host);
593 if (!mrq->data->error)
594 mrq->data->error = -EIO;
595 }
596
597 /* Unmap sg buffers */
598 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
599 host->sps.dir);
600
601 host->sps.sg = NULL;
602 host->sps.busy = 0;
603
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530604 if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
605 (host->curr.wait_for_auto_prog_done &&
606 host->curr.got_auto_prog_done))) || mrq->data->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 /*
608 * If we've already gotten our DATAEND / DATABLKEND
609 * for this request, then complete it through here.
610 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611
612 if (!mrq->data->error) {
613 host->curr.data_xfered = host->curr.xfer_size;
614 host->curr.xfer_remain -= host->curr.xfer_size;
615 }
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700616 if (host->dummy_52_needed) {
617 mrq->data->bytes_xfered = host->curr.data_xfered;
618 host->dummy_52_sent = 1;
619 msmsdcc_start_command(host, &dummy52cmd,
620 MCI_CPSM_PROGENA);
Jeff Ohlstein5e48f242011-11-01 14:59:48 -0700621 spin_unlock_irqrestore(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -0700622 return;
623 }
624 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530625 if (!mrq->data->stop || mrq->cmd->error ||
626 (mrq->sbc && !mrq->data->error)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 host->curr.mrq = NULL;
628 host->curr.cmd = NULL;
629 mrq->data->bytes_xfered = host->curr.data_xfered;
630 del_timer(&host->req_tout_timer);
631 spin_unlock_irqrestore(&host->lock, flags);
632
633 mmc_request_done(host->mmc, mrq);
634 return;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530635 } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
636 || !mrq->sbc)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 msmsdcc_start_command(host, mrq->data->stop, 0);
638 }
639 }
640 spin_unlock_irqrestore(&host->lock, flags);
641}
642
643/**
644 * Exit from current SPS data transfer
645 *
646 * This function exits from current SPS data transfer.
647 *
648 * This function should be called when error condition
649 * is encountered during data transfer.
650 *
651 * @host - Pointer to sdcc host structure
652 *
653 */
654static void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host)
655{
656 struct mmc_request *mrq;
657
658 mrq = host->curr.mrq;
659 BUG_ON(!mrq);
660
661 msmsdcc_reset_and_restore(host);
662 if (!mrq->data->error)
663 mrq->data->error = -EIO;
664
665 /* Unmap sg buffers */
666 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
667 host->sps.dir);
668
669 host->sps.sg = NULL;
670 host->sps.busy = 0;
671 if (host->curr.data)
672 msmsdcc_stop_data(host);
673
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530674 if (!mrq->data->stop || mrq->cmd->error ||
675 (mrq->sbc && !mrq->data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700676 msmsdcc_request_end(host, mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +0530677 else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
678 || !mrq->sbc))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 msmsdcc_start_command(host, mrq->data->stop, 0);
680
681}
682#else
683static inline void msmsdcc_sps_complete_cb(struct sps_event_notify *notify) { }
684static inline void msmsdcc_sps_complete_tlet(unsigned long data) { }
685static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
686#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
687
688static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
689
Sahitya Tummala62612cf2010-12-08 15:03:03 +0530690static void
691msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
692 unsigned int result,
693 struct msm_dmov_errdata *err)
694{
695 struct msmsdcc_dma_data *dma_data =
696 container_of(cmd, struct msmsdcc_dma_data, hdr);
697 struct msmsdcc_host *host = dma_data->host;
698
699 dma_data->result = result;
700 if (err)
701 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
702
703 tasklet_schedule(&host->dma_tlet);
704}
705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706static int msmsdcc_check_dma_op_req(struct mmc_data *data)
San Mehat9d2bd732009-09-22 16:44:22 -0700707{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 if (((data->blksz * data->blocks) < MCI_FIFOSIZE) ||
709 ((data->blksz * data->blocks) % MCI_FIFOSIZE))
San Mehat9d2bd732009-09-22 16:44:22 -0700710 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 else
712 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700713}
714
715static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
716{
717 struct msmsdcc_nc_dmadata *nc;
718 dmov_box *box;
719 uint32_t rows;
San Mehat9d2bd732009-09-22 16:44:22 -0700720 unsigned int n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 int i;
San Mehat9d2bd732009-09-22 16:44:22 -0700722 struct scatterlist *sg = data->sg;
723
Krishna Konda25786ec2011-07-25 16:21:36 -0700724 if ((host->dma.channel == -1) || (host->dma.crci == -1))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 return -ENOENT;
San Mehat9d2bd732009-09-22 16:44:22 -0700726
Krishna Konda25786ec2011-07-25 16:21:36 -0700727 BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
728
San Mehat9d2bd732009-09-22 16:44:22 -0700729 host->dma.sg = data->sg;
730 host->dma.num_ents = data->sg_len;
731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
San Mehat56a8b5b2009-11-21 12:29:46 -0800733
San Mehat9d2bd732009-09-22 16:44:22 -0700734 nc = host->dma.nc;
735
San Mehat9d2bd732009-09-22 16:44:22 -0700736 if (data->flags & MMC_DATA_READ)
737 host->dma.dir = DMA_FROM_DEVICE;
738 else
739 host->dma.dir = DMA_TO_DEVICE;
740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
San Mehat9d2bd732009-09-22 16:44:22 -0700742 host->curr.user_pages = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700743 box = &nc->cmd[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 for (i = 0; i < host->dma.num_ents; i++) {
San Mehat9d2bd732009-09-22 16:44:22 -0700745 box->cmd = CMD_MODE_BOX;
746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747 /* Initialize sg dma address */
748 sg->dma_address = pfn_to_dma(mmc_dev(host->mmc),
749 page_to_pfn(sg_page(sg)))
750 + sg->offset;
751
752 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700753 box->cmd |= CMD_LC;
754 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
755 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
756 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
757
758 if (data->flags & MMC_DATA_READ) {
759 box->src_row_addr = msmsdcc_fifo_addr(host);
760 box->dst_row_addr = sg_dma_address(sg);
761
762 box->src_dst_len = (MCI_FIFOSIZE << 16) |
763 (MCI_FIFOSIZE);
764 box->row_offset = MCI_FIFOSIZE;
765
766 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700767 box->cmd |= CMD_SRC_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700768 } else {
769 box->src_row_addr = sg_dma_address(sg);
770 box->dst_row_addr = msmsdcc_fifo_addr(host);
771
772 box->src_dst_len = (MCI_FIFOSIZE << 16) |
773 (MCI_FIFOSIZE);
774 box->row_offset = (MCI_FIFOSIZE << 16);
775
776 box->num_rows = rows * ((1 << 16) + 1);
Krishna Konda25786ec2011-07-25 16:21:36 -0700777 box->cmd |= CMD_DST_CRCI(host->dma.crci);
San Mehat9d2bd732009-09-22 16:44:22 -0700778 }
779 box++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 sg++;
781 }
782
783 /* location of command block must be 64 bit aligned */
784 BUG_ON(host->dma.cmd_busaddr & 0x07);
785
786 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
787 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
788 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
789 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790
791 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
792 host->dma.num_ents, host->dma.dir);
793 /* dsb inside dma_map_sg will write nc out to mem as well */
794
795 if (n != host->dma.num_ents) {
796 pr_err("%s: Unable to map in all sg elements\n",
797 mmc_hostname(host->mmc));
798 host->dma.sg = NULL;
799 host->dma.num_ents = 0;
800 return -ENOMEM;
San Mehat56a8b5b2009-11-21 12:29:46 -0800801 }
San Mehat9d2bd732009-09-22 16:44:22 -0700802
803 return 0;
804}
805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
807/**
808 * Submits data transfer request to SPS driver
809 *
810 * This function make sg (scatter gather) data buffers
811 * DMA ready and then submits them to SPS driver for
812 * transfer.
813 *
814 * @host - Pointer to sdcc host structure
815 * @data - Pointer to mmc_data structure
816 *
817 * @return 0 if success else negative value
818 */
819static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
820 struct mmc_data *data)
San Mehat56a8b5b2009-11-21 12:29:46 -0800821{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 int rc = 0;
823 u32 flags;
824 int i;
825 u32 addr, len, data_cnt;
826 struct scatterlist *sg = data->sg;
827 struct sps_pipe *sps_pipe_handle;
828
829 BUG_ON(data->sg_len > NR_SG); /* Prevent memory corruption */
830
831 host->sps.sg = data->sg;
832 host->sps.num_ents = data->sg_len;
833 host->sps.xfer_req_cnt = 0;
834 if (data->flags & MMC_DATA_READ) {
835 host->sps.dir = DMA_FROM_DEVICE;
836 sps_pipe_handle = host->sps.prod.pipe_handle;
837 } else {
838 host->sps.dir = DMA_TO_DEVICE;
839 sps_pipe_handle = host->sps.cons.pipe_handle;
840 }
841
842 /* Make sg buffers DMA ready */
843 rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
844 host->sps.dir);
845
846 if (rc != data->sg_len) {
847 pr_err("%s: Unable to map in all sg elements, rc=%d\n",
848 mmc_hostname(host->mmc), rc);
849 host->sps.sg = NULL;
850 host->sps.num_ents = 0;
851 rc = -ENOMEM;
852 goto dma_map_err;
853 }
854
855 pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
856 mmc_hostname(host->mmc), __func__,
857 host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
858 (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
859
860 for (i = 0; i < data->sg_len; i++) {
861 /*
862 * Check if this is the last buffer to transfer?
863 * If yes then set the INT and EOT flags.
864 */
865 len = sg_dma_len(sg);
866 addr = sg_dma_address(sg);
867 flags = 0;
868 while (len > 0) {
869 if (len > SPS_MAX_DESC_SIZE) {
870 data_cnt = SPS_MAX_DESC_SIZE;
871 } else {
872 data_cnt = len;
873 if (i == data->sg_len - 1)
874 flags = SPS_IOVEC_FLAG_INT |
875 SPS_IOVEC_FLAG_EOT;
876 }
877 rc = sps_transfer_one(sps_pipe_handle, addr,
878 data_cnt, host, flags);
879 if (rc) {
880 pr_err("%s: sps_transfer_one() error! rc=%d,"
881 " pipe=0x%x, sg=0x%x, sg_buf_no=%d\n",
882 mmc_hostname(host->mmc), rc,
883 (u32)sps_pipe_handle, (u32)sg, i);
884 goto dma_map_err;
885 }
886 addr += data_cnt;
887 len -= data_cnt;
888 host->sps.xfer_req_cnt++;
889 }
890 sg++;
891 }
892 goto out;
893
894dma_map_err:
895 /* unmap sg buffers */
896 dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
897 host->sps.dir);
898out:
899 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -0700900}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901#else
902static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
903 struct mmc_data *data) { return 0; }
904#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
San Mehat9d2bd732009-09-22 16:44:22 -0700905
906static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800907msmsdcc_start_command_deferred(struct msmsdcc_host *host,
908 struct mmc_command *cmd, u32 *c)
909{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 DBG(host, "op %02x arg %08x flags %08x\n",
911 cmd->opcode, cmd->arg, cmd->flags);
912
San Mehat56a8b5b2009-11-21 12:29:46 -0800913 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
914
915 if (cmd->flags & MMC_RSP_PRESENT) {
916 if (cmd->flags & MMC_RSP_136)
917 *c |= MCI_CPSM_LONGRSP;
918 *c |= MCI_CPSM_RESPONSE;
919 }
920
921 if (/*interrupt*/0)
922 *c |= MCI_CPSM_INTERRUPT;
923
924 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
925 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
926 (cmd->opcode == 53))
927 *c |= MCI_CSPM_DATCMD;
928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929 /* Check if AUTO CMD19 is required or not? */
Subhash Jadavani1d6ba602011-09-21 18:10:54 +0530930 if (host->tuning_needed) {
931 /*
932 * For open ended block read operation (without CMD23),
933 * AUTO_CMD19 bit should be set while sending the READ command.
934 * For close ended block read operation (with CMD23),
935 * AUTO_CMD19 bit should be set while sending CMD23.
936 */
937 if ((cmd->opcode == 23 && (host->curr.mrq->cmd->opcode == 17 ||
938 host->curr.mrq->cmd->opcode == 18)) ||
939 (!host->curr.mrq->sbc &&
940 (cmd->opcode == 17 || cmd->opcode == 18))) {
941 msmsdcc_enable_cdr_cm_sdc4_dll(host);
942 *c |= MCI_CSPM_AUTO_CMD19;
943 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 }
945
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +0530946 if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530947 *c |= MCI_CPSM_PROGENA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 host->prog_enable = 1;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +0530949 }
950
San Mehat56a8b5b2009-11-21 12:29:46 -0800951 if (cmd == cmd->mrq->stop)
952 *c |= MCI_CSPM_MCIABORT;
953
San Mehat56a8b5b2009-11-21 12:29:46 -0800954 if (host->curr.cmd != NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955 pr_err("%s: Overlapping command requests\n",
956 mmc_hostname(host->mmc));
San Mehat56a8b5b2009-11-21 12:29:46 -0800957 }
958 host->curr.cmd = cmd;
959}
960
961static void
962msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
963 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700964{
Subhash Jadavani24fb7f82011-07-25 15:54:34 +0530965 unsigned int datactrl = 0, timeout;
San Mehat9d2bd732009-09-22 16:44:22 -0700966 unsigned long long clks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -0700968 unsigned int pio_irqmask = 0;
969
Subhash Jadavani7d572f12011-11-13 13:09:36 +0530970 BUG_ON(!data->sg);
971 BUG_ON(!data->sg_len);
972
San Mehat9d2bd732009-09-22 16:44:22 -0700973 host->curr.data = data;
974 host->curr.xfer_size = data->blksz * data->blocks;
975 host->curr.xfer_remain = host->curr.xfer_size;
976 host->curr.data_xfered = 0;
977 host->curr.got_dataend = 0;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530978 host->curr.got_auto_prog_done = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700979
980 memset(&host->pio, 0, sizeof(host->pio));
981
San Mehat9d2bd732009-09-22 16:44:22 -0700982 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
983
Subhash Jadavani7a651aa2011-08-03 20:44:58 +0530984 if (host->curr.wait_for_auto_prog_done)
985 datactrl |= MCI_AUTO_PROG_DONE;
986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 if (!msmsdcc_check_dma_op_req(data)) {
988 if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
989 datactrl |= MCI_DPSM_DMAENABLE;
990 } else if (host->is_sps_mode) {
991 if (!msmsdcc_is_dml_busy(host)) {
992 if (!msmsdcc_sps_start_xfer(host, data)) {
993 /* Now kick start DML transfer */
994 mb();
995 msmsdcc_dml_start_xfer(host, data);
996 datactrl |= MCI_DPSM_DMAENABLE;
997 host->sps.busy = 1;
998 }
999 } else {
1000 /*
1001 * Can't proceed with new transfer as
1002 * previous trasnfer is already in progress.
1003 * There is no point of going into PIO mode
1004 * as well. Is this a time to do kernel panic?
1005 */
1006 pr_err("%s: %s: DML HW is busy!!!"
1007 " Can't perform new SPS transfers"
1008 " now\n", mmc_hostname(host->mmc),
1009 __func__);
1010 }
1011 }
1012 }
1013
1014 /* Is data transfer in PIO mode required? */
1015 if (!(datactrl & MCI_DPSM_DMAENABLE)) {
San Mehat9d2bd732009-09-22 16:44:22 -07001016 host->pio.sg = data->sg;
1017 host->pio.sg_len = data->sg_len;
1018 host->pio.sg_off = 0;
1019
1020 if (data->flags & MMC_DATA_READ) {
1021 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
1022 if (host->curr.xfer_remain < MCI_FIFOSIZE)
1023 pio_irqmask |= MCI_RXDATAAVLBLMASK;
1024 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
1026 MCI_TXFIFOEMPTYMASK;
San Mehat9d2bd732009-09-22 16:44:22 -07001027 }
1028
1029 if (data->flags & MMC_DATA_READ)
Subhash Jadavani24fb7f82011-07-25 15:54:34 +05301030 datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
San Mehat9d2bd732009-09-22 16:44:22 -07001031
San Mehat56a8b5b2009-11-21 12:29:46 -08001032 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 do_div(clks, 1000000000UL);
San Mehat56a8b5b2009-11-21 12:29:46 -08001034 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -07001035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
1037 /* Use ADM (Application Data Mover) HW for Data transfer */
1038 /* Save parameters for the dma exec function */
San Mehat56a8b5b2009-11-21 12:29:46 -08001039 host->cmd_timeout = timeout;
1040 host->cmd_pio_irqmask = pio_irqmask;
1041 host->cmd_datactrl = datactrl;
1042 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 host->dma.hdr.exec_func = msmsdcc_dma_exec_func;
1045 host->dma.hdr.user = (void *)host;
San Mehat9d2bd732009-09-22 16:44:22 -07001046 host->dma.busy = 1;
San Mehat56a8b5b2009-11-21 12:29:46 -08001047
1048 if (cmd) {
1049 msmsdcc_start_command_deferred(host, cmd, &c);
1050 host->cmd_c = c;
1051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1053 (~(MCI_IRQ_PIO))) | host->cmd_pio_irqmask,
1054 host->base + MMCIMASK0);
1055 mb();
1056 msm_dmov_enqueue_cmd_ext(host->dma.channel, &host->dma.hdr);
San Mehat56a8b5b2009-11-21 12:29:46 -08001057 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 /* SPS-BAM mode or PIO mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 writel_relaxed(timeout, base + MMCIDATATIMER);
San Mehat56a8b5b2009-11-21 12:29:46 -08001060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 writel_relaxed(host->curr.xfer_size, base + MMCIDATALENGTH);
San Mehat56a8b5b2009-11-21 12:29:46 -08001062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1064 (~(MCI_IRQ_PIO))) | pio_irqmask,
1065 host->base + MMCIMASK0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 writel_relaxed(datactrl, base + MMCIDATACTRL);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301067 /*
1068 * We don't need delay after writing to DATA_CTRL register
1069 * if we are not writing to CMD register immediately after
1070 * this. As we already have delay before sending the
1071 * command, we just need mb() here.
1072 */
1073 mb();
San Mehat56a8b5b2009-11-21 12:29:46 -08001074
1075 if (cmd) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 msmsdcc_delay(host); /* Delay between data/command */
San Mehat56a8b5b2009-11-21 12:29:46 -08001077 /* Daisy-chain the command if requested */
1078 msmsdcc_start_command(host, cmd, c);
1079 }
San Mehat9d2bd732009-09-22 16:44:22 -07001080 }
1081}
1082
1083static void
1084msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
1085{
San Mehat56a8b5b2009-11-21 12:29:46 -08001086 msmsdcc_start_command_deferred(host, cmd, &c);
1087 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -07001088}
1089
1090static void
1091msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
1092 unsigned int status)
1093{
1094 if (status & MCI_DATACRCFAIL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1096 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1097 pr_err("%s: Data CRC error\n",
1098 mmc_hostname(host->mmc));
1099 pr_err("%s: opcode 0x%.8x\n", __func__,
1100 data->mrq->cmd->opcode);
1101 pr_err("%s: blksz %d, blocks %d\n", __func__,
1102 data->blksz, data->blocks);
1103 data->error = -EILSEQ;
1104 }
San Mehat9d2bd732009-09-22 16:44:22 -07001105 } else if (status & MCI_DATATIMEOUT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 /* CRC is optional for the bus test commands, not all
1107 * cards respond back with CRC. However controller
1108 * waits for the CRC and times out. Hence ignore the
1109 * data timeouts during the Bustest.
1110 */
1111 if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
1112 || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
1113 pr_err("%s: Data timeout\n",
1114 mmc_hostname(host->mmc));
1115 data->error = -ETIMEDOUT;
1116 }
San Mehat9d2bd732009-09-22 16:44:22 -07001117 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001118 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001119 data->error = -EIO;
1120 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001121 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001122 data->error = -EIO;
1123 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001124 pr_err("%s: Unknown error (0x%.8x)\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -07001126 data->error = -EIO;
1127 }
San Mehat9d2bd732009-09-22 16:44:22 -07001128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 /* Dummy CMD52 is not needed when CMD53 has errors */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001130 if (host->dummy_52_needed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131 host->dummy_52_needed = 0;
1132}
San Mehat9d2bd732009-09-22 16:44:22 -07001133
1134static int
1135msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
1136{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001138 uint32_t *ptr = (uint32_t *) buffer;
1139 int count = 0;
1140
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301141 if (remain % 4)
1142 remain = ((remain >> 2) + 1) << 2;
1143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 while (readl_relaxed(base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1145
1146 *ptr = readl_relaxed(base + MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -07001147 ptr++;
1148 count += sizeof(uint32_t);
1149
1150 remain -= sizeof(uint32_t);
1151 if (remain == 0)
1152 break;
1153 }
1154 return count;
1155}
1156
1157static int
1158msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 unsigned int remain)
San Mehat9d2bd732009-09-22 16:44:22 -07001160{
1161 void __iomem *base = host->base;
1162 char *ptr = buffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163 unsigned int maxcnt = MCI_FIFOHALFSIZE;
San Mehat9d2bd732009-09-22 16:44:22 -07001164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 while (readl_relaxed(base + MMCISTATUS) &
1166 (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY)) {
1167 unsigned int count, sz;
San Mehat9d2bd732009-09-22 16:44:22 -07001168
San Mehat9d2bd732009-09-22 16:44:22 -07001169 count = min(remain, maxcnt);
1170
Sahitya Tummala71dd9102010-12-08 15:03:06 +05301171 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
1172 writesl(base + MMCIFIFO, ptr, sz);
San Mehat9d2bd732009-09-22 16:44:22 -07001173 ptr += count;
1174 remain -= count;
1175
1176 if (remain == 0)
1177 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 }
1179 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07001180
1181 return ptr - buffer;
1182}
1183
San Mehat1cd22962010-02-03 12:59:29 -08001184static irqreturn_t
San Mehat9d2bd732009-09-22 16:44:22 -07001185msmsdcc_pio_irq(int irq, void *dev_id)
1186{
1187 struct msmsdcc_host *host = dev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 void __iomem *base = host->base;
San Mehat9d2bd732009-09-22 16:44:22 -07001189 uint32_t status;
1190
Murali Palnati36448a42011-09-02 15:06:18 +05301191 spin_lock(&host->lock);
1192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 status = readl_relaxed(base + MMCISTATUS);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
Murali Palnati36448a42011-09-02 15:06:18 +05301196 (MCI_IRQ_PIO)) == 0) {
1197 spin_unlock(&host->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 return IRQ_NONE;
Murali Palnati36448a42011-09-02 15:06:18 +05301199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200
1201#if IRQ_DEBUG
1202 msmsdcc_print_status(host, "irq1-r", status);
1203#endif
1204
San Mehat9d2bd732009-09-22 16:44:22 -07001205 do {
1206 unsigned long flags;
1207 unsigned int remain, len;
1208 char *buffer;
1209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
1211 | MCI_RXDATAAVLBL)))
1212 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001213
1214 /* Map the current scatter buffer */
1215 local_irq_save(flags);
1216 buffer = kmap_atomic(sg_page(host->pio.sg),
1217 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
1218 buffer += host->pio.sg_off;
1219 remain = host->pio.sg->length - host->pio.sg_off;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220
San Mehat9d2bd732009-09-22 16:44:22 -07001221 len = 0;
1222 if (status & MCI_RXACTIVE)
1223 len = msmsdcc_pio_read(host, buffer, remain);
1224 if (status & MCI_TXACTIVE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001225 len = msmsdcc_pio_write(host, buffer, remain);
San Mehat9d2bd732009-09-22 16:44:22 -07001226
1227 /* Unmap the buffer */
1228 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
1229 local_irq_restore(flags);
1230
1231 host->pio.sg_off += len;
1232 host->curr.xfer_remain -= len;
1233 host->curr.data_xfered += len;
1234 remain -= len;
1235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 if (remain) /* Done with this page? */
1237 break; /* Nope */
San Mehat9d2bd732009-09-22 16:44:22 -07001238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 if (status & MCI_RXACTIVE && host->curr.user_pages)
1240 flush_dcache_page(sg_page(host->pio.sg));
San Mehat9d2bd732009-09-22 16:44:22 -07001241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 if (!--host->pio.sg_len) {
1243 memset(&host->pio, 0, sizeof(host->pio));
1244 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001245 }
1246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 /* Advance to next sg */
1248 host->pio.sg++;
1249 host->pio.sg_off = 0;
1250
1251 status = readl_relaxed(base + MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -07001252 } while (1);
1253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
1255 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1256 (~(MCI_IRQ_PIO))) | MCI_RXDATAAVLBLMASK,
1257 host->base + MMCIMASK0);
1258 if (!host->curr.xfer_remain) {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301259 /*
1260 * back to back write to MASK0 register don't need
1261 * synchronization delay.
1262 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1264 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1265 }
1266 mb();
1267 } else if (!host->curr.xfer_remain) {
1268 writel_relaxed((readl_relaxed(host->base + MMCIMASK0) &
1269 (~(MCI_IRQ_PIO))) | 0, host->base + MMCIMASK0);
1270 mb();
1271 }
San Mehat9d2bd732009-09-22 16:44:22 -07001272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 spin_unlock(&host->lock);
San Mehat9d2bd732009-09-22 16:44:22 -07001274
1275 return IRQ_HANDLED;
1276}
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278static void
1279msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq);
1280
1281static void msmsdcc_wait_for_rxdata(struct msmsdcc_host *host,
1282 struct mmc_data *data)
1283{
1284 u32 loop_cnt = 0;
1285
1286 /*
1287 * For read commands with data less than fifo size, it is possible to
1288 * get DATAEND first and RXDATA_AVAIL might be set later because of
1289 * synchronization delay through the asynchronous RX FIFO. Thus, for
1290 * such cases, even after DATAEND interrupt is received software
1291 * should poll for RXDATA_AVAIL until the requested data is read out
1292 * of FIFO. This change is needed to get around this abnormal but
1293 * sometimes expected behavior of SDCC3 controller.
1294 *
1295 * We can expect RXDATAAVAIL bit to be set after 6HCLK clock cycles
1296 * after the data is loaded into RX FIFO. This would amount to less
1297 * than a microsecond and thus looping for 1000 times is good enough
1298 * for that delay.
1299 */
1300 while (((int)host->curr.xfer_remain > 0) && (++loop_cnt < 1000)) {
1301 if (readl_relaxed(host->base + MMCISTATUS) & MCI_RXDATAAVLBL) {
1302 spin_unlock(&host->lock);
1303 msmsdcc_pio_irq(1, host);
1304 spin_lock(&host->lock);
1305 }
1306 }
1307 if (loop_cnt == 1000) {
1308 pr_info("%s: Timed out while polling for Rx Data\n",
1309 mmc_hostname(host->mmc));
1310 data->error = -ETIMEDOUT;
1311 msmsdcc_reset_and_restore(host);
1312 }
1313}
1314
San Mehat9d2bd732009-09-22 16:44:22 -07001315static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
1316{
1317 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -07001318
1319 host->curr.cmd = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
1321 cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
1322 cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
1323 cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -07001324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
Sahitya Tummala5a0ae912011-07-18 13:34:01 +05301326 pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001327 cmd->error = -ETIMEDOUT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 } else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
1329 !host->cmd19_tuning_in_progress) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001330 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001331 cmd->error = -EILSEQ;
1332 }
1333
1334 if (!cmd->data || cmd->error) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 if (host->curr.data && host->dma.sg &&
1336 host->is_dma_mode)
San Mehat9d2bd732009-09-22 16:44:22 -07001337 msm_dmov_stop_cmd(host->dma.channel,
1338 &host->dma.hdr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339 else if (host->curr.data && host->sps.sg &&
1340 host->is_sps_mode){
1341 /* Stop current SPS transfer */
1342 msmsdcc_sps_exit_curr_xfer(host);
1343 }
San Mehat9d2bd732009-09-22 16:44:22 -07001344 else if (host->curr.data) { /* Non DMA */
Sahitya Tummalab08bb352010-12-08 15:03:05 +05301345 msmsdcc_reset_and_restore(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001346 msmsdcc_stop_data(host);
1347 msmsdcc_request_end(host, cmd->mrq);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301348 } else { /* host->data == NULL */
1349 if (!cmd->error && host->prog_enable) {
1350 if (status & MCI_PROGDONE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351 host->prog_enable = 0;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301352 msmsdcc_request_end(host, cmd->mrq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 } else
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301354 host->curr.cmd = cmd;
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301355 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05301356 host->prog_enable = 0;
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001357 if (host->dummy_52_needed)
1358 host->dummy_52_needed = 0;
1359 if (cmd->data && cmd->error)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 msmsdcc_reset_and_restore(host);
Sahitya Tummalad5137bd2010-12-08 15:03:04 +05301361 msmsdcc_request_end(host, cmd->mrq);
1362 }
1363 }
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301364 } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
1365 if (cmd->data->flags & MMC_DATA_READ)
1366 msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
1367 else
1368 msmsdcc_request_start(host, host->curr.mrq);
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301369 } else if (cmd->data) {
1370 if (!(cmd->data->flags & MMC_DATA_READ))
1371 msmsdcc_start_data(host, cmd->data, NULL, 0);
Joe Perchesb5a74d62009-09-22 16:44:25 -07001372 }
1373}
1374
San Mehat9d2bd732009-09-22 16:44:22 -07001375static irqreturn_t
1376msmsdcc_irq(int irq, void *dev_id)
1377{
1378 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -07001379 u32 status;
1380 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 int timer = 0;
San Mehat9d2bd732009-09-22 16:44:22 -07001382
1383 spin_lock(&host->lock);
1384
1385 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001386 struct mmc_command *cmd;
1387 struct mmc_data *data;
San Mehat9d2bd732009-09-22 16:44:22 -07001388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 if (timer) {
1390 timer = 0;
1391 msmsdcc_delay(host);
1392 }
San Mehat865c8062009-11-13 13:42:06 -08001393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 if (!host->clks_on) {
1395 pr_debug("%s: %s: SDIO async irq received\n",
1396 mmc_hostname(host->mmc), __func__);
1397 host->mmc->ios.clock = host->clk_rate;
1398 spin_unlock(&host->lock);
1399 host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);
1400 spin_lock(&host->lock);
1401 if (host->plat->cfg_mpm_sdiowakeup &&
1402 (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
1403 wake_lock(&host->sdio_wlock);
1404 /* only ansyc interrupt can come when clocks are off */
1405 writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301406 if (host->clk_rate <=
1407 msmsdcc_get_min_sup_clk_rate(host))
1408 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 }
1410
1411 status = readl_relaxed(host->base + MMCISTATUS);
1412
1413 if (((readl_relaxed(host->base + MMCIMASK0) & status) &
1414 (~(MCI_IRQ_PIO))) == 0)
San Mehat865c8062009-11-13 13:42:06 -08001415 break;
San Mehat9d2bd732009-09-22 16:44:22 -07001416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417#if IRQ_DEBUG
1418 msmsdcc_print_status(host, "irq0-r", status);
1419#endif
1420 status &= readl_relaxed(host->base + MMCIMASK0);
1421 writel_relaxed(status, host->base + MMCICLEAR);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05301422 /* Allow clear to take effect*/
Sujith Reddy Thumma32fae1a2011-10-03 11:16:51 +05301423 if (host->clk_rate <=
1424 msmsdcc_get_min_sup_clk_rate(host))
1425 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426#if IRQ_DEBUG
1427 msmsdcc_print_status(host, "irq0-p", status);
1428#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
1431 if (status & MCI_SDIOINTROPE) {
1432 if (host->sdcc_suspending)
1433 wake_lock(&host->sdio_suspend_wlock);
1434 mmc_signal_sdio_irq(host->mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07001435 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436#endif
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001437 data = host->curr.data;
1438
1439 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
1441 MCI_CMDTIMEOUT)) {
1442 if (status & MCI_CMDTIMEOUT)
1443 pr_debug("%s: dummy CMD52 timeout\n",
1444 mmc_hostname(host->mmc));
1445 if (status & MCI_CMDCRCFAIL)
1446 pr_debug("%s: dummy CMD52 CRC failed\n",
1447 mmc_hostname(host->mmc));
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001448 host->dummy_52_sent = 0;
1449 host->dummy_52_needed = 0;
1450 if (data) {
1451 msmsdcc_stop_data(host);
1452 msmsdcc_request_end(host, data->mrq);
1453 }
1454 WARN(!data, "No data cmd for dummy CMD52\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 spin_unlock(&host->lock);
1456 return IRQ_HANDLED;
1457 }
1458 break;
1459 }
1460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 /*
1462 * Check for proper command response
1463 */
1464 cmd = host->curr.cmd;
1465 if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
1466 MCI_CMDTIMEOUT | MCI_PROGDONE |
1467 MCI_AUTOCMD19TIMEOUT)) && host->curr.cmd) {
1468 msmsdcc_do_cmdirq(host, status);
1469 }
1470
1471 if (data) {
1472 /* Check for data errors */
1473 if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|
1474 MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
1475 msmsdcc_data_err(host, data, status);
1476 host->curr.data_xfered = 0;
1477 if (host->dma.sg && host->is_dma_mode)
1478 msm_dmov_stop_cmd(host->dma.channel,
1479 &host->dma.hdr, 0);
1480 else if (host->sps.sg && host->is_sps_mode) {
1481 /* Stop current SPS transfer */
1482 msmsdcc_sps_exit_curr_xfer(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301483 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 msmsdcc_reset_and_restore(host);
1485 if (host->curr.data)
1486 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301487 if (!data->stop || (host->curr.mrq->sbc
1488 && !data->error))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 timer |=
1490 msmsdcc_request_end(host,
1491 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301492 else if ((host->curr.mrq->sbc
1493 && data->error) ||
1494 !host->curr.mrq->sbc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495 msmsdcc_start_command(host,
1496 data->stop,
1497 0);
1498 timer = 1;
1499 }
1500 }
1501 }
1502
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301503 /* Check for prog done */
1504 if (host->curr.wait_for_auto_prog_done &&
1505 (status & MCI_PROGDONE))
1506 host->curr.got_auto_prog_done = 1;
1507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 /* Check for data done */
1509 if (!host->curr.got_dataend && (status & MCI_DATAEND))
1510 host->curr.got_dataend = 1;
1511
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301512 if (host->curr.got_dataend &&
1513 (!host->curr.wait_for_auto_prog_done ||
1514 (host->curr.wait_for_auto_prog_done &&
1515 host->curr.got_auto_prog_done))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 /*
1517 * If DMA is still in progress, we complete
1518 * via the completion handler
1519 */
1520 if (!host->dma.busy && !host->sps.busy) {
1521 /*
1522 * There appears to be an issue in the
1523 * controller where if you request a
1524 * small block transfer (< fifo size),
1525 * you may get your DATAEND/DATABLKEND
1526 * irq without the PIO data irq.
1527 *
1528 * Check to see if theres still data
1529 * to be read, and simulate a PIO irq.
1530 */
1531 if (data->flags & MMC_DATA_READ)
1532 msmsdcc_wait_for_rxdata(host,
1533 data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 if (!data->error) {
1535 host->curr.data_xfered =
1536 host->curr.xfer_size;
1537 host->curr.xfer_remain -=
1538 host->curr.xfer_size;
1539 }
1540
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001541 if (!host->dummy_52_needed) {
1542 msmsdcc_stop_data(host);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301543 if (!data->stop ||
1544 (host->curr.mrq->sbc
1545 && !data->error))
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001546 msmsdcc_request_end(
1547 host,
1548 data->mrq);
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301549 else if ((host->curr.mrq->sbc
1550 && data->error) ||
1551 !host->curr.mrq->sbc) {
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001552 msmsdcc_start_command(
1553 host,
1554 data->stop, 0);
1555 timer = 1;
1556 }
1557 } else {
1558 host->dummy_52_sent = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 msmsdcc_start_command(host,
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001560 &dummy52cmd,
1561 MCI_CPSM_PROGENA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 }
1563 }
1564 }
1565 }
1566
San Mehat9d2bd732009-09-22 16:44:22 -07001567 ret = 1;
1568 } while (status);
1569
1570 spin_unlock(&host->lock);
1571
San Mehat9d2bd732009-09-22 16:44:22 -07001572 return IRQ_RETVAL(ret);
1573}
1574
1575static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
1577{
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301578 if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 /* Queue/read data, daisy-chain command when data starts */
Sujit Reddy Thummadf8e9b22011-11-04 16:22:06 +05301580 if (mrq->sbc)
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301581 msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
1582 else
1583 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 } else {
1585 msmsdcc_start_command(host, mrq->cmd, 0);
1586 }
1587}
1588
1589static void
San Mehat9d2bd732009-09-22 16:44:22 -07001590msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
1591{
1592 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 /*
1596 * Get the SDIO AL client out of LPM.
1597 */
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07001598 WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 if (host->plat->is_sdio_al_client)
1600 msmsdcc_sdio_al_lpm(mmc, false);
San Mehat9d2bd732009-09-22 16:44:22 -07001601
Subhash Jadavanib5b07742011-08-29 17:48:07 +05301602 /* check if sps pipe reset is pending? */
1603 if (host->is_sps_mode && host->sps.pipe_reset_pending) {
1604 msmsdcc_sps_pipes_reset_and_restore(host);
1605 host->sps.pipe_reset_pending = false;
1606 }
1607
San Mehat9d2bd732009-09-22 16:44:22 -07001608 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 WARN(host->curr.mrq, "Request in progress\n");
1610 WARN(!host->pwr, "SDCC power is turned off\n");
1611 WARN(!host->clks_on, "SDCC clocks are turned off\n");
1612 WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001613
1614 if (host->eject) {
1615 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
1616 mrq->cmd->error = 0;
1617 mrq->data->bytes_xfered = mrq->data->blksz *
1618 mrq->data->blocks;
1619 } else
1620 mrq->cmd->error = -ENOMEDIUM;
1621
1622 spin_unlock_irqrestore(&host->lock, flags);
1623 mmc_request_done(mmc, mrq);
1624 return;
1625 }
1626
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301627 /*
1628 * Kick the software command timeout timer here.
1629 * Timer expires in 10 secs.
1630 */
1631 mod_timer(&host->req_tout_timer,
1632 (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
San Mehat9d2bd732009-09-22 16:44:22 -07001633
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301634 host->curr.mrq = mrq;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301635 if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301636 if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
1637 mrq->cmd->opcode == 54) {
Pratibhasagar V1c11da62011-11-14 12:36:35 +05301638 if (!host->sdcc_version)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639 host->dummy_52_needed = 1;
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301640 else
1641 /*
1642 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
1643 * write operations using CMD53 and CMD54.
1644 * Setting this bit with CMD53 would
1645 * automatically triggers PROG_DONE interrupt
1646 * without the need of sending dummy CMD52.
1647 */
1648 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 }
San Mehat9d2bd732009-09-22 16:44:22 -07001650 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301651
Pratibhasagar V00b94332011-10-18 14:57:27 +05301652 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301653 mrq->sbc->mrq = mrq;
1654 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301655 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301656 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301657 msmsdcc_start_command(host, mrq->sbc, 0);
1658 } else {
1659 msmsdcc_request_start(host, mrq);
1660 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301661 } else {
1662 msmsdcc_request_start(host, mrq);
1663 }
1664
San Mehat9d2bd732009-09-22 16:44:22 -07001665 spin_unlock_irqrestore(&host->lock, flags);
1666}
1667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1669 int min_uV, int max_uV)
1670{
1671 int rc = 0;
1672
1673 if (vreg->set_voltage_sup) {
1674 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1675 if (rc) {
1676 pr_err("%s: regulator_set_voltage(%s) failed."
1677 " min_uV=%d, max_uV=%d, rc=%d\n",
1678 __func__, vreg->name, min_uV, max_uV, rc);
1679 }
1680 }
1681
1682 return rc;
1683}
1684
1685static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1686 int uA_load)
1687{
1688 int rc = 0;
1689
Krishna Kondafea60182011-11-01 16:01:34 -07001690 /* regulators that do not support regulator_set_voltage also
1691 do not support regulator_set_optimum_mode */
1692 if (vreg->set_voltage_sup) {
1693 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1694 if (rc < 0)
1695 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1696 "uA_load=%d) failed. rc=%d\n", __func__,
1697 vreg->name, uA_load, rc);
1698 else
1699 /* regulator_set_optimum_mode() can return non zero
1700 * value even for success case.
1701 */
1702 rc = 0;
1703 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704
1705 return rc;
1706}
1707
1708static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1709 struct device *dev)
1710{
1711 int rc = 0;
1712
1713 /* check if regulator is already initialized? */
1714 if (vreg->reg)
1715 goto out;
1716
1717 /* Get the regulator handle */
1718 vreg->reg = regulator_get(dev, vreg->name);
1719 if (IS_ERR(vreg->reg)) {
1720 rc = PTR_ERR(vreg->reg);
1721 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1722 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001723 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001725
1726 if (regulator_count_voltages(vreg->reg) > 0)
1727 vreg->set_voltage_sup = 1;
1728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729out:
1730 return rc;
1731}
1732
1733static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1734{
1735 if (vreg->reg)
1736 regulator_put(vreg->reg);
1737}
1738
1739/* This init function should be called only once for each SDCC slot */
1740static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1741{
1742 int rc = 0;
1743 struct msm_mmc_slot_reg_data *curr_slot;
1744 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1745 struct device *dev = mmc_dev(host->mmc);
1746
1747 curr_slot = host->plat->vreg_data;
1748 if (!curr_slot)
1749 goto out;
1750
1751 curr_vdd_reg = curr_slot->vdd_data;
1752 curr_vccq_reg = curr_slot->vccq_data;
1753 curr_vddp_reg = curr_slot->vddp_data;
1754
1755 if (is_init) {
1756 /*
1757 * Get the regulator handle from voltage regulator framework
1758 * and then try to set the voltage level for the regulator
1759 */
1760 if (curr_vdd_reg) {
1761 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1762 if (rc)
1763 goto out;
1764 }
1765 if (curr_vccq_reg) {
1766 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1767 if (rc)
1768 goto vdd_reg_deinit;
1769 }
1770 if (curr_vddp_reg) {
1771 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1772 if (rc)
1773 goto vccq_reg_deinit;
1774 }
1775 goto out;
1776 } else {
1777 /* Deregister all regulators from regulator framework */
1778 goto vddp_reg_deinit;
1779 }
1780vddp_reg_deinit:
1781 if (curr_vddp_reg)
1782 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1783vccq_reg_deinit:
1784 if (curr_vccq_reg)
1785 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1786vdd_reg_deinit:
1787 if (curr_vdd_reg)
1788 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1789out:
1790 return rc;
1791}
1792
1793static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1794{
1795 int rc = 0;
1796
Subhash Jadavanicc922692011-08-01 23:05:01 +05301797 /* Put regulator in HPM (high power mode) */
1798 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1799 if (rc < 0)
1800 goto out;
1801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 if (!vreg->is_enabled) {
1803 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301804 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1805 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 if (rc)
1807 goto out;
1808
1809 rc = regulator_enable(vreg->reg);
1810 if (rc) {
1811 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1812 __func__, vreg->name, rc);
1813 goto out;
1814 }
1815 vreg->is_enabled = true;
1816 }
1817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818out:
1819 return rc;
1820}
1821
1822static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1823{
1824 int rc = 0;
1825
1826 /* Never disable regulator marked as always_on */
1827 if (vreg->is_enabled && !vreg->always_on) {
1828 rc = regulator_disable(vreg->reg);
1829 if (rc) {
1830 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1831 __func__, vreg->name, rc);
1832 goto out;
1833 }
1834 vreg->is_enabled = false;
1835
1836 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1837 if (rc < 0)
1838 goto out;
1839
1840 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301841 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 if (rc)
1843 goto out;
1844 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1845 /* Put always_on regulator in LPM (low power mode) */
1846 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1847 if (rc < 0)
1848 goto out;
1849 }
1850out:
1851 return rc;
1852}
1853
1854static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1855{
1856 int rc = 0, i;
1857 struct msm_mmc_slot_reg_data *curr_slot;
1858 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1859 struct msm_mmc_reg_data *vreg_table[3];
1860
1861 curr_slot = host->plat->vreg_data;
1862 if (!curr_slot)
1863 goto out;
1864
1865 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1866 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1867 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1868
1869 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1870 if (vreg_table[i]) {
1871 if (enable)
1872 rc = msmsdcc_vreg_enable(vreg_table[i]);
1873 else
1874 rc = msmsdcc_vreg_disable(vreg_table[i]);
1875 if (rc)
1876 goto out;
1877 }
1878 }
1879out:
1880 return rc;
1881}
1882
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301883static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884{
1885 int rc = 0;
1886
1887 if (host->plat->vreg_data) {
1888 struct msm_mmc_reg_data *vddp_reg =
1889 host->plat->vreg_data->vddp_data;
1890
1891 if (vddp_reg && vddp_reg->is_enabled)
1892 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1893 }
1894
1895 return rc;
1896}
1897
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301898static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1899{
1900 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1901 int rc = 0;
1902
1903 if (curr_slot && curr_slot->vddp_data) {
1904 rc = msmsdcc_set_vddp_level(host,
1905 curr_slot->vddp_data->low_vol_level);
1906
1907 if (rc)
1908 pr_err("%s: %s: failed to change vddp level to %d",
1909 mmc_hostname(host->mmc), __func__,
1910 curr_slot->vddp_data->low_vol_level);
1911 }
1912
1913 return rc;
1914}
1915
1916static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1917{
1918 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1919 int rc = 0;
1920
1921 if (curr_slot && curr_slot->vddp_data) {
1922 rc = msmsdcc_set_vddp_level(host,
1923 curr_slot->vddp_data->high_vol_level);
1924
1925 if (rc)
1926 pr_err("%s: %s: failed to change vddp level to %d",
1927 mmc_hostname(host->mmc), __func__,
1928 curr_slot->vddp_data->high_vol_level);
1929 }
1930
1931 return rc;
1932}
1933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1935{
1936 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1937 return 1;
1938 return 0;
1939}
1940
1941static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1942{
1943 if (enable) {
1944 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1945 clk_enable(host->dfab_pclk);
1946 if (!IS_ERR(host->pclk))
1947 clk_enable(host->pclk);
1948 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301949 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301951 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952 clk_disable(host->clk);
1953 if (!IS_ERR(host->pclk))
1954 clk_disable(host->pclk);
1955 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1956 clk_disable(host->dfab_pclk);
1957 }
1958}
1959
1960static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1961 unsigned int req_clk)
1962{
1963 unsigned int sel_clk = -1;
1964
1965 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1966 unsigned char cnt;
1967
1968 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1969 if (host->plat->sup_clk_table[cnt] > req_clk)
1970 break;
1971 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1972 sel_clk = host->plat->sup_clk_table[cnt];
1973 break;
1974 } else
1975 sel_clk = host->plat->sup_clk_table[cnt];
1976 }
1977 } else {
1978 if ((req_clk < host->plat->msmsdcc_fmax) &&
1979 (req_clk > host->plat->msmsdcc_fmid))
1980 sel_clk = host->plat->msmsdcc_fmid;
1981 else
1982 sel_clk = req_clk;
1983 }
1984
1985 return sel_clk;
1986}
1987
1988static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1989 struct msmsdcc_host *host)
1990{
1991 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1992 return host->plat->sup_clk_table[0];
1993 else
1994 return host->plat->msmsdcc_fmin;
1995}
1996
1997static inline unsigned int msmsdcc_get_max_sup_clk_rate(
1998 struct msmsdcc_host *host)
1999{
2000 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2001 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2002 else
2003 return host->plat->msmsdcc_fmax;
2004}
2005
2006static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302007{
2008 struct msm_mmc_gpio_data *curr;
2009 int i, rc = 0;
2010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302012 for (i = 0; i < curr->size; i++) {
2013 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 if (curr->gpio[i].is_always_on &&
2015 curr->gpio[i].is_enabled)
2016 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302017 rc = gpio_request(curr->gpio[i].no,
2018 curr->gpio[i].name);
2019 if (rc) {
2020 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2021 mmc_hostname(host->mmc),
2022 curr->gpio[i].no,
2023 curr->gpio[i].name, rc);
2024 goto free_gpios;
2025 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302027 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 if (curr->gpio[i].is_always_on)
2029 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302030 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302032 }
2033 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302035
2036free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302038 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039 curr->gpio[i].is_enabled = false;
2040 }
2041out:
2042 return rc;
2043}
2044
2045static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2046{
2047 struct msm_mmc_pad_data *curr;
2048 int i;
2049
2050 curr = host->plat->pin_data->pad_data;
2051 for (i = 0; i < curr->drv->size; i++) {
2052 if (enable)
2053 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2054 curr->drv->on[i].val);
2055 else
2056 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2057 curr->drv->off[i].val);
2058 }
2059
2060 for (i = 0; i < curr->pull->size; i++) {
2061 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002062 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002063 curr->pull->on[i].val);
2064 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002065 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 curr->pull->off[i].val);
2067 }
2068
2069 return 0;
2070}
2071
2072static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2073{
2074 int rc = 0;
2075
2076 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2077 return 0;
2078
2079 if (host->plat->pin_data->is_gpio)
2080 rc = msmsdcc_setup_gpio(host, enable);
2081 else
2082 rc = msmsdcc_setup_pad(host, enable);
2083
2084 if (!rc)
2085 host->plat->pin_data->cfg_sts = enable;
2086
2087 return rc;
2088}
2089
2090static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2091{
2092 unsigned int wakeup_irq;
2093
2094 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2095 host->plat->sdiowakeup_irq :
2096 host->core_irqres->start;
2097
2098 if (!host->irq_wake_enabled) {
2099 enable_irq_wake(wakeup_irq);
2100 host->irq_wake_enabled = true;
2101 }
2102}
2103
2104static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2105{
2106 unsigned int wakeup_irq;
2107
2108 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2109 host->plat->sdiowakeup_irq :
2110 host->core_irqres->start;
2111
2112 if (host->irq_wake_enabled) {
2113 disable_irq_wake(wakeup_irq);
2114 host->irq_wake_enabled = false;
2115 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302116}
2117
San Mehat9d2bd732009-09-22 16:44:22 -07002118static void
2119msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2120{
2121 struct msmsdcc_host *host = mmc_priv(mmc);
2122 u32 clk = 0, pwr = 0;
2123 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002124 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002127 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302128
San Mehat9d2bd732009-09-22 16:44:22 -07002129 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 spin_lock_irqsave(&host->lock, flags);
2131 if (!host->clks_on) {
2132 msmsdcc_setup_clocks(host, true);
2133 host->clks_on = 1;
2134 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2135 if (!host->plat->sdiowakeup_irq) {
2136 writel_relaxed(host->mci_irqenable,
2137 host->base + MMCIMASK0);
2138 mb();
2139 if (host->plat->cfg_mpm_sdiowakeup &&
2140 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2141 host->plat->cfg_mpm_sdiowakeup(
2142 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2143 msmsdcc_disable_irq_wake(host);
2144 } else if (!(mmc->pm_flags &
2145 MMC_PM_WAKE_SDIO_IRQ)) {
2146 writel_relaxed(host->mci_irqenable,
2147 host->base + MMCIMASK0);
2148 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302149 } else {
2150 writel_relaxed(host->mci_irqenable,
2151 host->base + MMCIMASK0);
2152 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 }
San Mehat9d2bd732009-09-22 16:44:22 -07002154 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155 spin_unlock_irqrestore(&host->lock, flags);
2156
2157 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2158 /*
2159 * For DDR50 mode, controller needs clock rate to be
2160 * double than what is required on the SD card CLK pin.
2161 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302162 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002163 /*
2164 * Make sure that we don't double the clock if
2165 * doubled clock rate is already set
2166 */
2167 if (!host->ddr_doubled_clk_rate ||
2168 (host->ddr_doubled_clk_rate &&
2169 (host->ddr_doubled_clk_rate != ios->clock))) {
2170 host->ddr_doubled_clk_rate =
2171 msmsdcc_get_sup_clk_rate(
2172 host, (ios->clock * 2));
2173 clock = host->ddr_doubled_clk_rate;
2174 }
2175 } else {
2176 host->ddr_doubled_clk_rate = 0;
2177 }
2178
2179 if (clock != host->clk_rate) {
2180 rc = clk_set_rate(host->clk, clock);
2181 if (rc < 0)
2182 pr_debug("%s: failed to set clk rate %u\n",
2183 mmc_hostname(mmc), clock);
2184 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302185 host->reg_write_delay =
2186 (1 + ((3 * USEC_PER_SEC) /
2187 (host->clk_rate ? host->clk_rate :
2188 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 }
2190 /*
2191 * give atleast 2 MCLK cycles delay for clocks
2192 * and SDCC core to stabilize
2193 */
2194 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002195 clk |= MCI_CLK_ENABLE;
2196 }
2197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198 if (ios->bus_width == MMC_BUS_WIDTH_8)
2199 clk |= MCI_CLK_WIDEBUS_8;
2200 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2201 clk |= MCI_CLK_WIDEBUS_4;
2202 else
2203 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205 if (msmsdcc_is_pwrsave(host))
2206 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 host->tuning_needed = 0;
2211 /*
2212 * Select the controller timing mode according
2213 * to current bus speed mode
2214 */
2215 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2216 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2217 clk |= (4 << 14);
2218 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302219 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220 clk |= (3 << 14);
2221 } else {
2222 clk |= (2 << 14); /* feedback clock */
2223 }
2224
2225 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2226 clk |= (2 << 23);
2227
2228 if (host->io_pad_pwr_switch)
2229 clk |= IO_PAD_PWR_SWITCH;
2230
2231 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002232 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2234 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002235
2236 switch (ios->power_mode) {
2237 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2239 if (!host->sdcc_irq_disabled) {
2240 if (host->plat->cfg_mpm_sdiowakeup)
2241 host->plat->cfg_mpm_sdiowakeup(
2242 mmc_dev(mmc), SDC_DAT1_DISABLE);
2243 disable_irq(host->core_irqres->start);
2244 host->sdcc_irq_disabled = 1;
2245 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302246 /*
2247 * As VDD pad rail is always on, set low voltage for VDD
2248 * pad rail when slot is unused (when card is not present
2249 * or during system suspend).
2250 */
2251 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002253 break;
2254 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302255 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002256 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 if (host->sdcc_irq_disabled) {
2258 if (host->plat->cfg_mpm_sdiowakeup)
2259 host->plat->cfg_mpm_sdiowakeup(
2260 mmc_dev(mmc), SDC_DAT1_ENABLE);
2261 enable_irq(host->core_irqres->start);
2262 host->sdcc_irq_disabled = 0;
2263 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302264 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002266 break;
2267 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002269 pwr |= MCI_PWR_ON;
2270 break;
2271 }
2272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 spin_lock_irqsave(&host->lock, flags);
2274 if (!host->clks_on) {
2275 /* force the clocks to be on */
2276 msmsdcc_setup_clocks(host, true);
2277 /*
2278 * give atleast 2 MCLK cycles delay for clocks
2279 * and SDCC core to stabilize
2280 */
2281 msmsdcc_delay(host);
2282 }
2283 writel_relaxed(clk, host->base + MMCICLOCK);
2284 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002285
2286 if (host->pwr != pwr) {
2287 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302289 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002290 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 if (!host->clks_on) {
2292 /* force the clocks to be off */
2293 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 }
2295
2296 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2297 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2298 if (!host->plat->sdiowakeup_irq) {
2299 writel_relaxed(MCI_SDIOINTMASK,
2300 host->base + MMCIMASK0);
2301 mb();
2302 if (host->plat->cfg_mpm_sdiowakeup &&
2303 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2304 host->plat->cfg_mpm_sdiowakeup(
2305 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2306 msmsdcc_enable_irq_wake(host);
2307 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2308 writel_relaxed(0, host->base + MMCIMASK0);
2309 } else {
2310 writel_relaxed(MCI_SDIOINTMASK,
2311 host->base + MMCIMASK0);
2312 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302313 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314 }
2315 msmsdcc_setup_clocks(host, false);
2316 host->clks_on = 0;
2317 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002318 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002319}
2320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2322{
2323 struct msmsdcc_host *host = mmc_priv(mmc);
2324 u32 clk;
2325
2326 clk = readl_relaxed(host->base + MMCICLOCK);
2327 pr_debug("Changing to pwr_save=%d", pwrsave);
2328 if (pwrsave && msmsdcc_is_pwrsave(host))
2329 clk |= MCI_CLK_PWRSAVE;
2330 else
2331 clk &= ~MCI_CLK_PWRSAVE;
2332 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302333 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334
2335 return 0;
2336}
2337
2338static int msmsdcc_get_ro(struct mmc_host *mmc)
2339{
2340 int status = -ENOSYS;
2341 struct msmsdcc_host *host = mmc_priv(mmc);
2342
2343 if (host->plat->wpswitch) {
2344 status = host->plat->wpswitch(mmc_dev(mmc));
2345 } else if (host->plat->wpswitch_gpio) {
2346 status = gpio_request(host->plat->wpswitch_gpio,
2347 "SD_WP_Switch");
2348 if (status) {
2349 pr_err("%s: %s: Failed to request GPIO %d\n",
2350 mmc_hostname(mmc), __func__,
2351 host->plat->wpswitch_gpio);
2352 } else {
2353 status = gpio_direction_input(
2354 host->plat->wpswitch_gpio);
2355 if (!status) {
2356 /*
2357 * Wait for atleast 300ms as debounce
2358 * time for GPIO input to stabilize.
2359 */
2360 msleep(300);
2361 status = gpio_get_value_cansleep(
2362 host->plat->wpswitch_gpio);
2363 status ^= !host->plat->wpswitch_polarity;
2364 }
2365 gpio_free(host->plat->wpswitch_gpio);
2366 }
2367 }
2368
2369 if (status < 0)
2370 status = -ENOSYS;
2371 pr_debug("%s: Card read-only status %d\n", __func__, status);
2372
2373 return status;
2374}
2375
2376#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002377static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2378{
2379 struct msmsdcc_host *host = mmc_priv(mmc);
2380 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381
2382 if (enable) {
2383 spin_lock_irqsave(&host->lock, flags);
2384 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2385 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2386 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2387 spin_unlock_irqrestore(&host->lock, flags);
2388 } else {
2389 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2390 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2391 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2392 }
2393 mb();
2394}
2395#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2396
2397#ifdef CONFIG_PM_RUNTIME
2398static int msmsdcc_enable(struct mmc_host *mmc)
2399{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302400 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 struct device *dev = mmc->parent;
2402
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302403 if (dev->power.runtime_status == RPM_SUSPENDING) {
2404 if (mmc->suspend_task == current) {
2405 pm_runtime_get_noresume(dev);
2406 goto out;
2407 }
2408 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302410 rc = pm_runtime_get_sync(dev);
2411
2412 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2414 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302415 return rc;
2416 }
2417out:
2418 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419}
2420
2421static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2422{
2423 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302424 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302426 if (host->plat->disable_runtime_pm)
2427 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2429 return -ENOTSUPP;
2430
2431 rc = pm_runtime_put_sync(mmc->parent);
2432
2433 if (rc < 0)
2434 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2435 __func__, rc);
2436 return rc;
2437}
2438#else
2439#define msmsdcc_enable NULL
2440#define msmsdcc_disable NULL
2441#endif
2442
2443static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2444 struct mmc_ios *ios)
2445{
2446 struct msmsdcc_host *host = mmc_priv(mmc);
2447 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302448 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002449
2450 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2451 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302452 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 goto out;
2454 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2455 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302456 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 goto out;
2458 }
San Mehat9d2bd732009-09-22 16:44:22 -07002459
2460 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 /*
2462 * If we are here means voltage switch from high voltage to
2463 * low voltage is required
2464 */
2465
2466 /*
2467 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2468 * register until they become all zeros.
2469 */
2470 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302471 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2473 mmc_hostname(mmc), __func__);
2474 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002475 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476
2477 /* Stop SD CLK output. */
2478 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2479 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302480 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002481 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482
2483 /*
2484 * Switch VDDPX from high voltage to low voltage
2485 * to change the VDD of the SD IO pads.
2486 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302487 rc = msmsdcc_set_vddp_low_vol(host);
2488 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490
2491 spin_lock_irqsave(&host->lock, flags);
2492 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2493 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302494 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495 host->io_pad_pwr_switch = 1;
2496 spin_unlock_irqrestore(&host->lock, flags);
2497
2498 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2499 usleep_range(5000, 5500);
2500
2501 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302502 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2504 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302505 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 spin_unlock_irqrestore(&host->lock, flags);
2507
2508 /*
2509 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2510 * don't become all ones within 1 ms then a Voltage Switch
2511 * sequence has failed and a power cycle to the card is required.
2512 * Otherwise Voltage Switch sequence is completed successfully.
2513 */
2514 usleep_range(1000, 1500);
2515
2516 spin_lock_irqsave(&host->lock, flags);
2517 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2518 != (0xF << 1)) {
2519 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2520 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302521 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 goto out_unlock;
2523 }
2524
2525out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302526 /* Enable PWRSAVE */
2527 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2528 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 spin_unlock_irqrestore(&host->lock, flags);
2530out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302531 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002532}
2533
2534static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2535 u8 phase);
2536/* Initialize the DLL (Programmable Delay Line ) */
2537static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2538{
2539 int rc = 0;
2540 u32 wait_timeout;
2541
2542 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2543 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2544 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2545
2546 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2547 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2548 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2549
2550 msmsdcc_delay(host);
2551
2552 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2553 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2554 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2555
2556 /* Initialize the phase to 0 */
2557 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2558 if (rc)
2559 goto out;
2560
2561 wait_timeout = 1000;
2562 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2563 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2564 /* max. wait for 1 sec for LOCK bit to be set */
2565 if (--wait_timeout == 0) {
2566 pr_err("%s: %s: DLL failed to lock at phase: %d",
2567 mmc_hostname(host->mmc), __func__, 0);
2568 rc = -1;
2569 goto out;
2570 }
2571 /* wait for 1ms */
2572 usleep_range(1000, 1500);
2573 }
2574out:
2575 return rc;
2576}
2577
2578/*
2579 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2580 * calibration sequence. This function should be called before
2581 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2582 * commands (CMD17/CMD18).
2583 */
2584static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2585{
2586 /* Set CDR_EN bit to 1. */
2587 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2588 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2589
2590 /* Set CDR_EXT_EN bit to 0. */
2591 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2592 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2593
2594 /* Set CK_OUT_EN bit to 0. */
2595 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2596 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2597
2598 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2599 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2600 ;
2601
2602 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2603 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2604 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2605
2606 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2607 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2608 ;
2609}
2610
2611static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2612 u8 phase)
2613{
2614 int rc = 0;
2615 u32 mclk_freq = 0;
2616 u32 wait_timeout;
2617
2618 /* Set CDR_EN bit to 0. */
2619 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2620 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2621
2622 /* Set CDR_EXT_EN bit to 1. */
2623 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2624 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2625
2626 /* Program the MCLK value to MCLK_FREQ bit field */
2627 if (host->clk_rate <= 112000000)
2628 mclk_freq = 0;
2629 else if (host->clk_rate <= 125000000)
2630 mclk_freq = 1;
2631 else if (host->clk_rate <= 137000000)
2632 mclk_freq = 2;
2633 else if (host->clk_rate <= 150000000)
2634 mclk_freq = 3;
2635 else if (host->clk_rate <= 162000000)
2636 mclk_freq = 4;
2637 else if (host->clk_rate <= 175000000)
2638 mclk_freq = 5;
2639 else if (host->clk_rate <= 187000000)
2640 mclk_freq = 6;
2641 else if (host->clk_rate <= 200000000)
2642 mclk_freq = 7;
2643
2644 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2645 & ~(7 << 24)) | (mclk_freq << 24)),
2646 host->base + MCI_DLL_CONFIG);
2647
2648 /* Set CK_OUT_EN bit to 0. */
2649 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2650 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2651
2652 /* Set DLL_EN bit to 1. */
2653 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2654 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2655
2656 wait_timeout = 1000;
2657 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2658 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2659 /* max. wait for 1 sec for LOCK bit for be set */
2660 if (--wait_timeout == 0) {
2661 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2662 mmc_hostname(host->mmc), __func__, phase);
2663 rc = -1;
2664 goto out;
2665 }
2666 /* wait for 1ms */
2667 usleep_range(1000, 1500);
2668 }
2669
2670 /*
2671 * Write the selected DLL clock output phase (0 ... 15)
2672 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2673 */
2674 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2675 & ~(0xF << 20)) | (phase << 20)),
2676 host->base + MCI_DLL_CONFIG);
2677
2678 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2679 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2680 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2681
2682 wait_timeout = 1000;
2683 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2684 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2685 /* max. wait for 1 sec for LOCK bit for be set */
2686 if (--wait_timeout == 0) {
2687 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2688 mmc_hostname(host->mmc), __func__, phase);
2689 rc = -1;
2690 goto out;
2691 }
2692 /* wait for 1ms */
2693 usleep_range(1000, 1500);
2694 }
2695out:
2696 return rc;
2697}
2698
2699static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2700{
2701 struct msmsdcc_host *host = mmc_priv(mmc);
2702 u8 phase;
2703 u8 *data_buf;
2704 u8 tuned_phases[16], tuned_phase_cnt = 0;
2705 int rc = 0;
2706
2707 /* Tuning is only required for SDR50 & SDR104 modes */
2708 if (!host->tuning_needed) {
2709 rc = 0;
2710 goto out;
2711 }
2712
2713 host->cmd19_tuning_in_progress = 1;
2714 /*
2715 * Make sure that clock is always enabled when DLL
2716 * tuning is in progress. Keeping PWRSAVE ON may
2717 * turn off the clock. So let's disable the PWRSAVE
2718 * here and re-enable it once tuning is completed.
2719 */
2720 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2721 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302722 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 /* first of all reset the tuning block */
2724 rc = msmsdcc_init_cm_sdc4_dll(host);
2725 if (rc)
2726 goto out;
2727
2728 data_buf = kmalloc(64, GFP_KERNEL);
2729 if (!data_buf) {
2730 rc = -ENOMEM;
2731 goto out;
2732 }
2733
2734 phase = 0;
2735 do {
2736 struct mmc_command cmd = {0};
2737 struct mmc_data data = {0};
2738 struct mmc_request mrq = {
2739 .cmd = &cmd,
2740 .data = &data
2741 };
2742 struct scatterlist sg;
2743
2744 /* set the phase in delay line hw block */
2745 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2746 if (rc)
2747 goto kfree;
2748
2749 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2750 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2751
2752 data.blksz = 64;
2753 data.blocks = 1;
2754 data.flags = MMC_DATA_READ;
2755 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2756
2757 data.sg = &sg;
2758 data.sg_len = 1;
2759 sg_init_one(&sg, data_buf, 64);
2760 memset(data_buf, 0, 64);
2761 mmc_wait_for_req(mmc, &mrq);
2762
2763 if (!cmd.error && !data.error &&
2764 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2765 /* tuning is successful with this tuning point */
2766 tuned_phases[tuned_phase_cnt++] = phase;
2767 }
2768 } while (++phase < 16);
2769
2770 kfree(data_buf);
2771
2772 if (tuned_phase_cnt) {
2773 tuned_phase_cnt--;
2774 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2775 phase = tuned_phases[tuned_phase_cnt];
2776 /*
2777 * Finally set the selected phase in delay
2778 * line hw block.
2779 */
2780 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2781 if (rc)
2782 goto out;
2783 } else {
2784 /* tuning failed */
2785 rc = -EAGAIN;
2786 pr_err("%s: %s: no tuning point found",
2787 mmc_hostname(mmc), __func__);
2788 }
2789 goto out;
2790
2791kfree:
2792 kfree(data_buf);
2793out:
2794 /* re-enable PWESAVE */
2795 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2796 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302797 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 host->cmd19_tuning_in_progress = 0;
2799 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002800}
2801
2802static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803 .enable = msmsdcc_enable,
2804 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002805 .request = msmsdcc_request,
2806 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002807 .get_ro = msmsdcc_get_ro,
2808#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002809 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002810#endif
2811 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2812 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002813};
2814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815static unsigned int
2816msmsdcc_slot_status(struct msmsdcc_host *host)
2817{
2818 int status;
2819 unsigned int gpio_no = host->plat->status_gpio;
2820
2821 status = gpio_request(gpio_no, "SD_HW_Detect");
2822 if (status) {
2823 pr_err("%s: %s: Failed to request GPIO %d\n",
2824 mmc_hostname(host->mmc), __func__, gpio_no);
2825 } else {
2826 status = gpio_direction_input(gpio_no);
2827 if (!status)
2828 status = !gpio_get_value_cansleep(gpio_no);
2829 gpio_free(gpio_no);
2830 }
2831 return status;
2832}
2833
San Mehat9d2bd732009-09-22 16:44:22 -07002834static void
2835msmsdcc_check_status(unsigned long data)
2836{
2837 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2838 unsigned int status;
2839
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 if (host->plat->status || host->plat->status_gpio) {
2841 if (host->plat->status)
2842 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002843 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 status = msmsdcc_slot_status(host);
2845
2846 host->eject = !status;
2847 if (status ^ host->oldstat) {
2848 pr_info("%s: Slot status change detected (%d -> %d)\n",
2849 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002850 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851 }
2852 host->oldstat = status;
2853 } else {
2854 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002855 }
San Mehat9d2bd732009-09-22 16:44:22 -07002856}
2857
2858static irqreturn_t
2859msmsdcc_platform_status_irq(int irq, void *dev_id)
2860{
2861 struct msmsdcc_host *host = dev_id;
2862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002864 msmsdcc_check_status((unsigned long) host);
2865 return IRQ_HANDLED;
2866}
2867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002868static irqreturn_t
2869msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2870{
2871 struct msmsdcc_host *host = dev_id;
2872
2873 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2874 spin_lock(&host->lock);
2875 if (!host->sdio_irq_disabled) {
2876 disable_irq_nosync(irq);
2877 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2878 wake_lock(&host->sdio_wlock);
2879 msmsdcc_disable_irq_wake(host);
2880 }
2881 host->sdio_irq_disabled = 1;
2882 }
2883 if (host->plat->is_sdio_al_client) {
2884 if (!host->clks_on) {
2885 msmsdcc_setup_clocks(host, true);
2886 host->clks_on = 1;
2887 }
2888 if (host->sdcc_irq_disabled) {
2889 writel_relaxed(host->mci_irqenable,
2890 host->base + MMCIMASK0);
2891 mb();
2892 enable_irq(host->core_irqres->start);
2893 host->sdcc_irq_disabled = 0;
2894 }
2895 wake_lock(&host->sdio_wlock);
2896 }
2897 spin_unlock(&host->lock);
2898
2899 return IRQ_HANDLED;
2900}
2901
San Mehat9d2bd732009-09-22 16:44:22 -07002902static void
2903msmsdcc_status_notify_cb(int card_present, void *dev_id)
2904{
2905 struct msmsdcc_host *host = dev_id;
2906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002908 card_present);
2909 msmsdcc_check_status((unsigned long) host);
2910}
2911
San Mehat9d2bd732009-09-22 16:44:22 -07002912static int
2913msmsdcc_init_dma(struct msmsdcc_host *host)
2914{
2915 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2916 host->dma.host = host;
2917 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002918 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002919
2920 if (!host->dmares)
2921 return -ENODEV;
2922
2923 host->dma.nc = dma_alloc_coherent(NULL,
2924 sizeof(struct msmsdcc_nc_dmadata),
2925 &host->dma.nc_busaddr,
2926 GFP_KERNEL);
2927 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002928 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002929 return -ENOMEM;
2930 }
2931 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2932 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2933 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2934 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2935 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002936 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002937
2938 return 0;
2939}
2940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2942/**
2943 * Allocate and Connect a SDCC peripheral's SPS endpoint
2944 *
2945 * This function allocates endpoint context and
2946 * connect it with memory endpoint by calling
2947 * appropriate SPS driver APIs.
2948 *
2949 * Also registers a SPS callback function with
2950 * SPS driver
2951 *
2952 * This function should only be called once typically
2953 * during driver probe.
2954 *
2955 * @host - Pointer to sdcc host structure
2956 * @ep - Pointer to sps endpoint data structure
2957 * @is_produce - 1 means Producer endpoint
2958 * 0 means Consumer endpoint
2959 *
2960 * @return - 0 if successful else negative value.
2961 *
2962 */
2963static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2964 struct msmsdcc_sps_ep_conn_data *ep,
2965 bool is_producer)
2966{
2967 int rc = 0;
2968 struct sps_pipe *sps_pipe_handle;
2969 struct sps_connect *sps_config = &ep->config;
2970 struct sps_register_event *sps_event = &ep->event;
2971
2972 /* Allocate endpoint context */
2973 sps_pipe_handle = sps_alloc_endpoint();
2974 if (!sps_pipe_handle) {
2975 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2976 mmc_hostname(host->mmc), is_producer);
2977 rc = -ENOMEM;
2978 goto out;
2979 }
2980
2981 /* Get default connection configuration for an endpoint */
2982 rc = sps_get_config(sps_pipe_handle, sps_config);
2983 if (rc) {
2984 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2985 " rc=%d", mmc_hostname(host->mmc),
2986 (u32)sps_pipe_handle, rc);
2987 goto get_config_err;
2988 }
2989
2990 /* Modify the default connection configuration */
2991 if (is_producer) {
2992 /*
2993 * For SDCC producer transfer, source should be
2994 * SDCC peripheral where as destination should
2995 * be system memory.
2996 */
2997 sps_config->source = host->sps.bam_handle;
2998 sps_config->destination = SPS_DEV_HANDLE_MEM;
2999 /* Producer pipe will handle this connection */
3000 sps_config->mode = SPS_MODE_SRC;
3001 sps_config->options =
3002 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3003 } else {
3004 /*
3005 * For SDCC consumer transfer, source should be
3006 * system memory where as destination should
3007 * SDCC peripheral
3008 */
3009 sps_config->source = SPS_DEV_HANDLE_MEM;
3010 sps_config->destination = host->sps.bam_handle;
3011 sps_config->mode = SPS_MODE_DEST;
3012 sps_config->options =
3013 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3014 }
3015
3016 /* Producer pipe index */
3017 sps_config->src_pipe_index = host->sps.src_pipe_index;
3018 /* Consumer pipe index */
3019 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3020 /*
3021 * This event thresold value is only significant for BAM-to-BAM
3022 * transfer. It's ignored for BAM-to-System mode transfer.
3023 */
3024 sps_config->event_thresh = 0x10;
3025 /*
3026 * Max. no of scatter/gather buffers that can
3027 * be passed by block layer = 32 (NR_SG).
3028 * Each BAM descritor needs 64 bits (8 bytes).
3029 * One BAM descriptor is required per buffer transfer.
3030 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3031 * But due to HW limitation we need to allocate atleast one extra
3032 * descriptor memory (256 bytes + 8 bytes). But in order to be
3033 * in power of 2, we are allocating 512 bytes of memory.
3034 */
3035 sps_config->desc.size = 512;
3036 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3037 sps_config->desc.size,
3038 &sps_config->desc.phys_base,
3039 GFP_KERNEL);
3040
Pratibhasagar V00b94332011-10-18 14:57:27 +05303041 if (!sps_config->desc.base) {
3042 rc = -ENOMEM;
3043 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3044 , mmc_hostname(host->mmc));
3045 goto get_config_err;
3046 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003047 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3048
3049 /* Establish connection between peripheral and memory endpoint */
3050 rc = sps_connect(sps_pipe_handle, sps_config);
3051 if (rc) {
3052 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3053 " rc=%d", mmc_hostname(host->mmc),
3054 (u32)sps_pipe_handle, rc);
3055 goto sps_connect_err;
3056 }
3057
3058 sps_event->mode = SPS_TRIGGER_CALLBACK;
3059 sps_event->options = SPS_O_EOT;
3060 sps_event->callback = msmsdcc_sps_complete_cb;
3061 sps_event->xfer_done = NULL;
3062 sps_event->user = (void *)host;
3063
3064 /* Register callback event for EOT (End of transfer) event. */
3065 rc = sps_register_event(sps_pipe_handle, sps_event);
3066 if (rc) {
3067 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3068 " rc=%d", mmc_hostname(host->mmc),
3069 (u32)sps_pipe_handle, rc);
3070 goto reg_event_err;
3071 }
3072 /* Now save the sps pipe handle */
3073 ep->pipe_handle = sps_pipe_handle;
3074 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3075 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3076 __func__, is_producer ? "READ" : "WRITE",
3077 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3078 goto out;
3079
3080reg_event_err:
3081 sps_disconnect(sps_pipe_handle);
3082sps_connect_err:
3083 dma_free_coherent(mmc_dev(host->mmc),
3084 sps_config->desc.size,
3085 sps_config->desc.base,
3086 sps_config->desc.phys_base);
3087get_config_err:
3088 sps_free_endpoint(sps_pipe_handle);
3089out:
3090 return rc;
3091}
3092
3093/**
3094 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3095 *
3096 * This function disconnect endpoint and deallocates
3097 * endpoint context.
3098 *
3099 * This function should only be called once typically
3100 * during driver remove.
3101 *
3102 * @host - Pointer to sdcc host structure
3103 * @ep - Pointer to sps endpoint data structure
3104 *
3105 */
3106static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3107 struct msmsdcc_sps_ep_conn_data *ep)
3108{
3109 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3110 struct sps_connect *sps_config = &ep->config;
3111 struct sps_register_event *sps_event = &ep->event;
3112
3113 sps_event->xfer_done = NULL;
3114 sps_event->callback = NULL;
3115 sps_register_event(sps_pipe_handle, sps_event);
3116 sps_disconnect(sps_pipe_handle);
3117 dma_free_coherent(mmc_dev(host->mmc),
3118 sps_config->desc.size,
3119 sps_config->desc.base,
3120 sps_config->desc.phys_base);
3121 sps_free_endpoint(sps_pipe_handle);
3122}
3123
3124/**
3125 * Reset SDCC peripheral's SPS endpoint
3126 *
3127 * This function disconnects an endpoint.
3128 *
3129 * This function should be called for reseting
3130 * SPS endpoint when data transfer error is
3131 * encountered during data transfer. This
3132 * can be considered as soft reset to endpoint.
3133 *
3134 * This function should only be called if
3135 * msmsdcc_sps_init() is already called.
3136 *
3137 * @host - Pointer to sdcc host structure
3138 * @ep - Pointer to sps endpoint data structure
3139 *
3140 * @return - 0 if successful else negative value.
3141 */
3142static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3143 struct msmsdcc_sps_ep_conn_data *ep)
3144{
3145 int rc = 0;
3146 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3147
3148 rc = sps_disconnect(sps_pipe_handle);
3149 if (rc) {
3150 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3151 " rc=%d", mmc_hostname(host->mmc), __func__,
3152 (u32)sps_pipe_handle, rc);
3153 goto out;
3154 }
3155 out:
3156 return rc;
3157}
3158
3159/**
3160 * Restore SDCC peripheral's SPS endpoint
3161 *
3162 * This function connects an endpoint.
3163 *
3164 * This function should be called for restoring
3165 * SPS endpoint after data transfer error is
3166 * encountered during data transfer. This
3167 * can be considered as soft reset to endpoint.
3168 *
3169 * This function should only be called if
3170 * msmsdcc_sps_reset_ep() is called before.
3171 *
3172 * @host - Pointer to sdcc host structure
3173 * @ep - Pointer to sps endpoint data structure
3174 *
3175 * @return - 0 if successful else negative value.
3176 */
3177static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3178 struct msmsdcc_sps_ep_conn_data *ep)
3179{
3180 int rc = 0;
3181 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3182 struct sps_connect *sps_config = &ep->config;
3183 struct sps_register_event *sps_event = &ep->event;
3184
3185 /* Establish connection between peripheral and memory endpoint */
3186 rc = sps_connect(sps_pipe_handle, sps_config);
3187 if (rc) {
3188 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3189 " rc=%d", mmc_hostname(host->mmc), __func__,
3190 (u32)sps_pipe_handle, rc);
3191 goto out;
3192 }
3193
3194 /* Register callback event for EOT (End of transfer) event. */
3195 rc = sps_register_event(sps_pipe_handle, sps_event);
3196 if (rc) {
3197 pr_err("%s: %s: sps_register_event() failed!!!"
3198 " pipe_handle=0x%x, rc=%d",
3199 mmc_hostname(host->mmc), __func__,
3200 (u32)sps_pipe_handle, rc);
3201 goto reg_event_err;
3202 }
3203 goto out;
3204
3205reg_event_err:
3206 sps_disconnect(sps_pipe_handle);
3207out:
3208 return rc;
3209}
3210
3211/**
3212 * Initialize SPS HW connected with SDCC core
3213 *
3214 * This function register BAM HW resources with
3215 * SPS driver and then initialize 2 SPS endpoints
3216 *
3217 * This function should only be called once typically
3218 * during driver probe.
3219 *
3220 * @host - Pointer to sdcc host structure
3221 *
3222 * @return - 0 if successful else negative value.
3223 *
3224 */
3225static int msmsdcc_sps_init(struct msmsdcc_host *host)
3226{
3227 int rc = 0;
3228 struct sps_bam_props bam = {0};
3229
3230 host->bam_base = ioremap(host->bam_memres->start,
3231 resource_size(host->bam_memres));
3232 if (!host->bam_base) {
3233 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3234 " size=0x%x", mmc_hostname(host->mmc),
3235 host->bam_memres->start,
3236 (host->bam_memres->end -
3237 host->bam_memres->start));
3238 rc = -ENOMEM;
3239 goto out;
3240 }
3241
3242 bam.phys_addr = host->bam_memres->start;
3243 bam.virt_addr = host->bam_base;
3244 /*
3245 * This event thresold value is only significant for BAM-to-BAM
3246 * transfer. It's ignored for BAM-to-System mode transfer.
3247 */
3248 bam.event_threshold = 0x10; /* Pipe event threshold */
3249 /*
3250 * This threshold controls when the BAM publish
3251 * the descriptor size on the sideband interface.
3252 * SPS HW will only be used when
3253 * data transfer size > MCI_FIFOSIZE (64 bytes).
3254 * PIO mode will be used when
3255 * data transfer size < MCI_FIFOSIZE (64 bytes).
3256 * So set this thresold value to 64 bytes.
3257 */
3258 bam.summing_threshold = 64;
3259 /* SPS driver wll handle the SDCC BAM IRQ */
3260 bam.irq = (u32)host->bam_irqres->start;
3261 bam.manage = SPS_BAM_MGR_LOCAL;
3262
3263 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3264 (u32)bam.phys_addr);
3265 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3266 (u32)bam.virt_addr);
3267
3268 /* Register SDCC Peripheral BAM device to SPS driver */
3269 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3270 if (rc) {
3271 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3272 mmc_hostname(host->mmc), rc);
3273 goto reg_bam_err;
3274 }
3275 pr_info("%s: BAM device registered. bam_handle=0x%x",
3276 mmc_hostname(host->mmc), host->sps.bam_handle);
3277
3278 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3279 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3280
3281 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3282 SPS_PROD_PERIPHERAL);
3283 if (rc)
3284 goto sps_reset_err;
3285 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3286 SPS_CONS_PERIPHERAL);
3287 if (rc)
3288 goto cons_conn_err;
3289
3290 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3291 mmc_hostname(host->mmc),
3292 (unsigned long long)host->bam_memres->start,
3293 (unsigned int)host->bam_irqres->start);
3294 goto out;
3295
3296cons_conn_err:
3297 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3298sps_reset_err:
3299 sps_deregister_bam_device(host->sps.bam_handle);
3300reg_bam_err:
3301 iounmap(host->bam_base);
3302out:
3303 return rc;
3304}
3305
3306/**
3307 * De-initialize SPS HW connected with SDCC core
3308 *
3309 * This function deinitialize SPS endpoints and then
3310 * deregisters BAM resources from SPS driver.
3311 *
3312 * This function should only be called once typically
3313 * during driver remove.
3314 *
3315 * @host - Pointer to sdcc host structure
3316 *
3317 */
3318static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3319{
3320 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3321 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3322 sps_deregister_bam_device(host->sps.bam_handle);
3323 iounmap(host->bam_base);
3324}
3325#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3326
3327static ssize_t
3328show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3329{
3330 struct mmc_host *mmc = dev_get_drvdata(dev);
3331 struct msmsdcc_host *host = mmc_priv(mmc);
3332 int poll;
3333 unsigned long flags;
3334
3335 spin_lock_irqsave(&host->lock, flags);
3336 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3337 spin_unlock_irqrestore(&host->lock, flags);
3338
3339 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3340}
3341
3342static ssize_t
3343set_polling(struct device *dev, struct device_attribute *attr,
3344 const char *buf, size_t count)
3345{
3346 struct mmc_host *mmc = dev_get_drvdata(dev);
3347 struct msmsdcc_host *host = mmc_priv(mmc);
3348 int value;
3349 unsigned long flags;
3350
3351 sscanf(buf, "%d", &value);
3352
3353 spin_lock_irqsave(&host->lock, flags);
3354 if (value) {
3355 mmc->caps |= MMC_CAP_NEEDS_POLL;
3356 mmc_detect_change(host->mmc, 0);
3357 } else {
3358 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3359 }
3360#ifdef CONFIG_HAS_EARLYSUSPEND
3361 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3362#endif
3363 spin_unlock_irqrestore(&host->lock, flags);
3364 return count;
3365}
3366
3367static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3368 show_polling, set_polling);
3369static struct attribute *dev_attrs[] = {
3370 &dev_attr_polling.attr,
3371 NULL,
3372};
3373static struct attribute_group dev_attr_grp = {
3374 .attrs = dev_attrs,
3375};
3376
3377#ifdef CONFIG_HAS_EARLYSUSPEND
3378static void msmsdcc_early_suspend(struct early_suspend *h)
3379{
3380 struct msmsdcc_host *host =
3381 container_of(h, struct msmsdcc_host, early_suspend);
3382 unsigned long flags;
3383
3384 spin_lock_irqsave(&host->lock, flags);
3385 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3386 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3387 spin_unlock_irqrestore(&host->lock, flags);
3388};
3389static void msmsdcc_late_resume(struct early_suspend *h)
3390{
3391 struct msmsdcc_host *host =
3392 container_of(h, struct msmsdcc_host, early_suspend);
3393 unsigned long flags;
3394
3395 if (host->polling_enabled) {
3396 spin_lock_irqsave(&host->lock, flags);
3397 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3398 mmc_detect_change(host->mmc, 0);
3399 spin_unlock_irqrestore(&host->lock, flags);
3400 }
3401};
3402#endif
3403
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303404void msmsdcc_print_regs(const char *name, void __iomem *base,
3405 unsigned int no_of_regs)
3406{
3407 unsigned int i;
3408
3409 if (!base)
3410 return;
3411 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3412 name, (u32)base);
3413 for (i = 0; i < no_of_regs; i = i + 4) {
3414 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3415 (u32)readl_relaxed(base + i*4),
3416 (u32)readl_relaxed(base + ((i+1)*4)),
3417 (u32)readl_relaxed(base + ((i+2)*4)),
3418 (u32)readl_relaxed(base + ((i+3)*4)));
3419 }
3420}
3421
3422static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3423{
3424 /* Dump current state of SDCC clocks, power and irq */
3425 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3426 (host->pwr ? "ON" : "OFF"));
3427 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3428 mmc_hostname(host->mmc),
3429 (host->clks_on ? "ON" : "OFF"),
3430 (u32)clk_get_rate(host->clk));
3431 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3432 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3433
3434 /* Now dump SDCC registers. Don't print FIFO registers */
3435 if (host->clks_on)
3436 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3437
3438 if (host->curr.data) {
3439 if (msmsdcc_check_dma_op_req(host->curr.data))
3440 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3441 else if (host->is_dma_mode)
3442 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3443 mmc_hostname(host->mmc), host->dma.busy,
3444 host->dma.channel, host->dma.crci);
3445 else if (host->is_sps_mode)
3446 pr_info("%s: SPS mode: busy=%d\n",
3447 mmc_hostname(host->mmc), host->sps.busy);
3448
3449 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3450 mmc_hostname(host->mmc), host->curr.xfer_size,
3451 host->curr.data_xfered, host->curr.xfer_remain);
3452 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3453 " wait_for_auto_prog_done=%d,"
3454 " got_auto_prog_done=%d\n",
3455 mmc_hostname(host->mmc), host->curr.got_dataend,
3456 host->prog_enable, host->curr.wait_for_auto_prog_done,
3457 host->curr.got_auto_prog_done);
3458 }
3459
3460}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3462{
3463 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3464 struct mmc_request *mrq;
3465 unsigned long flags;
3466
3467 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003468 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003469 pr_info("%s: %s: dummy CMD52 timeout\n",
3470 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003471 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 }
3473
3474 mrq = host->curr.mrq;
3475
3476 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303477 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3478 mrq->cmd->opcode);
3479 msmsdcc_dump_sdcc_state(host);
3480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481 if (!mrq->cmd->error)
3482 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303483 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485 if (mrq->data && !mrq->data->error)
3486 mrq->data->error = -ETIMEDOUT;
3487 host->curr.data_xfered = 0;
3488 if (host->dma.sg && host->is_dma_mode) {
3489 msm_dmov_stop_cmd(host->dma.channel,
3490 &host->dma.hdr, 0);
3491 } else if (host->sps.sg && host->is_sps_mode) {
3492 /* Stop current SPS transfer */
3493 msmsdcc_sps_exit_curr_xfer(host);
3494 } else {
3495 msmsdcc_reset_and_restore(host);
3496 msmsdcc_stop_data(host);
3497 if (mrq->data && mrq->data->stop)
3498 msmsdcc_start_command(host,
3499 mrq->data->stop, 0);
3500 else
3501 msmsdcc_request_end(host, mrq);
3502 }
3503 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303504 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 msmsdcc_reset_and_restore(host);
3506 msmsdcc_request_end(host, mrq);
3507 }
3508 }
3509 spin_unlock_irqrestore(&host->lock, flags);
3510}
3511
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303512static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3513{
3514 int i, ret;
3515 struct mmc_platform_data *pdata;
3516 struct device_node *np = dev->of_node;
3517 u32 bus_width = 0;
3518 u32 *clk_table;
3519 int clk_table_len;
3520 u32 *sup_voltages;
3521 int sup_volt_len;
3522
3523 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3524 if (!pdata) {
3525 dev_err(dev, "could not allocate memory for platform data\n");
3526 goto err;
3527 }
3528
3529 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3530 if (bus_width == 8) {
3531 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3532 } else if (bus_width == 4) {
3533 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3534 } else {
3535 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3536 pdata->mmc_bus_width = 0;
3537 }
3538
3539 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3540 size_t sz;
3541 sz = sup_volt_len / sizeof(*sup_voltages);
3542 if (sz > 0) {
3543 sup_voltages = devm_kzalloc(dev,
3544 sz * sizeof(*sup_voltages), GFP_KERNEL);
3545 if (!sup_voltages) {
3546 dev_err(dev, "No memory for supported voltage\n");
3547 goto err;
3548 }
3549
3550 ret = of_property_read_u32_array(np,
3551 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3552 if (ret < 0) {
3553 dev_err(dev, "error while reading voltage"
3554 "ranges %d\n", ret);
3555 goto err;
3556 }
3557 } else {
3558 dev_err(dev, "No supported voltages\n");
3559 goto err;
3560 }
3561 for (i = 0; i < sz; i += 2) {
3562 u32 mask;
3563
3564 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3565 sup_voltages[i + 1]);
3566 if (!mask)
3567 dev_err(dev, "Invalide voltage range %d\n", i);
3568 pdata->ocr_mask |= mask;
3569 }
3570 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3571 } else {
3572 dev_err(dev, "Supported voltage range not specified\n");
3573 }
3574
3575 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3576 size_t sz;
3577 sz = clk_table_len / sizeof(*clk_table);
3578
3579 if (sz > 0) {
3580 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3581 GFP_KERNEL);
3582 if (!clk_table) {
3583 dev_err(dev, "No memory for clock table\n");
3584 goto err;
3585 }
3586
3587 ret = of_property_read_u32_array(np,
3588 "qcom,sdcc-clk-rates", clk_table, sz);
3589 if (ret < 0) {
3590 dev_err(dev, "error while reading clk"
3591 "table %d\n", ret);
3592 goto err;
3593 }
3594 } else {
3595 dev_err(dev, "clk_table not specified\n");
3596 goto err;
3597 }
3598 pdata->sup_clk_table = clk_table;
3599 pdata->sup_clk_cnt = sz;
3600 } else {
3601 dev_err(dev, "Supported clock rates not specified\n");
3602 }
3603
3604 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3605 pdata->nonremovable = true;
3606 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3607 pdata->disable_cmd23 = true;
3608
3609 return pdata;
3610err:
3611 return NULL;
3612}
3613
San Mehat9d2bd732009-09-22 16:44:22 -07003614static int
3615msmsdcc_probe(struct platform_device *pdev)
3616{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303617 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003618 struct msmsdcc_host *host;
3619 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 unsigned long flags;
3621 struct resource *core_irqres = NULL;
3622 struct resource *bam_irqres = NULL;
3623 struct resource *core_memres = NULL;
3624 struct resource *dml_memres = NULL;
3625 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003626 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003627 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303628 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003630
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303631 if (pdev->dev.of_node) {
3632 plat = msmsdcc_populate_pdata(&pdev->dev);
3633 of_property_read_u32((&pdev->dev)->of_node,
3634 "cell-index", &pdev->id);
3635 } else {
3636 plat = pdev->dev.platform_data;
3637 }
3638
San Mehat9d2bd732009-09-22 16:44:22 -07003639 /* must have platform data */
3640 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003641 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003642 ret = -EINVAL;
3643 goto out;
3644 }
3645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003647 return -EINVAL;
3648
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303649 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3650 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3651 return -EINVAL;
3652 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653
San Mehat9d2bd732009-09-22 16:44:22 -07003654 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003655 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003656 return -ENXIO;
3657 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303658 if (pdev->dev.of_node) {
3659 /*
3660 * Device tree iomem resources are only accessible by index.
3661 * index = 0 -> SDCC register interface
3662 * index = 1 -> DML register interface
3663 * index = 2 -> BAM register interface
3664 * IRQ resources:
3665 * index = 0 -> SDCC IRQ
3666 * index = 1 -> BAM IRQ
3667 */
3668 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3669 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3670 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3671 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3672 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3673 } else {
3674 for (i = 0; i < pdev->num_resources; i++) {
3675 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3676 if (!strncmp(pdev->resource[i].name,
3677 "sdcc_dml_addr",
3678 sizeof("sdcc_dml_addr")))
3679 dml_memres = &pdev->resource[i];
3680 else if (!strncmp(pdev->resource[i].name,
3681 "sdcc_bam_addr",
3682 sizeof("sdcc_bam_addr")))
3683 bam_memres = &pdev->resource[i];
3684 else
3685 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003686
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303687 }
3688 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3689 if (!strncmp(pdev->resource[i].name,
3690 "sdcc_bam_irq",
3691 sizeof("sdcc_bam_irq")))
3692 bam_irqres = &pdev->resource[i];
3693 else
3694 core_irqres = &pdev->resource[i];
3695 }
3696 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3697 if (!strncmp(pdev->resource[i].name,
3698 "sdcc_dma_chnl",
3699 sizeof("sdcc_dma_chnl")))
3700 dmares = &pdev->resource[i];
3701 else if (!strncmp(pdev->resource[i].name,
3702 "sdcc_dma_crci",
3703 sizeof("sdcc_dma_crci")))
3704 dma_crci_res = &pdev->resource[i];
3705 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003706 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707 }
3708
3709 if (!core_irqres || !core_memres) {
3710 pr_err("%s: Invalid sdcc core resource\n", __func__);
3711 return -ENXIO;
3712 }
3713
3714 /*
3715 * Both BAM and DML memory resource should be preset.
3716 * BAM IRQ resource should also be present.
3717 */
3718 if ((bam_memres && !dml_memres) ||
3719 (!bam_memres && dml_memres) ||
3720 ((bam_memres && dml_memres) && !bam_irqres)) {
3721 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003722 return -ENXIO;
3723 }
3724
3725 /*
3726 * Setup our host structure
3727 */
San Mehat9d2bd732009-09-22 16:44:22 -07003728 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3729 if (!mmc) {
3730 ret = -ENOMEM;
3731 goto out;
3732 }
3733
3734 host = mmc_priv(mmc);
3735 host->pdev_id = pdev->id;
3736 host->plat = plat;
3737 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003738 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303739
3740 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003741 host->is_sps_mode = 1;
3742 else if (dmares)
3743 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003745 host->base = ioremap(core_memres->start,
3746 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003747 if (!host->base) {
3748 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003750 }
3751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 host->core_irqres = core_irqres;
3753 host->bam_irqres = bam_irqres;
3754 host->core_memres = core_memres;
3755 host->dml_memres = dml_memres;
3756 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003757 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003758 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003759 spin_lock_init(&host->lock);
3760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761#ifdef CONFIG_MMC_EMBEDDED_SDIO
3762 if (plat->embedded_sdio)
3763 mmc_set_embedded_sdio_data(mmc,
3764 &plat->embedded_sdio->cis,
3765 &plat->embedded_sdio->cccr,
3766 plat->embedded_sdio->funcs,
3767 plat->embedded_sdio->num_funcs);
3768#endif
3769
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303770 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3771 (unsigned long)host);
3772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3774 (unsigned long)host);
3775 if (host->is_dma_mode) {
3776 /* Setup DMA */
3777 ret = msmsdcc_init_dma(host);
3778 if (ret)
3779 goto ioremap_free;
3780 } else {
3781 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003782 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003783 }
3784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785 /*
3786 * Setup SDCC clock if derived from Dayatona
3787 * fabric core clock.
3788 */
3789 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003790 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791 if (!IS_ERR(host->dfab_pclk)) {
3792 /* Set the clock rate to 64MHz for max. performance */
3793 ret = clk_set_rate(host->dfab_pclk, 64000000);
3794 if (ret)
3795 goto dfab_pclk_put;
3796 ret = clk_enable(host->dfab_pclk);
3797 if (ret)
3798 goto dfab_pclk_put;
3799 } else
3800 goto dma_free;
3801 }
3802
3803 /*
3804 * Setup main peripheral bus clock
3805 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003806 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807 if (!IS_ERR(host->pclk)) {
3808 ret = clk_enable(host->pclk);
3809 if (ret)
3810 goto pclk_put;
3811
3812 host->pclk_rate = clk_get_rate(host->pclk);
3813 }
3814
3815 /*
3816 * Setup SDC MMC clock
3817 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003818 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003819 if (IS_ERR(host->clk)) {
3820 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003822 }
3823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3825 if (ret) {
3826 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3827 goto clk_put;
3828 }
3829
3830 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003831 if (ret)
3832 goto clk_put;
3833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003834 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303835 if (!host->clk_rate)
3836 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303837
3838 /*
3839 * Lookup the Controller Version, to identify the supported features
3840 * Version number read as 0 would indicate SDCC3 or earlier versions
3841 */
3842 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3843 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3844 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303845 /*
3846 * Set the register write delay according to min. clock frequency
3847 * supported and update later when the host->clk_rate changes.
3848 */
3849 host->reg_write_delay =
3850 (1 + ((3 * USEC_PER_SEC) /
3851 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852
3853 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303854 /* Apply Hard reset to SDCC to put it in power on default state */
3855 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856
3857 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003858 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003860 goto clk_disable;
3861 }
3862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863
3864 /* Clocks has to be running before accessing SPS/DML HW blocks */
3865 if (host->is_sps_mode) {
3866 /* Initialize SPS */
3867 ret = msmsdcc_sps_init(host);
3868 if (ret)
3869 goto vreg_deinit;
3870 /* Initialize DML */
3871 ret = msmsdcc_dml_init(host);
3872 if (ret)
3873 goto sps_exit;
3874 }
San Mehat9d2bd732009-09-22 16:44:22 -07003875
San Mehat9d2bd732009-09-22 16:44:22 -07003876 /*
3877 * Setup MMC host structure
3878 */
3879 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003880 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3881 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003882 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3884 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003885
San Mehat9d2bd732009-09-22 16:44:22 -07003886 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303887 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303888
3889 /*
3890 * If we send the CMD23 before multi block write/read command
3891 * then we need not to send CMD12 at the end of the transfer.
3892 * If we don't send the CMD12 then only way to detect the PROG_DONE
3893 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3894 * controller. So let's enable the CMD23 for SDCC4 only.
3895 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303896 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303897 mmc->caps |= MMC_CAP_CMD23;
3898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003899 mmc->caps |= plat->uhs_caps;
3900 /*
3901 * XPC controls the maximum current in the default speed mode of SDXC
3902 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3903 * XPC=1 means 150mA (max.) and speed class is supported.
3904 */
3905 if (plat->xpc_cap)
3906 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3907 MMC_CAP_SET_XPC_180);
3908
3909 if (plat->nonremovable)
3910 mmc->caps |= MMC_CAP_NONREMOVABLE;
3911#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3912 mmc->caps |= MMC_CAP_SDIO_IRQ;
3913#endif
3914
3915 if (plat->is_sdio_al_client)
3916 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003917
Martin K. Petersena36274e2010-09-10 01:33:59 -04003918 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003919 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003921
3922 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3923 mmc->max_seg_size = mmc->max_req_size;
3924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003925 writel_relaxed(0, host->base + MMCIMASK0);
3926 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3929 mb();
3930 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003932 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3933 DRIVER_NAME " (cmd)", host);
3934 if (ret)
3935 goto dml_exit;
3936
3937 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3938 DRIVER_NAME " (pio)", host);
3939 if (ret)
3940 goto irq_free;
3941
3942 /*
3943 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3944 * IRQ is un-necessarily being monitored by MPM (Modem power
3945 * management block) during idle-power collapse. The MPM will be
3946 * configured to monitor the DATA1 GPIO line with level-low trigger
3947 * and thus depending on the GPIO status, it prevents TCXO shutdown
3948 * during idle-power collapse.
3949 */
3950 disable_irq(core_irqres->start);
3951 host->sdcc_irq_disabled = 1;
3952
3953 if (plat->sdiowakeup_irq) {
3954 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3955 mmc_hostname(mmc));
3956 ret = request_irq(plat->sdiowakeup_irq,
3957 msmsdcc_platform_sdiowakeup_irq,
3958 IRQF_SHARED | IRQF_TRIGGER_LOW,
3959 DRIVER_NAME "sdiowakeup", host);
3960 if (ret) {
3961 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3962 plat->sdiowakeup_irq, ret);
3963 goto pio_irq_free;
3964 } else {
3965 spin_lock_irqsave(&host->lock, flags);
3966 if (!host->sdio_irq_disabled) {
3967 disable_irq_nosync(plat->sdiowakeup_irq);
3968 host->sdio_irq_disabled = 1;
3969 }
3970 spin_unlock_irqrestore(&host->lock, flags);
3971 }
3972 }
3973
3974 if (plat->cfg_mpm_sdiowakeup) {
3975 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3976 mmc_hostname(mmc));
3977 }
3978
3979 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3980 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003981 /*
3982 * Setup card detect change
3983 */
3984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003985 if (plat->status || plat->status_gpio) {
3986 if (plat->status)
3987 host->oldstat = plat->status(mmc_dev(host->mmc));
3988 else
3989 host->oldstat = msmsdcc_slot_status(host);
3990 host->eject = !host->oldstat;
3991 }
San Mehat9d2bd732009-09-22 16:44:22 -07003992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003993 if (plat->status_irq) {
3994 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003995 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003996 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07003997 DRIVER_NAME " (slot)",
3998 host);
3999 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004000 pr_err("Unable to get slot IRQ %d (%d)\n",
4001 plat->status_irq, ret);
4002 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004003 }
4004 } else if (plat->register_status_notify) {
4005 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4006 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004007 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004008 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004009
4010 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004011
4012 ret = pm_runtime_set_active(&(pdev)->dev);
4013 if (ret < 0)
4014 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4015 __func__, ret);
4016 /*
4017 * There is no notion of suspend/resume for SD/MMC/SDIO
4018 * cards. So host can be suspended/resumed with out
4019 * worrying about its children.
4020 */
4021 pm_suspend_ignore_children(&(pdev)->dev, true);
4022
4023 /*
4024 * MMC/SD/SDIO bus suspend/resume operations are defined
4025 * only for the slots that will be used for non-removable
4026 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4027 * defined. Otherwise, they simply become card removal and
4028 * insertion events during suspend and resume respectively.
4029 * Hence, enable run-time PM only for slots for which bus
4030 * suspend/resume operations are defined.
4031 */
4032#ifdef CONFIG_MMC_UNSAFE_RESUME
4033 /*
4034 * If this capability is set, MMC core will enable/disable host
4035 * for every claim/release operation on a host. We use this
4036 * notification to increment/decrement runtime pm usage count.
4037 */
4038 mmc->caps |= MMC_CAP_DISABLE;
4039 pm_runtime_enable(&(pdev)->dev);
4040#else
4041 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4042 mmc->caps |= MMC_CAP_DISABLE;
4043 pm_runtime_enable(&(pdev)->dev);
4044 }
4045#endif
4046 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4047 (unsigned long)host);
4048
San Mehat9d2bd732009-09-22 16:44:22 -07004049 mmc_add_host(mmc);
4050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051#ifdef CONFIG_HAS_EARLYSUSPEND
4052 host->early_suspend.suspend = msmsdcc_early_suspend;
4053 host->early_suspend.resume = msmsdcc_late_resume;
4054 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4055 register_early_suspend(&host->early_suspend);
4056#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004057
Krishna Konda25786ec2011-07-25 16:21:36 -07004058 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4059 " dmacrcri %d\n", mmc_hostname(mmc),
4060 (unsigned long long)core_memres->start,
4061 (unsigned int) core_irqres->start,
4062 (unsigned int) plat->status_irq, host->dma.channel,
4063 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064
4065 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4066 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4067 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4068 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4069 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4070 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4071 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4072 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4073 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4074 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4075 host->eject);
4076 pr_info("%s: Power save feature enable = %d\n",
4077 mmc_hostname(mmc), msmsdcc_pwrsave);
4078
Krishna Konda25786ec2011-07-25 16:21:36 -07004079 if (host->is_dma_mode && host->dma.channel != -1
4080 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004081 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004083 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084 mmc_hostname(mmc), host->dma.cmd_busaddr,
4085 host->dma.cmdptr_busaddr);
4086 } else if (host->is_sps_mode) {
4087 pr_info("%s: SPS-BAM data transfer mode available\n",
4088 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004089 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004090 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004092#if defined(CONFIG_DEBUG_FS)
4093 msmsdcc_dbg_createhost(host);
4094#endif
4095 if (!plat->status_irq) {
4096 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4097 if (ret)
4098 goto platform_irq_free;
4099 }
San Mehat9d2bd732009-09-22 16:44:22 -07004100 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004101
4102 platform_irq_free:
4103 del_timer_sync(&host->req_tout_timer);
4104 pm_runtime_disable(&(pdev)->dev);
4105 pm_runtime_set_suspended(&(pdev)->dev);
4106
4107 if (plat->status_irq)
4108 free_irq(plat->status_irq, host);
4109 sdiowakeup_irq_free:
4110 wake_lock_destroy(&host->sdio_suspend_wlock);
4111 if (plat->sdiowakeup_irq)
4112 free_irq(plat->sdiowakeup_irq, host);
4113 pio_irq_free:
4114 if (plat->sdiowakeup_irq)
4115 wake_lock_destroy(&host->sdio_wlock);
4116 free_irq(core_irqres->start, host);
4117 irq_free:
4118 free_irq(core_irqres->start, host);
4119 dml_exit:
4120 if (host->is_sps_mode)
4121 msmsdcc_dml_exit(host);
4122 sps_exit:
4123 if (host->is_sps_mode)
4124 msmsdcc_sps_exit(host);
4125 vreg_deinit:
4126 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004127 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004129 clk_put:
4130 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 pclk_disable:
4132 if (!IS_ERR(host->pclk))
4133 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004134 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004135 if (!IS_ERR(host->pclk))
4136 clk_put(host->pclk);
4137 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4138 clk_disable(host->dfab_pclk);
4139 dfab_pclk_put:
4140 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4141 clk_put(host->dfab_pclk);
4142 dma_free:
4143 if (host->is_dma_mode) {
4144 if (host->dmares)
4145 dma_free_coherent(NULL,
4146 sizeof(struct msmsdcc_nc_dmadata),
4147 host->dma.nc, host->dma.nc_busaddr);
4148 }
4149 ioremap_free:
4150 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004151 host_free:
4152 mmc_free_host(mmc);
4153 out:
4154 return ret;
4155}
4156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004158{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4160 struct mmc_platform_data *plat;
4161 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163 if (!mmc)
4164 return -ENXIO;
4165
4166 if (pm_runtime_suspended(&(pdev)->dev))
4167 pm_runtime_resume(&(pdev)->dev);
4168
4169 host = mmc_priv(mmc);
4170
4171 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4172 plat = host->plat;
4173
4174 if (!plat->status_irq)
4175 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4176
4177 del_timer_sync(&host->req_tout_timer);
4178 tasklet_kill(&host->dma_tlet);
4179 tasklet_kill(&host->sps.tlet);
4180 mmc_remove_host(mmc);
4181
4182 if (plat->status_irq)
4183 free_irq(plat->status_irq, host);
4184
4185 wake_lock_destroy(&host->sdio_suspend_wlock);
4186 if (plat->sdiowakeup_irq) {
4187 wake_lock_destroy(&host->sdio_wlock);
4188 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4189 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004190 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004191
4192 free_irq(host->core_irqres->start, host);
4193 free_irq(host->core_irqres->start, host);
4194
4195 clk_put(host->clk);
4196 if (!IS_ERR(host->pclk))
4197 clk_put(host->pclk);
4198 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4199 clk_put(host->dfab_pclk);
4200
4201 msmsdcc_vreg_init(host, false);
4202
4203 if (host->is_dma_mode) {
4204 if (host->dmares)
4205 dma_free_coherent(NULL,
4206 sizeof(struct msmsdcc_nc_dmadata),
4207 host->dma.nc, host->dma.nc_busaddr);
4208 }
4209
4210 if (host->is_sps_mode) {
4211 msmsdcc_dml_exit(host);
4212 msmsdcc_sps_exit(host);
4213 }
4214
4215 iounmap(host->base);
4216 mmc_free_host(mmc);
4217
4218#ifdef CONFIG_HAS_EARLYSUSPEND
4219 unregister_early_suspend(&host->early_suspend);
4220#endif
4221 pm_runtime_disable(&(pdev)->dev);
4222 pm_runtime_set_suspended(&(pdev)->dev);
4223
4224 return 0;
4225}
4226
4227#ifdef CONFIG_MSM_SDIO_AL
4228int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4229{
4230 struct msmsdcc_host *host = mmc_priv(mmc);
4231 unsigned long flags;
4232
4233 spin_lock_irqsave(&host->lock, flags);
4234 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4235 enable ? "En" : "Dis");
4236
4237 if (enable) {
4238 if (!host->sdcc_irq_disabled) {
4239 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304240 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004241 host->sdcc_irq_disabled = 1;
4242 }
4243
4244 if (host->clks_on) {
4245 msmsdcc_setup_clocks(host, false);
4246 host->clks_on = 0;
4247 }
4248
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304249 if (host->plat->sdio_lpm_gpio_setup &&
4250 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 spin_unlock_irqrestore(&host->lock, flags);
4252 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4253 spin_lock_irqsave(&host->lock, flags);
4254 host->sdio_gpio_lpm = 1;
4255 }
4256
4257 if (host->sdio_irq_disabled) {
4258 msmsdcc_enable_irq_wake(host);
4259 enable_irq(host->plat->sdiowakeup_irq);
4260 host->sdio_irq_disabled = 0;
4261 }
4262 } else {
4263 if (!host->sdio_irq_disabled) {
4264 disable_irq_nosync(host->plat->sdiowakeup_irq);
4265 host->sdio_irq_disabled = 1;
4266 msmsdcc_disable_irq_wake(host);
4267 }
4268
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304269 if (host->plat->sdio_lpm_gpio_setup &&
4270 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004271 spin_unlock_irqrestore(&host->lock, flags);
4272 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4273 spin_lock_irqsave(&host->lock, flags);
4274 host->sdio_gpio_lpm = 0;
4275 }
4276
4277 if (!host->clks_on) {
4278 msmsdcc_setup_clocks(host, true);
4279 host->clks_on = 1;
4280 }
4281
4282 if (host->sdcc_irq_disabled) {
4283 writel_relaxed(host->mci_irqenable,
4284 host->base + MMCIMASK0);
4285 mb();
4286 enable_irq(host->core_irqres->start);
4287 host->sdcc_irq_disabled = 0;
4288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289 }
4290 spin_unlock_irqrestore(&host->lock, flags);
4291 return 0;
4292}
4293#else
4294int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4295{
4296 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004297}
4298#endif
4299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004300#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004301static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004302msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004303{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304 struct mmc_host *mmc = dev_get_drvdata(dev);
4305 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004306 int rc = 0;
4307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308 if (host->plat->is_sdio_al_client)
4309 return 0;
4310
Sahitya Tummala7661a452011-07-18 13:28:35 +05304311 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004312 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313 host->sdcc_suspending = 1;
4314 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316 /*
4317 * If the clocks are already turned off by SDIO clients (as
4318 * part of LPM), then clocks should be turned on before
4319 * calling mmc_suspend_host() because mmc_suspend_host might
4320 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304321 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004322 * cards, clocks will be turned on before mmc_suspend_host
4323 * and turned off after mmc_suspend_host.
4324 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304325 if (mmc->card && mmc_card_sdio(mmc->card)) {
4326 mmc->ios.clock = host->clk_rate;
4327 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4328 }
San Mehat9d2bd732009-09-22 16:44:22 -07004329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004330 /*
4331 * MMC core thinks that host is disabled by now since
4332 * runtime suspend is scheduled after msmsdcc_disable()
4333 * is called. Thus, MMC core will try to enable the host
4334 * while suspending it. This results in a synchronous
4335 * runtime resume request while in runtime suspending
4336 * context and hence inorder to complete this resume
4337 * requet, it will wait for suspend to be complete,
4338 * but runtime suspend also can not proceed further
4339 * until the host is resumed. Thus, it leads to a hang.
4340 * Hence, increase the pm usage count before suspending
4341 * the host so that any resume requests after this will
4342 * simple become pm usage counter increment operations.
4343 */
4344 pm_runtime_get_noresume(dev);
4345 rc = mmc_suspend_host(mmc);
4346 pm_runtime_put_noidle(dev);
4347
4348 if (!rc) {
4349 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4350 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4351 disable_irq(host->core_irqres->start);
4352 host->sdcc_irq_disabled = 1;
4353
4354 /*
4355 * If MMC core level suspend is not supported,
4356 * turn off clocks to allow deep sleep (TCXO
4357 * shutdown).
4358 */
4359 mmc->ios.clock = 0;
4360 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4361 enable_irq(host->core_irqres->start);
4362 host->sdcc_irq_disabled = 0;
4363
4364 if (host->plat->sdiowakeup_irq) {
4365 host->sdio_irq_disabled = 0;
4366 msmsdcc_enable_irq_wake(host);
4367 enable_irq(host->plat->sdiowakeup_irq);
4368 }
4369 }
4370 }
4371 host->sdcc_suspending = 0;
4372 mmc->suspend_task = NULL;
4373 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4374 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004375 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304376 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004377 return rc;
4378}
4379
4380static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004382{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004383 struct mmc_host *mmc = dev_get_drvdata(dev);
4384 struct msmsdcc_host *host = mmc_priv(mmc);
4385 unsigned long flags;
4386
4387 if (host->plat->is_sdio_al_client)
4388 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004389
Sahitya Tummala7661a452011-07-18 13:28:35 +05304390 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004391 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4393 if (host->sdcc_irq_disabled) {
4394 enable_irq(host->core_irqres->start);
4395 host->sdcc_irq_disabled = 0;
4396 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304397 mmc->ios.clock = host->clk_rate;
4398 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004399
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304400 spin_lock_irqsave(&host->lock, flags);
4401 writel_relaxed(host->mci_irqenable,
4402 host->base + MMCIMASK0);
4403 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004404
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304405 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4406 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004407 if (host->plat->sdiowakeup_irq) {
4408 disable_irq_nosync(
4409 host->plat->sdiowakeup_irq);
4410 msmsdcc_disable_irq_wake(host);
4411 host->sdio_irq_disabled = 1;
4412 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304413 }
San Mehat9d2bd732009-09-22 16:44:22 -07004414
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304415 spin_unlock_irqrestore(&host->lock, flags);
4416 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004417
4418 mmc_resume_host(mmc);
4419
4420 /*
4421 * FIXME: Clearing of flags must be handled in clients
4422 * resume handler.
4423 */
4424 spin_lock_irqsave(&host->lock, flags);
4425 mmc->pm_flags = 0;
4426 spin_unlock_irqrestore(&host->lock, flags);
4427
4428 /*
4429 * After resuming the host wait for sometime so that
4430 * the SDIO work will be processed.
4431 */
4432 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4433 if ((host->plat->cfg_mpm_sdiowakeup ||
4434 host->plat->sdiowakeup_irq) &&
4435 wake_lock_active(&host->sdio_wlock))
4436 wake_lock_timeout(&host->sdio_wlock, 1);
4437 }
4438
4439 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004440 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304441 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004442 return 0;
4443}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004444
4445static int msmsdcc_runtime_idle(struct device *dev)
4446{
4447 struct mmc_host *mmc = dev_get_drvdata(dev);
4448 struct msmsdcc_host *host = mmc_priv(mmc);
4449
4450 if (host->plat->is_sdio_al_client)
4451 return 0;
4452
4453 /* Idle timeout is not configurable for now */
4454 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4455
4456 return -EAGAIN;
4457}
4458
4459static int msmsdcc_pm_suspend(struct device *dev)
4460{
4461 struct mmc_host *mmc = dev_get_drvdata(dev);
4462 struct msmsdcc_host *host = mmc_priv(mmc);
4463 int rc = 0;
4464
4465 if (host->plat->is_sdio_al_client)
4466 return 0;
4467
4468
4469 if (host->plat->status_irq)
4470 disable_irq(host->plat->status_irq);
4471
4472 if (!pm_runtime_suspended(dev))
4473 rc = msmsdcc_runtime_suspend(dev);
4474
4475 return rc;
4476}
4477
4478static int msmsdcc_pm_resume(struct device *dev)
4479{
4480 struct mmc_host *mmc = dev_get_drvdata(dev);
4481 struct msmsdcc_host *host = mmc_priv(mmc);
4482 int rc = 0;
4483
4484 if (host->plat->is_sdio_al_client)
4485 return 0;
4486
Sahitya Tummalafb486372011-09-02 19:01:49 +05304487 if (!pm_runtime_suspended(dev))
4488 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004489 if (host->plat->status_irq) {
4490 msmsdcc_check_status((unsigned long)host);
4491 enable_irq(host->plat->status_irq);
4492 }
4493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494 return rc;
4495}
4496
Daniel Walker08ecfde2010-06-23 12:32:20 -07004497#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004498#define msmsdcc_runtime_suspend NULL
4499#define msmsdcc_runtime_resume NULL
4500#define msmsdcc_runtime_idle NULL
4501#define msmsdcc_pm_suspend NULL
4502#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004503#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4506 .runtime_suspend = msmsdcc_runtime_suspend,
4507 .runtime_resume = msmsdcc_runtime_resume,
4508 .runtime_idle = msmsdcc_runtime_idle,
4509 .suspend = msmsdcc_pm_suspend,
4510 .resume = msmsdcc_pm_resume,
4511};
4512
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304513static const struct of_device_id msmsdcc_dt_match[] = {
4514 {.compatible = "qcom,msm-sdcc"},
4515
4516};
4517MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4518
San Mehat9d2bd732009-09-22 16:44:22 -07004519static struct platform_driver msmsdcc_driver = {
4520 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004521 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004522 .driver = {
4523 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304525 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004526 },
4527};
4528
4529static int __init msmsdcc_init(void)
4530{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004531#if defined(CONFIG_DEBUG_FS)
4532 int ret = 0;
4533 ret = msmsdcc_dbg_init();
4534 if (ret) {
4535 pr_err("Failed to create debug fs dir \n");
4536 return ret;
4537 }
4538#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004539 return platform_driver_register(&msmsdcc_driver);
4540}
4541
4542static void __exit msmsdcc_exit(void)
4543{
4544 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545
4546#if defined(CONFIG_DEBUG_FS)
4547 debugfs_remove(debugfs_file);
4548 debugfs_remove(debugfs_dir);
4549#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004550}
4551
4552module_init(msmsdcc_init);
4553module_exit(msmsdcc_exit);
4554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004555MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004556MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004557
4558#if defined(CONFIG_DEBUG_FS)
4559
4560static int
4561msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4562{
4563 file->private_data = inode->i_private;
4564 return 0;
4565}
4566
4567static ssize_t
4568msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4569 size_t count, loff_t *ppos)
4570{
4571 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4572 char buf[1024];
4573 int max, i;
4574
4575 i = 0;
4576 max = sizeof(buf) - 1;
4577
4578 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4579 host->curr.cmd, host->curr.data);
4580 if (host->curr.cmd) {
4581 struct mmc_command *cmd = host->curr.cmd;
4582
4583 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4584 cmd->opcode, cmd->arg, cmd->flags);
4585 }
4586 if (host->curr.data) {
4587 struct mmc_data *data = host->curr.data;
4588 i += scnprintf(buf + i, max - i,
4589 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4590 data->timeout_ns, data->timeout_clks,
4591 data->blksz, data->blocks, data->error,
4592 data->flags);
4593 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4594 host->curr.xfer_size, host->curr.xfer_remain,
4595 host->curr.data_xfered, host->dma.sg);
4596 }
4597
4598 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4599}
4600
4601static const struct file_operations msmsdcc_dbg_state_ops = {
4602 .read = msmsdcc_dbg_state_read,
4603 .open = msmsdcc_dbg_state_open,
4604};
4605
4606static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4607{
4608 if (debugfs_dir) {
4609 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4610 0644, debugfs_dir, host,
4611 &msmsdcc_dbg_state_ops);
4612 }
4613}
4614
4615static int __init msmsdcc_dbg_init(void)
4616{
4617 int err;
4618
4619 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4620 if (IS_ERR(debugfs_dir)) {
4621 err = PTR_ERR(debugfs_dir);
4622 debugfs_dir = NULL;
4623 return err;
4624 }
4625
4626 return 0;
4627}
4628#endif