blob: 6b856b292965facc49ca501f6d9ea0f87a2c085e [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;
Subhash Jadavani758cf8c2011-11-13 11:59:55 +05301649 } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
1650 host->sdcc_version) {
1651 host->curr.wait_for_auto_prog_done = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652 }
San Mehat9d2bd732009-09-22 16:44:22 -07001653 }
Subhash Jadavani7a651aa2011-08-03 20:44:58 +05301654
Pratibhasagar V00b94332011-10-18 14:57:27 +05301655 if (mrq->data && mrq->sbc) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301656 mrq->sbc->mrq = mrq;
1657 mrq->sbc->data = mrq->data;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301658 if (mrq->data->flags & MMC_DATA_WRITE) {
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301659 host->curr.wait_for_auto_prog_done = 1;
Subhash Jadavani1d6ba602011-09-21 18:10:54 +05301660 msmsdcc_start_command(host, mrq->sbc, 0);
1661 } else {
1662 msmsdcc_request_start(host, mrq);
1663 }
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05301664 } else {
1665 msmsdcc_request_start(host, mrq);
1666 }
1667
San Mehat9d2bd732009-09-22 16:44:22 -07001668 spin_unlock_irqrestore(&host->lock, flags);
1669}
1670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001671static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
1672 int min_uV, int max_uV)
1673{
1674 int rc = 0;
1675
1676 if (vreg->set_voltage_sup) {
1677 rc = regulator_set_voltage(vreg->reg, min_uV, max_uV);
1678 if (rc) {
1679 pr_err("%s: regulator_set_voltage(%s) failed."
1680 " min_uV=%d, max_uV=%d, rc=%d\n",
1681 __func__, vreg->name, min_uV, max_uV, rc);
1682 }
1683 }
1684
1685 return rc;
1686}
1687
1688static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
1689 int uA_load)
1690{
1691 int rc = 0;
1692
Krishna Kondafea60182011-11-01 16:01:34 -07001693 /* regulators that do not support regulator_set_voltage also
1694 do not support regulator_set_optimum_mode */
1695 if (vreg->set_voltage_sup) {
1696 rc = regulator_set_optimum_mode(vreg->reg, uA_load);
1697 if (rc < 0)
1698 pr_err("%s: regulator_set_optimum_mode(reg=%s, "
1699 "uA_load=%d) failed. rc=%d\n", __func__,
1700 vreg->name, uA_load, rc);
1701 else
1702 /* regulator_set_optimum_mode() can return non zero
1703 * value even for success case.
1704 */
1705 rc = 0;
1706 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707
1708 return rc;
1709}
1710
1711static inline int msmsdcc_vreg_init_reg(struct msm_mmc_reg_data *vreg,
1712 struct device *dev)
1713{
1714 int rc = 0;
1715
1716 /* check if regulator is already initialized? */
1717 if (vreg->reg)
1718 goto out;
1719
1720 /* Get the regulator handle */
1721 vreg->reg = regulator_get(dev, vreg->name);
1722 if (IS_ERR(vreg->reg)) {
1723 rc = PTR_ERR(vreg->reg);
1724 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
1725 __func__, vreg->name, rc);
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001726 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 }
Krishna Konda9f7d67e2011-11-07 23:40:13 -08001728
1729 if (regulator_count_voltages(vreg->reg) > 0)
1730 vreg->set_voltage_sup = 1;
1731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732out:
1733 return rc;
1734}
1735
1736static inline void msmsdcc_vreg_deinit_reg(struct msm_mmc_reg_data *vreg)
1737{
1738 if (vreg->reg)
1739 regulator_put(vreg->reg);
1740}
1741
1742/* This init function should be called only once for each SDCC slot */
1743static int msmsdcc_vreg_init(struct msmsdcc_host *host, bool is_init)
1744{
1745 int rc = 0;
1746 struct msm_mmc_slot_reg_data *curr_slot;
1747 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1748 struct device *dev = mmc_dev(host->mmc);
1749
1750 curr_slot = host->plat->vreg_data;
1751 if (!curr_slot)
1752 goto out;
1753
1754 curr_vdd_reg = curr_slot->vdd_data;
1755 curr_vccq_reg = curr_slot->vccq_data;
1756 curr_vddp_reg = curr_slot->vddp_data;
1757
1758 if (is_init) {
1759 /*
1760 * Get the regulator handle from voltage regulator framework
1761 * and then try to set the voltage level for the regulator
1762 */
1763 if (curr_vdd_reg) {
1764 rc = msmsdcc_vreg_init_reg(curr_vdd_reg, dev);
1765 if (rc)
1766 goto out;
1767 }
1768 if (curr_vccq_reg) {
1769 rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
1770 if (rc)
1771 goto vdd_reg_deinit;
1772 }
1773 if (curr_vddp_reg) {
1774 rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
1775 if (rc)
1776 goto vccq_reg_deinit;
1777 }
1778 goto out;
1779 } else {
1780 /* Deregister all regulators from regulator framework */
1781 goto vddp_reg_deinit;
1782 }
1783vddp_reg_deinit:
1784 if (curr_vddp_reg)
1785 msmsdcc_vreg_deinit_reg(curr_vddp_reg);
1786vccq_reg_deinit:
1787 if (curr_vccq_reg)
1788 msmsdcc_vreg_deinit_reg(curr_vccq_reg);
1789vdd_reg_deinit:
1790 if (curr_vdd_reg)
1791 msmsdcc_vreg_deinit_reg(curr_vdd_reg);
1792out:
1793 return rc;
1794}
1795
1796static int msmsdcc_vreg_enable(struct msm_mmc_reg_data *vreg)
1797{
1798 int rc = 0;
1799
Subhash Jadavanicc922692011-08-01 23:05:01 +05301800 /* Put regulator in HPM (high power mode) */
1801 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
1802 if (rc < 0)
1803 goto out;
1804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 if (!vreg->is_enabled) {
1806 /* Set voltage level */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301807 rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
1808 vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 if (rc)
1810 goto out;
1811
1812 rc = regulator_enable(vreg->reg);
1813 if (rc) {
1814 pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
1815 __func__, vreg->name, rc);
1816 goto out;
1817 }
1818 vreg->is_enabled = true;
1819 }
1820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821out:
1822 return rc;
1823}
1824
1825static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
1826{
1827 int rc = 0;
1828
1829 /* Never disable regulator marked as always_on */
1830 if (vreg->is_enabled && !vreg->always_on) {
1831 rc = regulator_disable(vreg->reg);
1832 if (rc) {
1833 pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
1834 __func__, vreg->name, rc);
1835 goto out;
1836 }
1837 vreg->is_enabled = false;
1838
1839 rc = msmsdcc_vreg_set_optimum_mode(vreg, 0);
1840 if (rc < 0)
1841 goto out;
1842
1843 /* Set min. voltage level to 0 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301844 rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 if (rc)
1846 goto out;
1847 } else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
1848 /* Put always_on regulator in LPM (low power mode) */
1849 rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
1850 if (rc < 0)
1851 goto out;
1852 }
1853out:
1854 return rc;
1855}
1856
1857static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
1858{
1859 int rc = 0, i;
1860 struct msm_mmc_slot_reg_data *curr_slot;
1861 struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
1862 struct msm_mmc_reg_data *vreg_table[3];
1863
1864 curr_slot = host->plat->vreg_data;
1865 if (!curr_slot)
1866 goto out;
1867
1868 curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
1869 curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
1870 curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
1871
1872 for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
1873 if (vreg_table[i]) {
1874 if (enable)
1875 rc = msmsdcc_vreg_enable(vreg_table[i]);
1876 else
1877 rc = msmsdcc_vreg_disable(vreg_table[i]);
1878 if (rc)
1879 goto out;
1880 }
1881 }
1882out:
1883 return rc;
1884}
1885
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301886static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887{
1888 int rc = 0;
1889
1890 if (host->plat->vreg_data) {
1891 struct msm_mmc_reg_data *vddp_reg =
1892 host->plat->vreg_data->vddp_data;
1893
1894 if (vddp_reg && vddp_reg->is_enabled)
1895 rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
1896 }
1897
1898 return rc;
1899}
1900
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05301901static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
1902{
1903 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1904 int rc = 0;
1905
1906 if (curr_slot && curr_slot->vddp_data) {
1907 rc = msmsdcc_set_vddp_level(host,
1908 curr_slot->vddp_data->low_vol_level);
1909
1910 if (rc)
1911 pr_err("%s: %s: failed to change vddp level to %d",
1912 mmc_hostname(host->mmc), __func__,
1913 curr_slot->vddp_data->low_vol_level);
1914 }
1915
1916 return rc;
1917}
1918
1919static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
1920{
1921 struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
1922 int rc = 0;
1923
1924 if (curr_slot && curr_slot->vddp_data) {
1925 rc = msmsdcc_set_vddp_level(host,
1926 curr_slot->vddp_data->high_vol_level);
1927
1928 if (rc)
1929 pr_err("%s: %s: failed to change vddp level to %d",
1930 mmc_hostname(host->mmc), __func__,
1931 curr_slot->vddp_data->high_vol_level);
1932 }
1933
1934 return rc;
1935}
1936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
1938{
1939 if (host->clk_rate > 400000 && msmsdcc_pwrsave)
1940 return 1;
1941 return 0;
1942}
1943
1944static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
1945{
1946 if (enable) {
1947 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1948 clk_enable(host->dfab_pclk);
1949 if (!IS_ERR(host->pclk))
1950 clk_enable(host->pclk);
1951 clk_enable(host->clk);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301952 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 } else {
Subhash Jadavani15f29db2011-10-13 09:57:13 +05301954 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955 clk_disable(host->clk);
1956 if (!IS_ERR(host->pclk))
1957 clk_disable(host->pclk);
1958 if (!IS_ERR_OR_NULL(host->dfab_pclk))
1959 clk_disable(host->dfab_pclk);
1960 }
1961}
1962
1963static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
1964 unsigned int req_clk)
1965{
1966 unsigned int sel_clk = -1;
1967
1968 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt) {
1969 unsigned char cnt;
1970
1971 for (cnt = 0; cnt < host->plat->sup_clk_cnt; cnt++) {
1972 if (host->plat->sup_clk_table[cnt] > req_clk)
1973 break;
1974 else if (host->plat->sup_clk_table[cnt] == req_clk) {
1975 sel_clk = host->plat->sup_clk_table[cnt];
1976 break;
1977 } else
1978 sel_clk = host->plat->sup_clk_table[cnt];
1979 }
1980 } else {
1981 if ((req_clk < host->plat->msmsdcc_fmax) &&
1982 (req_clk > host->plat->msmsdcc_fmid))
1983 sel_clk = host->plat->msmsdcc_fmid;
1984 else
1985 sel_clk = req_clk;
1986 }
1987
1988 return sel_clk;
1989}
1990
1991static inline unsigned int msmsdcc_get_min_sup_clk_rate(
1992 struct msmsdcc_host *host)
1993{
1994 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
1995 return host->plat->sup_clk_table[0];
1996 else
1997 return host->plat->msmsdcc_fmin;
1998}
1999
2000static inline unsigned int msmsdcc_get_max_sup_clk_rate(
2001 struct msmsdcc_host *host)
2002{
2003 if (host->plat->sup_clk_table && host->plat->sup_clk_cnt)
2004 return host->plat->sup_clk_table[host->plat->sup_clk_cnt - 1];
2005 else
2006 return host->plat->msmsdcc_fmax;
2007}
2008
2009static int msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
Sahitya Tummala7a892482011-01-18 11:22:49 +05302010{
2011 struct msm_mmc_gpio_data *curr;
2012 int i, rc = 0;
2013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 curr = host->plat->pin_data->gpio_data;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302015 for (i = 0; i < curr->size; i++) {
2016 if (enable) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 if (curr->gpio[i].is_always_on &&
2018 curr->gpio[i].is_enabled)
2019 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302020 rc = gpio_request(curr->gpio[i].no,
2021 curr->gpio[i].name);
2022 if (rc) {
2023 pr_err("%s: gpio_request(%d, %s) failed %d\n",
2024 mmc_hostname(host->mmc),
2025 curr->gpio[i].no,
2026 curr->gpio[i].name, rc);
2027 goto free_gpios;
2028 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 curr->gpio[i].is_enabled = true;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302030 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 if (curr->gpio[i].is_always_on)
2032 continue;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302033 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034 curr->gpio[i].is_enabled = false;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302035 }
2036 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 goto out;
Sahitya Tummala7a892482011-01-18 11:22:49 +05302038
2039free_gpios:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040 for (; i >= 0; i--) {
Sahitya Tummala7a892482011-01-18 11:22:49 +05302041 gpio_free(curr->gpio[i].no);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002042 curr->gpio[i].is_enabled = false;
2043 }
2044out:
2045 return rc;
2046}
2047
2048static int msmsdcc_setup_pad(struct msmsdcc_host *host, bool enable)
2049{
2050 struct msm_mmc_pad_data *curr;
2051 int i;
2052
2053 curr = host->plat->pin_data->pad_data;
2054 for (i = 0; i < curr->drv->size; i++) {
2055 if (enable)
2056 msm_tlmm_set_hdrive(curr->drv->on[i].no,
2057 curr->drv->on[i].val);
2058 else
2059 msm_tlmm_set_hdrive(curr->drv->off[i].no,
2060 curr->drv->off[i].val);
2061 }
2062
2063 for (i = 0; i < curr->pull->size; i++) {
2064 if (enable)
Krishna Konda6ad526f2011-09-22 22:07:27 -07002065 msm_tlmm_set_pull(curr->pull->on[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 curr->pull->on[i].val);
2067 else
Krishna Konda6ad526f2011-09-22 22:07:27 -07002068 msm_tlmm_set_pull(curr->pull->off[i].no,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 curr->pull->off[i].val);
2070 }
2071
2072 return 0;
2073}
2074
2075static u32 msmsdcc_setup_pins(struct msmsdcc_host *host, bool enable)
2076{
2077 int rc = 0;
2078
2079 if (!host->plat->pin_data || host->plat->pin_data->cfg_sts == enable)
2080 return 0;
2081
2082 if (host->plat->pin_data->is_gpio)
2083 rc = msmsdcc_setup_gpio(host, enable);
2084 else
2085 rc = msmsdcc_setup_pad(host, enable);
2086
2087 if (!rc)
2088 host->plat->pin_data->cfg_sts = enable;
2089
2090 return rc;
2091}
2092
2093static void msmsdcc_enable_irq_wake(struct msmsdcc_host *host)
2094{
2095 unsigned int wakeup_irq;
2096
2097 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2098 host->plat->sdiowakeup_irq :
2099 host->core_irqres->start;
2100
2101 if (!host->irq_wake_enabled) {
2102 enable_irq_wake(wakeup_irq);
2103 host->irq_wake_enabled = true;
2104 }
2105}
2106
2107static void msmsdcc_disable_irq_wake(struct msmsdcc_host *host)
2108{
2109 unsigned int wakeup_irq;
2110
2111 wakeup_irq = (host->plat->sdiowakeup_irq) ?
2112 host->plat->sdiowakeup_irq :
2113 host->core_irqres->start;
2114
2115 if (host->irq_wake_enabled) {
2116 disable_irq_wake(wakeup_irq);
2117 host->irq_wake_enabled = false;
2118 }
Sahitya Tummala7a892482011-01-18 11:22:49 +05302119}
2120
San Mehat9d2bd732009-09-22 16:44:22 -07002121static void
2122msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
2123{
2124 struct msmsdcc_host *host = mmc_priv(mmc);
2125 u32 clk = 0, pwr = 0;
2126 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -08002127 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 unsigned int clock;
San Mehat9d2bd732009-09-22 16:44:22 -07002129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 DBG(host, "ios->clock = %u\n", ios->clock);
Sahitya Tummala7a892482011-01-18 11:22:49 +05302131
San Mehat9d2bd732009-09-22 16:44:22 -07002132 if (ios->clock) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 spin_lock_irqsave(&host->lock, flags);
2134 if (!host->clks_on) {
2135 msmsdcc_setup_clocks(host, true);
2136 host->clks_on = 1;
2137 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2138 if (!host->plat->sdiowakeup_irq) {
2139 writel_relaxed(host->mci_irqenable,
2140 host->base + MMCIMASK0);
2141 mb();
2142 if (host->plat->cfg_mpm_sdiowakeup &&
2143 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2144 host->plat->cfg_mpm_sdiowakeup(
2145 mmc_dev(mmc), SDC_DAT1_DISWAKE);
2146 msmsdcc_disable_irq_wake(host);
2147 } else if (!(mmc->pm_flags &
2148 MMC_PM_WAKE_SDIO_IRQ)) {
2149 writel_relaxed(host->mci_irqenable,
2150 host->base + MMCIMASK0);
2151 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05302152 } else {
2153 writel_relaxed(host->mci_irqenable,
2154 host->base + MMCIMASK0);
2155 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 }
San Mehat9d2bd732009-09-22 16:44:22 -07002157 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158 spin_unlock_irqrestore(&host->lock, flags);
2159
2160 clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
2161 /*
2162 * For DDR50 mode, controller needs clock rate to be
2163 * double than what is required on the SD card CLK pin.
2164 */
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302165 if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 /*
2167 * Make sure that we don't double the clock if
2168 * doubled clock rate is already set
2169 */
2170 if (!host->ddr_doubled_clk_rate ||
2171 (host->ddr_doubled_clk_rate &&
2172 (host->ddr_doubled_clk_rate != ios->clock))) {
2173 host->ddr_doubled_clk_rate =
2174 msmsdcc_get_sup_clk_rate(
2175 host, (ios->clock * 2));
2176 clock = host->ddr_doubled_clk_rate;
2177 }
2178 } else {
2179 host->ddr_doubled_clk_rate = 0;
2180 }
2181
2182 if (clock != host->clk_rate) {
2183 rc = clk_set_rate(host->clk, clock);
2184 if (rc < 0)
2185 pr_debug("%s: failed to set clk rate %u\n",
2186 mmc_hostname(mmc), clock);
2187 host->clk_rate = clock;
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05302188 host->reg_write_delay =
2189 (1 + ((3 * USEC_PER_SEC) /
2190 (host->clk_rate ? host->clk_rate :
2191 msmsdcc_get_min_sup_clk_rate(host))));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 }
2193 /*
2194 * give atleast 2 MCLK cycles delay for clocks
2195 * and SDCC core to stabilize
2196 */
2197 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002198 clk |= MCI_CLK_ENABLE;
2199 }
2200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 if (ios->bus_width == MMC_BUS_WIDTH_8)
2202 clk |= MCI_CLK_WIDEBUS_8;
2203 else if (ios->bus_width == MMC_BUS_WIDTH_4)
2204 clk |= MCI_CLK_WIDEBUS_4;
2205 else
2206 clk |= MCI_CLK_WIDEBUS_1;
San Mehat9d2bd732009-09-22 16:44:22 -07002207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 if (msmsdcc_is_pwrsave(host))
2209 clk |= MCI_CLK_PWRSAVE;
San Mehat9d2bd732009-09-22 16:44:22 -07002210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211 clk |= MCI_CLK_FLOWENA;
San Mehat9d2bd732009-09-22 16:44:22 -07002212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 host->tuning_needed = 0;
2214 /*
2215 * Select the controller timing mode according
2216 * to current bus speed mode
2217 */
2218 if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
2219 (ios->timing == MMC_TIMING_UHS_SDR50)) {
2220 clk |= (4 << 14);
2221 host->tuning_needed = 1;
Subhash Jadavani0e027b72011-08-30 17:40:55 +05302222 } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 clk |= (3 << 14);
2224 } else {
2225 clk |= (2 << 14); /* feedback clock */
2226 }
2227
2228 /* Select free running MCLK as input clock of cm_dll_sdc4 */
2229 clk |= (2 << 23);
2230
2231 if (host->io_pad_pwr_switch)
2232 clk |= IO_PAD_PWR_SWITCH;
2233
2234 if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
San Mehat9d2bd732009-09-22 16:44:22 -07002235 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
2237 pwr |= msmsdcc_setup_vreg(host, !!ios->vdd);
San Mehat9d2bd732009-09-22 16:44:22 -07002238
2239 switch (ios->power_mode) {
2240 case MMC_POWER_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 htc_pwrsink_set(PWRSINK_SDCARD, 0);
2242 if (!host->sdcc_irq_disabled) {
2243 if (host->plat->cfg_mpm_sdiowakeup)
2244 host->plat->cfg_mpm_sdiowakeup(
2245 mmc_dev(mmc), SDC_DAT1_DISABLE);
2246 disable_irq(host->core_irqres->start);
2247 host->sdcc_irq_disabled = 1;
2248 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302249 /*
2250 * As VDD pad rail is always on, set low voltage for VDD
2251 * pad rail when slot is unused (when card is not present
2252 * or during system suspend).
2253 */
2254 msmsdcc_set_vddp_low_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 msmsdcc_setup_pins(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07002256 break;
2257 case MMC_POWER_UP:
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302258 /* writing PWR_UP bit is redundant */
San Mehat9d2bd732009-09-22 16:44:22 -07002259 pwr |= MCI_PWR_UP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 if (host->sdcc_irq_disabled) {
2261 if (host->plat->cfg_mpm_sdiowakeup)
2262 host->plat->cfg_mpm_sdiowakeup(
2263 mmc_dev(mmc), SDC_DAT1_ENABLE);
2264 enable_irq(host->core_irqres->start);
2265 host->sdcc_irq_disabled = 0;
2266 }
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302267 msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 msmsdcc_setup_pins(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07002269 break;
2270 case MMC_POWER_ON:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271 htc_pwrsink_set(PWRSINK_SDCARD, 100);
San Mehat9d2bd732009-09-22 16:44:22 -07002272 pwr |= MCI_PWR_ON;
2273 break;
2274 }
2275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 spin_lock_irqsave(&host->lock, flags);
2277 if (!host->clks_on) {
2278 /* force the clocks to be on */
2279 msmsdcc_setup_clocks(host, true);
2280 /*
2281 * give atleast 2 MCLK cycles delay for clocks
2282 * and SDCC core to stabilize
2283 */
2284 msmsdcc_delay(host);
2285 }
2286 writel_relaxed(clk, host->base + MMCICLOCK);
2287 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002288
2289 if (host->pwr != pwr) {
2290 host->pwr = pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 writel_relaxed(pwr, host->base + MMCIPOWER);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302292 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002293 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 if (!host->clks_on) {
2295 /* force the clocks to be off */
2296 msmsdcc_setup_clocks(host, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 }
2298
2299 if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
2300 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
2301 if (!host->plat->sdiowakeup_irq) {
2302 writel_relaxed(MCI_SDIOINTMASK,
2303 host->base + MMCIMASK0);
2304 mb();
2305 if (host->plat->cfg_mpm_sdiowakeup &&
2306 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
2307 host->plat->cfg_mpm_sdiowakeup(
2308 mmc_dev(mmc), SDC_DAT1_ENWAKE);
2309 msmsdcc_enable_irq_wake(host);
2310 } else if (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2311 writel_relaxed(0, host->base + MMCIMASK0);
2312 } else {
2313 writel_relaxed(MCI_SDIOINTMASK,
2314 host->base + MMCIMASK0);
2315 }
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302316 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 }
2318 msmsdcc_setup_clocks(host, false);
2319 host->clks_on = 0;
2320 }
San Mehat4adbbcc2009-11-08 13:00:37 -08002321 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07002322}
2323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave)
2325{
2326 struct msmsdcc_host *host = mmc_priv(mmc);
2327 u32 clk;
2328
2329 clk = readl_relaxed(host->base + MMCICLOCK);
2330 pr_debug("Changing to pwr_save=%d", pwrsave);
2331 if (pwrsave && msmsdcc_is_pwrsave(host))
2332 clk |= MCI_CLK_PWRSAVE;
2333 else
2334 clk &= ~MCI_CLK_PWRSAVE;
2335 writel_relaxed(clk, host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302336 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337
2338 return 0;
2339}
2340
2341static int msmsdcc_get_ro(struct mmc_host *mmc)
2342{
2343 int status = -ENOSYS;
2344 struct msmsdcc_host *host = mmc_priv(mmc);
2345
2346 if (host->plat->wpswitch) {
2347 status = host->plat->wpswitch(mmc_dev(mmc));
2348 } else if (host->plat->wpswitch_gpio) {
2349 status = gpio_request(host->plat->wpswitch_gpio,
2350 "SD_WP_Switch");
2351 if (status) {
2352 pr_err("%s: %s: Failed to request GPIO %d\n",
2353 mmc_hostname(mmc), __func__,
2354 host->plat->wpswitch_gpio);
2355 } else {
2356 status = gpio_direction_input(
2357 host->plat->wpswitch_gpio);
2358 if (!status) {
2359 /*
2360 * Wait for atleast 300ms as debounce
2361 * time for GPIO input to stabilize.
2362 */
2363 msleep(300);
2364 status = gpio_get_value_cansleep(
2365 host->plat->wpswitch_gpio);
2366 status ^= !host->plat->wpswitch_polarity;
2367 }
2368 gpio_free(host->plat->wpswitch_gpio);
2369 }
2370 }
2371
2372 if (status < 0)
2373 status = -ENOSYS;
2374 pr_debug("%s: Card read-only status %d\n", __func__, status);
2375
2376 return status;
2377}
2378
2379#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002380static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
2381{
2382 struct msmsdcc_host *host = mmc_priv(mmc);
2383 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002384
2385 if (enable) {
2386 spin_lock_irqsave(&host->lock, flags);
2387 host->mci_irqenable |= MCI_SDIOINTOPERMASK;
2388 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
2389 MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2390 spin_unlock_irqrestore(&host->lock, flags);
2391 } else {
2392 host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
2393 writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
2394 ~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
2395 }
2396 mb();
2397}
2398#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
2399
2400#ifdef CONFIG_PM_RUNTIME
2401static int msmsdcc_enable(struct mmc_host *mmc)
2402{
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302403 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404 struct device *dev = mmc->parent;
2405
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302406 if (dev->power.runtime_status == RPM_SUSPENDING) {
2407 if (mmc->suspend_task == current) {
2408 pm_runtime_get_noresume(dev);
2409 goto out;
2410 }
2411 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302413 rc = pm_runtime_get_sync(dev);
2414
2415 if (rc < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2417 __func__, rc);
Sahitya Tummalaefa6af82011-09-07 14:46:30 +05302418 return rc;
2419 }
2420out:
2421 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422}
2423
2424static int msmsdcc_disable(struct mmc_host *mmc, int lazy)
2425{
2426 int rc;
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302427 struct msmsdcc_host *host = mmc_priv(mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428
Sahitya Tummalab07e1ae2011-09-02 11:58:42 +05302429 if (host->plat->disable_runtime_pm)
2430 return -ENOTSUPP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO)
2432 return -ENOTSUPP;
2433
2434 rc = pm_runtime_put_sync(mmc->parent);
2435
2436 if (rc < 0)
2437 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
2438 __func__, rc);
2439 return rc;
2440}
2441#else
2442#define msmsdcc_enable NULL
2443#define msmsdcc_disable NULL
2444#endif
2445
2446static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
2447 struct mmc_ios *ios)
2448{
2449 struct msmsdcc_host *host = mmc_priv(mmc);
2450 unsigned long flags;
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302451 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452
2453 if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
2454 /* Change voltage level of VDDPX to high voltage */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302455 rc = msmsdcc_set_vddp_high_vol(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 goto out;
2457 } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
2458 /* invalid selection. don't do anything */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302459 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 goto out;
2461 }
San Mehat9d2bd732009-09-22 16:44:22 -07002462
2463 spin_lock_irqsave(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 /*
2465 * If we are here means voltage switch from high voltage to
2466 * low voltage is required
2467 */
2468
2469 /*
2470 * Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
2471 * register until they become all zeros.
2472 */
2473 if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302474 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
2476 mmc_hostname(mmc), __func__);
2477 goto out_unlock;
San Mehat9d2bd732009-09-22 16:44:22 -07002478 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479
2480 /* Stop SD CLK output. */
2481 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2482 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302483 msmsdcc_delay(host);
San Mehat9d2bd732009-09-22 16:44:22 -07002484 spin_unlock_irqrestore(&host->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485
2486 /*
2487 * Switch VDDPX from high voltage to low voltage
2488 * to change the VDD of the SD IO pads.
2489 */
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302490 rc = msmsdcc_set_vddp_low_vol(host);
2491 if (rc)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493
2494 spin_lock_irqsave(&host->lock, flags);
2495 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2496 IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302497 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498 host->io_pad_pwr_switch = 1;
2499 spin_unlock_irqrestore(&host->lock, flags);
2500
2501 /* Wait 5 ms for the voltage regulater in the card to become stable. */
2502 usleep_range(5000, 5500);
2503
2504 spin_lock_irqsave(&host->lock, flags);
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302505 /* Disable PWRSAVE would make sure that SD CLK is always running */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2507 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302508 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002509 spin_unlock_irqrestore(&host->lock, flags);
2510
2511 /*
2512 * If MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT register
2513 * don't become all ones within 1 ms then a Voltage Switch
2514 * sequence has failed and a power cycle to the card is required.
2515 * Otherwise Voltage Switch sequence is completed successfully.
2516 */
2517 usleep_range(1000, 1500);
2518
2519 spin_lock_irqsave(&host->lock, flags);
2520 if ((readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1))
2521 != (0xF << 1)) {
2522 pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
2523 mmc_hostname(mmc), __func__);
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302524 rc = -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 goto out_unlock;
2526 }
2527
2528out_unlock:
Subhash Jadavani0c0b8182011-11-03 10:51:20 +05302529 /* Enable PWRSAVE */
2530 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2531 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002532 spin_unlock_irqrestore(&host->lock, flags);
2533out:
Subhash Jadavani99ba53a2011-08-01 16:04:18 +05302534 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535}
2536
2537static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2538 u8 phase);
2539/* Initialize the DLL (Programmable Delay Line ) */
2540static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
2541{
2542 int rc = 0;
2543 u32 wait_timeout;
2544
2545 /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
2546 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2547 & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
2548
2549 /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
2550 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2551 | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2552
2553 msmsdcc_delay(host);
2554
2555 /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
2556 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2557 & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
2558
2559 /* Initialize the phase to 0 */
2560 rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
2561 if (rc)
2562 goto out;
2563
2564 wait_timeout = 1000;
2565 /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
2566 while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
2567 /* max. wait for 1 sec for LOCK bit to be set */
2568 if (--wait_timeout == 0) {
2569 pr_err("%s: %s: DLL failed to lock at phase: %d",
2570 mmc_hostname(host->mmc), __func__, 0);
2571 rc = -1;
2572 goto out;
2573 }
2574 /* wait for 1ms */
2575 usleep_range(1000, 1500);
2576 }
2577out:
2578 return rc;
2579}
2580
2581/*
2582 * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
2583 * calibration sequence. This function should be called before
2584 * enabling AUTO_CMD19 bit in MCI_CMD register for block read
2585 * commands (CMD17/CMD18).
2586 */
2587static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
2588{
2589 /* Set CDR_EN bit to 1. */
2590 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
2591 MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2592
2593 /* Set CDR_EXT_EN bit to 0. */
2594 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2595 & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2596
2597 /* Set CK_OUT_EN bit to 0. */
2598 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2599 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2600
2601 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2602 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
2603 ;
2604
2605 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2606 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2607 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2608
2609 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
2610 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
2611 ;
2612}
2613
2614static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
2615 u8 phase)
2616{
2617 int rc = 0;
2618 u32 mclk_freq = 0;
2619 u32 wait_timeout;
2620
2621 /* Set CDR_EN bit to 0. */
2622 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2623 & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
2624
2625 /* Set CDR_EXT_EN bit to 1. */
2626 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2627 | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
2628
2629 /* Program the MCLK value to MCLK_FREQ bit field */
2630 if (host->clk_rate <= 112000000)
2631 mclk_freq = 0;
2632 else if (host->clk_rate <= 125000000)
2633 mclk_freq = 1;
2634 else if (host->clk_rate <= 137000000)
2635 mclk_freq = 2;
2636 else if (host->clk_rate <= 150000000)
2637 mclk_freq = 3;
2638 else if (host->clk_rate <= 162000000)
2639 mclk_freq = 4;
2640 else if (host->clk_rate <= 175000000)
2641 mclk_freq = 5;
2642 else if (host->clk_rate <= 187000000)
2643 mclk_freq = 6;
2644 else if (host->clk_rate <= 200000000)
2645 mclk_freq = 7;
2646
2647 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2648 & ~(7 << 24)) | (mclk_freq << 24)),
2649 host->base + MCI_DLL_CONFIG);
2650
2651 /* Set CK_OUT_EN bit to 0. */
2652 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2653 & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2654
2655 /* Set DLL_EN bit to 1. */
2656 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2657 | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
2658
2659 wait_timeout = 1000;
2660 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
2661 while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
2662 /* max. wait for 1 sec for LOCK bit for be set */
2663 if (--wait_timeout == 0) {
2664 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
2665 mmc_hostname(host->mmc), __func__, phase);
2666 rc = -1;
2667 goto out;
2668 }
2669 /* wait for 1ms */
2670 usleep_range(1000, 1500);
2671 }
2672
2673 /*
2674 * Write the selected DLL clock output phase (0 ... 15)
2675 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
2676 */
2677 writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
2678 & ~(0xF << 20)) | (phase << 20)),
2679 host->base + MCI_DLL_CONFIG);
2680
2681 /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
2682 writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
2683 | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
2684
2685 wait_timeout = 1000;
2686 /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
2687 while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
2688 /* max. wait for 1 sec for LOCK bit for be set */
2689 if (--wait_timeout == 0) {
2690 pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
2691 mmc_hostname(host->mmc), __func__, phase);
2692 rc = -1;
2693 goto out;
2694 }
2695 /* wait for 1ms */
2696 usleep_range(1000, 1500);
2697 }
2698out:
2699 return rc;
2700}
2701
2702static int msmsdcc_execute_tuning(struct mmc_host *mmc)
2703{
2704 struct msmsdcc_host *host = mmc_priv(mmc);
2705 u8 phase;
2706 u8 *data_buf;
2707 u8 tuned_phases[16], tuned_phase_cnt = 0;
2708 int rc = 0;
2709
2710 /* Tuning is only required for SDR50 & SDR104 modes */
2711 if (!host->tuning_needed) {
2712 rc = 0;
2713 goto out;
2714 }
2715
2716 host->cmd19_tuning_in_progress = 1;
2717 /*
2718 * Make sure that clock is always enabled when DLL
2719 * tuning is in progress. Keeping PWRSAVE ON may
2720 * turn off the clock. So let's disable the PWRSAVE
2721 * here and re-enable it once tuning is completed.
2722 */
2723 writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
2724 & ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302725 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726 /* first of all reset the tuning block */
2727 rc = msmsdcc_init_cm_sdc4_dll(host);
2728 if (rc)
2729 goto out;
2730
2731 data_buf = kmalloc(64, GFP_KERNEL);
2732 if (!data_buf) {
2733 rc = -ENOMEM;
2734 goto out;
2735 }
2736
2737 phase = 0;
2738 do {
2739 struct mmc_command cmd = {0};
2740 struct mmc_data data = {0};
2741 struct mmc_request mrq = {
2742 .cmd = &cmd,
2743 .data = &data
2744 };
2745 struct scatterlist sg;
2746
2747 /* set the phase in delay line hw block */
2748 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2749 if (rc)
2750 goto kfree;
2751
2752 cmd.opcode = MMC_SEND_TUNING_BLOCK;
2753 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
2754
2755 data.blksz = 64;
2756 data.blocks = 1;
2757 data.flags = MMC_DATA_READ;
2758 data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
2759
2760 data.sg = &sg;
2761 data.sg_len = 1;
2762 sg_init_one(&sg, data_buf, 64);
2763 memset(data_buf, 0, 64);
2764 mmc_wait_for_req(mmc, &mrq);
2765
2766 if (!cmd.error && !data.error &&
2767 !memcmp(data_buf, cmd19_tuning_block, 64)) {
2768 /* tuning is successful with this tuning point */
2769 tuned_phases[tuned_phase_cnt++] = phase;
2770 }
2771 } while (++phase < 16);
2772
2773 kfree(data_buf);
2774
2775 if (tuned_phase_cnt) {
2776 tuned_phase_cnt--;
2777 tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
2778 phase = tuned_phases[tuned_phase_cnt];
2779 /*
2780 * Finally set the selected phase in delay
2781 * line hw block.
2782 */
2783 rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
2784 if (rc)
2785 goto out;
2786 } else {
2787 /* tuning failed */
2788 rc = -EAGAIN;
2789 pr_err("%s: %s: no tuning point found",
2790 mmc_hostname(mmc), __func__);
2791 }
2792 goto out;
2793
2794kfree:
2795 kfree(data_buf);
2796out:
2797 /* re-enable PWESAVE */
2798 writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
2799 MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
Subhash Jadavani15f29db2011-10-13 09:57:13 +05302800 msmsdcc_delay(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801 host->cmd19_tuning_in_progress = 0;
2802 return rc;
San Mehat9d2bd732009-09-22 16:44:22 -07002803}
2804
2805static const struct mmc_host_ops msmsdcc_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 .enable = msmsdcc_enable,
2807 .disable = msmsdcc_disable,
San Mehat9d2bd732009-09-22 16:44:22 -07002808 .request = msmsdcc_request,
2809 .set_ios = msmsdcc_set_ios,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002810 .get_ro = msmsdcc_get_ro,
2811#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
San Mehat9d2bd732009-09-22 16:44:22 -07002812 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813#endif
2814 .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
2815 .execute_tuning = msmsdcc_execute_tuning
San Mehat9d2bd732009-09-22 16:44:22 -07002816};
2817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818static unsigned int
2819msmsdcc_slot_status(struct msmsdcc_host *host)
2820{
2821 int status;
2822 unsigned int gpio_no = host->plat->status_gpio;
2823
2824 status = gpio_request(gpio_no, "SD_HW_Detect");
2825 if (status) {
2826 pr_err("%s: %s: Failed to request GPIO %d\n",
2827 mmc_hostname(host->mmc), __func__, gpio_no);
2828 } else {
2829 status = gpio_direction_input(gpio_no);
2830 if (!status)
2831 status = !gpio_get_value_cansleep(gpio_no);
2832 gpio_free(gpio_no);
2833 }
2834 return status;
2835}
2836
San Mehat9d2bd732009-09-22 16:44:22 -07002837static void
2838msmsdcc_check_status(unsigned long data)
2839{
2840 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2841 unsigned int status;
2842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002843 if (host->plat->status || host->plat->status_gpio) {
2844 if (host->plat->status)
2845 status = host->plat->status(mmc_dev(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07002846 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847 status = msmsdcc_slot_status(host);
2848
2849 host->eject = !status;
2850 if (status ^ host->oldstat) {
2851 pr_info("%s: Slot status change detected (%d -> %d)\n",
2852 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -07002853 mmc_detect_change(host->mmc, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 }
2855 host->oldstat = status;
2856 } else {
2857 mmc_detect_change(host->mmc, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07002858 }
San Mehat9d2bd732009-09-22 16:44:22 -07002859}
2860
2861static irqreturn_t
2862msmsdcc_platform_status_irq(int irq, void *dev_id)
2863{
2864 struct msmsdcc_host *host = dev_id;
2865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002866 pr_debug("%s: %d\n", __func__, irq);
San Mehat9d2bd732009-09-22 16:44:22 -07002867 msmsdcc_check_status((unsigned long) host);
2868 return IRQ_HANDLED;
2869}
2870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871static irqreturn_t
2872msmsdcc_platform_sdiowakeup_irq(int irq, void *dev_id)
2873{
2874 struct msmsdcc_host *host = dev_id;
2875
2876 pr_debug("%s: SDIO Wake up IRQ : %d\n", mmc_hostname(host->mmc), irq);
2877 spin_lock(&host->lock);
2878 if (!host->sdio_irq_disabled) {
2879 disable_irq_nosync(irq);
2880 if (host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
2881 wake_lock(&host->sdio_wlock);
2882 msmsdcc_disable_irq_wake(host);
2883 }
2884 host->sdio_irq_disabled = 1;
2885 }
2886 if (host->plat->is_sdio_al_client) {
2887 if (!host->clks_on) {
2888 msmsdcc_setup_clocks(host, true);
2889 host->clks_on = 1;
2890 }
2891 if (host->sdcc_irq_disabled) {
2892 writel_relaxed(host->mci_irqenable,
2893 host->base + MMCIMASK0);
2894 mb();
2895 enable_irq(host->core_irqres->start);
2896 host->sdcc_irq_disabled = 0;
2897 }
2898 wake_lock(&host->sdio_wlock);
2899 }
2900 spin_unlock(&host->lock);
2901
2902 return IRQ_HANDLED;
2903}
2904
San Mehat9d2bd732009-09-22 16:44:22 -07002905static void
2906msmsdcc_status_notify_cb(int card_present, void *dev_id)
2907{
2908 struct msmsdcc_host *host = dev_id;
2909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910 pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
San Mehat9d2bd732009-09-22 16:44:22 -07002911 card_present);
2912 msmsdcc_check_status((unsigned long) host);
2913}
2914
San Mehat9d2bd732009-09-22 16:44:22 -07002915static int
2916msmsdcc_init_dma(struct msmsdcc_host *host)
2917{
2918 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
2919 host->dma.host = host;
2920 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07002921 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07002922
2923 if (!host->dmares)
2924 return -ENODEV;
2925
2926 host->dma.nc = dma_alloc_coherent(NULL,
2927 sizeof(struct msmsdcc_nc_dmadata),
2928 &host->dma.nc_busaddr,
2929 GFP_KERNEL);
2930 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07002931 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07002932 return -ENOMEM;
2933 }
2934 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
2935 host->dma.cmd_busaddr = host->dma.nc_busaddr;
2936 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
2937 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
2938 host->dma.channel = host->dmares->start;
Krishna Konda25786ec2011-07-25 16:21:36 -07002939 host->dma.crci = host->dma_crci_res->start;
San Mehat9d2bd732009-09-22 16:44:22 -07002940
2941 return 0;
2942}
2943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002944#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
2945/**
2946 * Allocate and Connect a SDCC peripheral's SPS endpoint
2947 *
2948 * This function allocates endpoint context and
2949 * connect it with memory endpoint by calling
2950 * appropriate SPS driver APIs.
2951 *
2952 * Also registers a SPS callback function with
2953 * SPS driver
2954 *
2955 * This function should only be called once typically
2956 * during driver probe.
2957 *
2958 * @host - Pointer to sdcc host structure
2959 * @ep - Pointer to sps endpoint data structure
2960 * @is_produce - 1 means Producer endpoint
2961 * 0 means Consumer endpoint
2962 *
2963 * @return - 0 if successful else negative value.
2964 *
2965 */
2966static int msmsdcc_sps_init_ep_conn(struct msmsdcc_host *host,
2967 struct msmsdcc_sps_ep_conn_data *ep,
2968 bool is_producer)
2969{
2970 int rc = 0;
2971 struct sps_pipe *sps_pipe_handle;
2972 struct sps_connect *sps_config = &ep->config;
2973 struct sps_register_event *sps_event = &ep->event;
2974
2975 /* Allocate endpoint context */
2976 sps_pipe_handle = sps_alloc_endpoint();
2977 if (!sps_pipe_handle) {
2978 pr_err("%s: sps_alloc_endpoint() failed!!! is_producer=%d",
2979 mmc_hostname(host->mmc), is_producer);
2980 rc = -ENOMEM;
2981 goto out;
2982 }
2983
2984 /* Get default connection configuration for an endpoint */
2985 rc = sps_get_config(sps_pipe_handle, sps_config);
2986 if (rc) {
2987 pr_err("%s: sps_get_config() failed!!! pipe_handle=0x%x,"
2988 " rc=%d", mmc_hostname(host->mmc),
2989 (u32)sps_pipe_handle, rc);
2990 goto get_config_err;
2991 }
2992
2993 /* Modify the default connection configuration */
2994 if (is_producer) {
2995 /*
2996 * For SDCC producer transfer, source should be
2997 * SDCC peripheral where as destination should
2998 * be system memory.
2999 */
3000 sps_config->source = host->sps.bam_handle;
3001 sps_config->destination = SPS_DEV_HANDLE_MEM;
3002 /* Producer pipe will handle this connection */
3003 sps_config->mode = SPS_MODE_SRC;
3004 sps_config->options =
3005 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3006 } else {
3007 /*
3008 * For SDCC consumer transfer, source should be
3009 * system memory where as destination should
3010 * SDCC peripheral
3011 */
3012 sps_config->source = SPS_DEV_HANDLE_MEM;
3013 sps_config->destination = host->sps.bam_handle;
3014 sps_config->mode = SPS_MODE_DEST;
3015 sps_config->options =
3016 SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS;
3017 }
3018
3019 /* Producer pipe index */
3020 sps_config->src_pipe_index = host->sps.src_pipe_index;
3021 /* Consumer pipe index */
3022 sps_config->dest_pipe_index = host->sps.dest_pipe_index;
3023 /*
3024 * This event thresold value is only significant for BAM-to-BAM
3025 * transfer. It's ignored for BAM-to-System mode transfer.
3026 */
3027 sps_config->event_thresh = 0x10;
3028 /*
3029 * Max. no of scatter/gather buffers that can
3030 * be passed by block layer = 32 (NR_SG).
3031 * Each BAM descritor needs 64 bits (8 bytes).
3032 * One BAM descriptor is required per buffer transfer.
3033 * So we would require total 256 (32 * 8) bytes of descriptor FIFO.
3034 * But due to HW limitation we need to allocate atleast one extra
3035 * descriptor memory (256 bytes + 8 bytes). But in order to be
3036 * in power of 2, we are allocating 512 bytes of memory.
3037 */
3038 sps_config->desc.size = 512;
3039 sps_config->desc.base = dma_alloc_coherent(mmc_dev(host->mmc),
3040 sps_config->desc.size,
3041 &sps_config->desc.phys_base,
3042 GFP_KERNEL);
3043
Pratibhasagar V00b94332011-10-18 14:57:27 +05303044 if (!sps_config->desc.base) {
3045 rc = -ENOMEM;
3046 pr_err("%s: dma_alloc_coherent() failed!!! Can't allocate buffer\n"
3047 , mmc_hostname(host->mmc));
3048 goto get_config_err;
3049 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003050 memset(sps_config->desc.base, 0x00, sps_config->desc.size);
3051
3052 /* Establish connection between peripheral and memory endpoint */
3053 rc = sps_connect(sps_pipe_handle, sps_config);
3054 if (rc) {
3055 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3056 " rc=%d", mmc_hostname(host->mmc),
3057 (u32)sps_pipe_handle, rc);
3058 goto sps_connect_err;
3059 }
3060
3061 sps_event->mode = SPS_TRIGGER_CALLBACK;
3062 sps_event->options = SPS_O_EOT;
3063 sps_event->callback = msmsdcc_sps_complete_cb;
3064 sps_event->xfer_done = NULL;
3065 sps_event->user = (void *)host;
3066
3067 /* Register callback event for EOT (End of transfer) event. */
3068 rc = sps_register_event(sps_pipe_handle, sps_event);
3069 if (rc) {
3070 pr_err("%s: sps_connect() failed!!! pipe_handle=0x%x,"
3071 " rc=%d", mmc_hostname(host->mmc),
3072 (u32)sps_pipe_handle, rc);
3073 goto reg_event_err;
3074 }
3075 /* Now save the sps pipe handle */
3076 ep->pipe_handle = sps_pipe_handle;
3077 pr_debug("%s: %s, success !!! %s: pipe_handle=0x%x,"
3078 " desc_fifo.phys_base=0x%x\n", mmc_hostname(host->mmc),
3079 __func__, is_producer ? "READ" : "WRITE",
3080 (u32)sps_pipe_handle, sps_config->desc.phys_base);
3081 goto out;
3082
3083reg_event_err:
3084 sps_disconnect(sps_pipe_handle);
3085sps_connect_err:
3086 dma_free_coherent(mmc_dev(host->mmc),
3087 sps_config->desc.size,
3088 sps_config->desc.base,
3089 sps_config->desc.phys_base);
3090get_config_err:
3091 sps_free_endpoint(sps_pipe_handle);
3092out:
3093 return rc;
3094}
3095
3096/**
3097 * Disconnect and Deallocate a SDCC peripheral's SPS endpoint
3098 *
3099 * This function disconnect endpoint and deallocates
3100 * endpoint context.
3101 *
3102 * This function should only be called once typically
3103 * during driver remove.
3104 *
3105 * @host - Pointer to sdcc host structure
3106 * @ep - Pointer to sps endpoint data structure
3107 *
3108 */
3109static void msmsdcc_sps_exit_ep_conn(struct msmsdcc_host *host,
3110 struct msmsdcc_sps_ep_conn_data *ep)
3111{
3112 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3113 struct sps_connect *sps_config = &ep->config;
3114 struct sps_register_event *sps_event = &ep->event;
3115
3116 sps_event->xfer_done = NULL;
3117 sps_event->callback = NULL;
3118 sps_register_event(sps_pipe_handle, sps_event);
3119 sps_disconnect(sps_pipe_handle);
3120 dma_free_coherent(mmc_dev(host->mmc),
3121 sps_config->desc.size,
3122 sps_config->desc.base,
3123 sps_config->desc.phys_base);
3124 sps_free_endpoint(sps_pipe_handle);
3125}
3126
3127/**
3128 * Reset SDCC peripheral's SPS endpoint
3129 *
3130 * This function disconnects an endpoint.
3131 *
3132 * This function should be called for reseting
3133 * SPS endpoint when data transfer error is
3134 * encountered during data transfer. This
3135 * can be considered as soft reset to endpoint.
3136 *
3137 * This function should only be called if
3138 * msmsdcc_sps_init() is already called.
3139 *
3140 * @host - Pointer to sdcc host structure
3141 * @ep - Pointer to sps endpoint data structure
3142 *
3143 * @return - 0 if successful else negative value.
3144 */
3145static int msmsdcc_sps_reset_ep(struct msmsdcc_host *host,
3146 struct msmsdcc_sps_ep_conn_data *ep)
3147{
3148 int rc = 0;
3149 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3150
3151 rc = sps_disconnect(sps_pipe_handle);
3152 if (rc) {
3153 pr_err("%s: %s: sps_disconnect() failed!!! pipe_handle=0x%x,"
3154 " rc=%d", mmc_hostname(host->mmc), __func__,
3155 (u32)sps_pipe_handle, rc);
3156 goto out;
3157 }
3158 out:
3159 return rc;
3160}
3161
3162/**
3163 * Restore SDCC peripheral's SPS endpoint
3164 *
3165 * This function connects an endpoint.
3166 *
3167 * This function should be called for restoring
3168 * SPS endpoint after data transfer error is
3169 * encountered during data transfer. This
3170 * can be considered as soft reset to endpoint.
3171 *
3172 * This function should only be called if
3173 * msmsdcc_sps_reset_ep() is called before.
3174 *
3175 * @host - Pointer to sdcc host structure
3176 * @ep - Pointer to sps endpoint data structure
3177 *
3178 * @return - 0 if successful else negative value.
3179 */
3180static int msmsdcc_sps_restore_ep(struct msmsdcc_host *host,
3181 struct msmsdcc_sps_ep_conn_data *ep)
3182{
3183 int rc = 0;
3184 struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
3185 struct sps_connect *sps_config = &ep->config;
3186 struct sps_register_event *sps_event = &ep->event;
3187
3188 /* Establish connection between peripheral and memory endpoint */
3189 rc = sps_connect(sps_pipe_handle, sps_config);
3190 if (rc) {
3191 pr_err("%s: %s: sps_connect() failed!!! pipe_handle=0x%x,"
3192 " rc=%d", mmc_hostname(host->mmc), __func__,
3193 (u32)sps_pipe_handle, rc);
3194 goto out;
3195 }
3196
3197 /* Register callback event for EOT (End of transfer) event. */
3198 rc = sps_register_event(sps_pipe_handle, sps_event);
3199 if (rc) {
3200 pr_err("%s: %s: sps_register_event() failed!!!"
3201 " pipe_handle=0x%x, rc=%d",
3202 mmc_hostname(host->mmc), __func__,
3203 (u32)sps_pipe_handle, rc);
3204 goto reg_event_err;
3205 }
3206 goto out;
3207
3208reg_event_err:
3209 sps_disconnect(sps_pipe_handle);
3210out:
3211 return rc;
3212}
3213
3214/**
3215 * Initialize SPS HW connected with SDCC core
3216 *
3217 * This function register BAM HW resources with
3218 * SPS driver and then initialize 2 SPS endpoints
3219 *
3220 * This function should only be called once typically
3221 * during driver probe.
3222 *
3223 * @host - Pointer to sdcc host structure
3224 *
3225 * @return - 0 if successful else negative value.
3226 *
3227 */
3228static int msmsdcc_sps_init(struct msmsdcc_host *host)
3229{
3230 int rc = 0;
3231 struct sps_bam_props bam = {0};
3232
3233 host->bam_base = ioremap(host->bam_memres->start,
3234 resource_size(host->bam_memres));
3235 if (!host->bam_base) {
3236 pr_err("%s: BAM ioremap() failed!!! phys_addr=0x%x,"
3237 " size=0x%x", mmc_hostname(host->mmc),
3238 host->bam_memres->start,
3239 (host->bam_memres->end -
3240 host->bam_memres->start));
3241 rc = -ENOMEM;
3242 goto out;
3243 }
3244
3245 bam.phys_addr = host->bam_memres->start;
3246 bam.virt_addr = host->bam_base;
3247 /*
3248 * This event thresold value is only significant for BAM-to-BAM
3249 * transfer. It's ignored for BAM-to-System mode transfer.
3250 */
3251 bam.event_threshold = 0x10; /* Pipe event threshold */
3252 /*
3253 * This threshold controls when the BAM publish
3254 * the descriptor size on the sideband interface.
3255 * SPS HW will only be used when
3256 * data transfer size > MCI_FIFOSIZE (64 bytes).
3257 * PIO mode will be used when
3258 * data transfer size < MCI_FIFOSIZE (64 bytes).
3259 * So set this thresold value to 64 bytes.
3260 */
3261 bam.summing_threshold = 64;
3262 /* SPS driver wll handle the SDCC BAM IRQ */
3263 bam.irq = (u32)host->bam_irqres->start;
3264 bam.manage = SPS_BAM_MGR_LOCAL;
3265
3266 pr_info("%s: bam physical base=0x%x\n", mmc_hostname(host->mmc),
3267 (u32)bam.phys_addr);
3268 pr_info("%s: bam virtual base=0x%x\n", mmc_hostname(host->mmc),
3269 (u32)bam.virt_addr);
3270
3271 /* Register SDCC Peripheral BAM device to SPS driver */
3272 rc = sps_register_bam_device(&bam, &host->sps.bam_handle);
3273 if (rc) {
3274 pr_err("%s: sps_register_bam_device() failed!!! err=%d",
3275 mmc_hostname(host->mmc), rc);
3276 goto reg_bam_err;
3277 }
3278 pr_info("%s: BAM device registered. bam_handle=0x%x",
3279 mmc_hostname(host->mmc), host->sps.bam_handle);
3280
3281 host->sps.src_pipe_index = SPS_SDCC_PRODUCER_PIPE_INDEX;
3282 host->sps.dest_pipe_index = SPS_SDCC_CONSUMER_PIPE_INDEX;
3283
3284 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.prod,
3285 SPS_PROD_PERIPHERAL);
3286 if (rc)
3287 goto sps_reset_err;
3288 rc = msmsdcc_sps_init_ep_conn(host, &host->sps.cons,
3289 SPS_CONS_PERIPHERAL);
3290 if (rc)
3291 goto cons_conn_err;
3292
3293 pr_info("%s: Qualcomm MSM SDCC-BAM at 0x%016llx irq %d\n",
3294 mmc_hostname(host->mmc),
3295 (unsigned long long)host->bam_memres->start,
3296 (unsigned int)host->bam_irqres->start);
3297 goto out;
3298
3299cons_conn_err:
3300 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3301sps_reset_err:
3302 sps_deregister_bam_device(host->sps.bam_handle);
3303reg_bam_err:
3304 iounmap(host->bam_base);
3305out:
3306 return rc;
3307}
3308
3309/**
3310 * De-initialize SPS HW connected with SDCC core
3311 *
3312 * This function deinitialize SPS endpoints and then
3313 * deregisters BAM resources from SPS driver.
3314 *
3315 * This function should only be called once typically
3316 * during driver remove.
3317 *
3318 * @host - Pointer to sdcc host structure
3319 *
3320 */
3321static void msmsdcc_sps_exit(struct msmsdcc_host *host)
3322{
3323 msmsdcc_sps_exit_ep_conn(host, &host->sps.cons);
3324 msmsdcc_sps_exit_ep_conn(host, &host->sps.prod);
3325 sps_deregister_bam_device(host->sps.bam_handle);
3326 iounmap(host->bam_base);
3327}
3328#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
3329
3330static ssize_t
3331show_polling(struct device *dev, struct device_attribute *attr, char *buf)
3332{
3333 struct mmc_host *mmc = dev_get_drvdata(dev);
3334 struct msmsdcc_host *host = mmc_priv(mmc);
3335 int poll;
3336 unsigned long flags;
3337
3338 spin_lock_irqsave(&host->lock, flags);
3339 poll = !!(mmc->caps & MMC_CAP_NEEDS_POLL);
3340 spin_unlock_irqrestore(&host->lock, flags);
3341
3342 return snprintf(buf, PAGE_SIZE, "%d\n", poll);
3343}
3344
3345static ssize_t
3346set_polling(struct device *dev, struct device_attribute *attr,
3347 const char *buf, size_t count)
3348{
3349 struct mmc_host *mmc = dev_get_drvdata(dev);
3350 struct msmsdcc_host *host = mmc_priv(mmc);
3351 int value;
3352 unsigned long flags;
3353
3354 sscanf(buf, "%d", &value);
3355
3356 spin_lock_irqsave(&host->lock, flags);
3357 if (value) {
3358 mmc->caps |= MMC_CAP_NEEDS_POLL;
3359 mmc_detect_change(host->mmc, 0);
3360 } else {
3361 mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3362 }
3363#ifdef CONFIG_HAS_EARLYSUSPEND
3364 host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
3365#endif
3366 spin_unlock_irqrestore(&host->lock, flags);
3367 return count;
3368}
3369
3370static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
3371 show_polling, set_polling);
3372static struct attribute *dev_attrs[] = {
3373 &dev_attr_polling.attr,
3374 NULL,
3375};
3376static struct attribute_group dev_attr_grp = {
3377 .attrs = dev_attrs,
3378};
3379
3380#ifdef CONFIG_HAS_EARLYSUSPEND
3381static void msmsdcc_early_suspend(struct early_suspend *h)
3382{
3383 struct msmsdcc_host *host =
3384 container_of(h, struct msmsdcc_host, early_suspend);
3385 unsigned long flags;
3386
3387 spin_lock_irqsave(&host->lock, flags);
3388 host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
3389 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
3390 spin_unlock_irqrestore(&host->lock, flags);
3391};
3392static void msmsdcc_late_resume(struct early_suspend *h)
3393{
3394 struct msmsdcc_host *host =
3395 container_of(h, struct msmsdcc_host, early_suspend);
3396 unsigned long flags;
3397
3398 if (host->polling_enabled) {
3399 spin_lock_irqsave(&host->lock, flags);
3400 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
3401 mmc_detect_change(host->mmc, 0);
3402 spin_unlock_irqrestore(&host->lock, flags);
3403 }
3404};
3405#endif
3406
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303407void msmsdcc_print_regs(const char *name, void __iomem *base,
3408 unsigned int no_of_regs)
3409{
3410 unsigned int i;
3411
3412 if (!base)
3413 return;
3414 pr_info("===== %s: Register Dumps @base=0x%x =====\n",
3415 name, (u32)base);
3416 for (i = 0; i < no_of_regs; i = i + 4) {
3417 pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
3418 (u32)readl_relaxed(base + i*4),
3419 (u32)readl_relaxed(base + ((i+1)*4)),
3420 (u32)readl_relaxed(base + ((i+2)*4)),
3421 (u32)readl_relaxed(base + ((i+3)*4)));
3422 }
3423}
3424
3425static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
3426{
3427 /* Dump current state of SDCC clocks, power and irq */
3428 pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
3429 (host->pwr ? "ON" : "OFF"));
3430 pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
3431 mmc_hostname(host->mmc),
3432 (host->clks_on ? "ON" : "OFF"),
3433 (u32)clk_get_rate(host->clk));
3434 pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
3435 (host->sdcc_irq_disabled ? "disabled" : "enabled"));
3436
3437 /* Now dump SDCC registers. Don't print FIFO registers */
3438 if (host->clks_on)
3439 msmsdcc_print_regs("SDCC-CORE", host->base, 28);
3440
3441 if (host->curr.data) {
3442 if (msmsdcc_check_dma_op_req(host->curr.data))
3443 pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
3444 else if (host->is_dma_mode)
3445 pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
3446 mmc_hostname(host->mmc), host->dma.busy,
3447 host->dma.channel, host->dma.crci);
3448 else if (host->is_sps_mode)
3449 pr_info("%s: SPS mode: busy=%d\n",
3450 mmc_hostname(host->mmc), host->sps.busy);
3451
3452 pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
3453 mmc_hostname(host->mmc), host->curr.xfer_size,
3454 host->curr.data_xfered, host->curr.xfer_remain);
3455 pr_info("%s: got_dataend=%d, prog_enable=%d,"
3456 " wait_for_auto_prog_done=%d,"
3457 " got_auto_prog_done=%d\n",
3458 mmc_hostname(host->mmc), host->curr.got_dataend,
3459 host->prog_enable, host->curr.wait_for_auto_prog_done,
3460 host->curr.got_auto_prog_done);
3461 }
3462
3463}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
3465{
3466 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
3467 struct mmc_request *mrq;
3468 unsigned long flags;
3469
3470 spin_lock_irqsave(&host->lock, flags);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003471 if (host->dummy_52_sent) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 pr_info("%s: %s: dummy CMD52 timeout\n",
3473 mmc_hostname(host->mmc), __func__);
Oluwafemi Adeyemicb791442011-07-11 22:51:25 -07003474 host->dummy_52_sent = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475 }
3476
3477 mrq = host->curr.mrq;
3478
3479 if (mrq && mrq->cmd) {
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303480 pr_info("%s: CMD%d: Request timeout\n", mmc_hostname(host->mmc),
3481 mrq->cmd->opcode);
3482 msmsdcc_dump_sdcc_state(host);
3483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 if (!mrq->cmd->error)
3485 mrq->cmd->error = -ETIMEDOUT;
Subhash Jadavanic0dd4a82011-09-07 18:41:36 +05303486 host->dummy_52_needed = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 if (host->curr.data) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003488 if (mrq->data && !mrq->data->error)
3489 mrq->data->error = -ETIMEDOUT;
3490 host->curr.data_xfered = 0;
3491 if (host->dma.sg && host->is_dma_mode) {
3492 msm_dmov_stop_cmd(host->dma.channel,
3493 &host->dma.hdr, 0);
3494 } else if (host->sps.sg && host->is_sps_mode) {
3495 /* Stop current SPS transfer */
3496 msmsdcc_sps_exit_curr_xfer(host);
3497 } else {
3498 msmsdcc_reset_and_restore(host);
3499 msmsdcc_stop_data(host);
3500 if (mrq->data && mrq->data->stop)
3501 msmsdcc_start_command(host,
3502 mrq->data->stop, 0);
3503 else
3504 msmsdcc_request_end(host, mrq);
3505 }
3506 } else {
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303507 host->prog_enable = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003508 msmsdcc_reset_and_restore(host);
3509 msmsdcc_request_end(host, mrq);
3510 }
3511 }
3512 spin_unlock_irqrestore(&host->lock, flags);
3513}
3514
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303515static struct mmc_platform_data *msmsdcc_populate_pdata(struct device *dev)
3516{
3517 int i, ret;
3518 struct mmc_platform_data *pdata;
3519 struct device_node *np = dev->of_node;
3520 u32 bus_width = 0;
3521 u32 *clk_table;
3522 int clk_table_len;
3523 u32 *sup_voltages;
3524 int sup_volt_len;
3525
3526 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3527 if (!pdata) {
3528 dev_err(dev, "could not allocate memory for platform data\n");
3529 goto err;
3530 }
3531
3532 of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
3533 if (bus_width == 8) {
3534 pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
3535 } else if (bus_width == 4) {
3536 pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
3537 } else {
3538 dev_notice(dev, "Invalid bus width, default to 1 bit mode\n");
3539 pdata->mmc_bus_width = 0;
3540 }
3541
3542 if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
3543 size_t sz;
3544 sz = sup_volt_len / sizeof(*sup_voltages);
3545 if (sz > 0) {
3546 sup_voltages = devm_kzalloc(dev,
3547 sz * sizeof(*sup_voltages), GFP_KERNEL);
3548 if (!sup_voltages) {
3549 dev_err(dev, "No memory for supported voltage\n");
3550 goto err;
3551 }
3552
3553 ret = of_property_read_u32_array(np,
3554 "qcom,sdcc-sup-voltages", sup_voltages, sz);
3555 if (ret < 0) {
3556 dev_err(dev, "error while reading voltage"
3557 "ranges %d\n", ret);
3558 goto err;
3559 }
3560 } else {
3561 dev_err(dev, "No supported voltages\n");
3562 goto err;
3563 }
3564 for (i = 0; i < sz; i += 2) {
3565 u32 mask;
3566
3567 mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
3568 sup_voltages[i + 1]);
3569 if (!mask)
3570 dev_err(dev, "Invalide voltage range %d\n", i);
3571 pdata->ocr_mask |= mask;
3572 }
3573 dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
3574 } else {
3575 dev_err(dev, "Supported voltage range not specified\n");
3576 }
3577
3578 if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
3579 size_t sz;
3580 sz = clk_table_len / sizeof(*clk_table);
3581
3582 if (sz > 0) {
3583 clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
3584 GFP_KERNEL);
3585 if (!clk_table) {
3586 dev_err(dev, "No memory for clock table\n");
3587 goto err;
3588 }
3589
3590 ret = of_property_read_u32_array(np,
3591 "qcom,sdcc-clk-rates", clk_table, sz);
3592 if (ret < 0) {
3593 dev_err(dev, "error while reading clk"
3594 "table %d\n", ret);
3595 goto err;
3596 }
3597 } else {
3598 dev_err(dev, "clk_table not specified\n");
3599 goto err;
3600 }
3601 pdata->sup_clk_table = clk_table;
3602 pdata->sup_clk_cnt = sz;
3603 } else {
3604 dev_err(dev, "Supported clock rates not specified\n");
3605 }
3606
3607 if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
3608 pdata->nonremovable = true;
3609 if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
3610 pdata->disable_cmd23 = true;
3611
3612 return pdata;
3613err:
3614 return NULL;
3615}
3616
San Mehat9d2bd732009-09-22 16:44:22 -07003617static int
3618msmsdcc_probe(struct platform_device *pdev)
3619{
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303620 struct mmc_platform_data *plat;
San Mehat9d2bd732009-09-22 16:44:22 -07003621 struct msmsdcc_host *host;
3622 struct mmc_host *mmc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003623 unsigned long flags;
3624 struct resource *core_irqres = NULL;
3625 struct resource *bam_irqres = NULL;
3626 struct resource *core_memres = NULL;
3627 struct resource *dml_memres = NULL;
3628 struct resource *bam_memres = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07003629 struct resource *dmares = NULL;
Krishna Konda25786ec2011-07-25 16:21:36 -07003630 struct resource *dma_crci_res = NULL;
Pratibhasagar V00b94332011-10-18 14:57:27 +05303631 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632 int i;
San Mehat9d2bd732009-09-22 16:44:22 -07003633
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303634 if (pdev->dev.of_node) {
3635 plat = msmsdcc_populate_pdata(&pdev->dev);
3636 of_property_read_u32((&pdev->dev)->of_node,
3637 "cell-index", &pdev->id);
3638 } else {
3639 plat = pdev->dev.platform_data;
3640 }
3641
San Mehat9d2bd732009-09-22 16:44:22 -07003642 /* must have platform data */
3643 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003644 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003645 ret = -EINVAL;
3646 goto out;
3647 }
3648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003649 if (pdev->id < 1 || pdev->id > 5)
San Mehat9d2bd732009-09-22 16:44:22 -07003650 return -EINVAL;
3651
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05303652 if (plat->is_sdio_al_client && !plat->sdiowakeup_irq) {
3653 pr_err("%s: No wakeup IRQ for sdio_al client\n", __func__);
3654 return -EINVAL;
3655 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656
San Mehat9d2bd732009-09-22 16:44:22 -07003657 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07003658 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003659 return -ENXIO;
3660 }
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303661 if (pdev->dev.of_node) {
3662 /*
3663 * Device tree iomem resources are only accessible by index.
3664 * index = 0 -> SDCC register interface
3665 * index = 1 -> DML register interface
3666 * index = 2 -> BAM register interface
3667 * IRQ resources:
3668 * index = 0 -> SDCC IRQ
3669 * index = 1 -> BAM IRQ
3670 */
3671 core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3672 dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3673 bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
3674 core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3675 bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
3676 } else {
3677 for (i = 0; i < pdev->num_resources; i++) {
3678 if (pdev->resource[i].flags & IORESOURCE_MEM) {
3679 if (!strncmp(pdev->resource[i].name,
3680 "sdcc_dml_addr",
3681 sizeof("sdcc_dml_addr")))
3682 dml_memres = &pdev->resource[i];
3683 else if (!strncmp(pdev->resource[i].name,
3684 "sdcc_bam_addr",
3685 sizeof("sdcc_bam_addr")))
3686 bam_memres = &pdev->resource[i];
3687 else
3688 core_memres = &pdev->resource[i];
San Mehat9d2bd732009-09-22 16:44:22 -07003689
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05303690 }
3691 if (pdev->resource[i].flags & IORESOURCE_IRQ) {
3692 if (!strncmp(pdev->resource[i].name,
3693 "sdcc_bam_irq",
3694 sizeof("sdcc_bam_irq")))
3695 bam_irqres = &pdev->resource[i];
3696 else
3697 core_irqres = &pdev->resource[i];
3698 }
3699 if (pdev->resource[i].flags & IORESOURCE_DMA) {
3700 if (!strncmp(pdev->resource[i].name,
3701 "sdcc_dma_chnl",
3702 sizeof("sdcc_dma_chnl")))
3703 dmares = &pdev->resource[i];
3704 else if (!strncmp(pdev->resource[i].name,
3705 "sdcc_dma_crci",
3706 sizeof("sdcc_dma_crci")))
3707 dma_crci_res = &pdev->resource[i];
3708 }
Krishna Konda25786ec2011-07-25 16:21:36 -07003709 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003710 }
3711
3712 if (!core_irqres || !core_memres) {
3713 pr_err("%s: Invalid sdcc core resource\n", __func__);
3714 return -ENXIO;
3715 }
3716
3717 /*
3718 * Both BAM and DML memory resource should be preset.
3719 * BAM IRQ resource should also be present.
3720 */
3721 if ((bam_memres && !dml_memres) ||
3722 (!bam_memres && dml_memres) ||
3723 ((bam_memres && dml_memres) && !bam_irqres)) {
3724 pr_err("%s: Invalid sdcc BAM/DML resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07003725 return -ENXIO;
3726 }
3727
3728 /*
3729 * Setup our host structure
3730 */
San Mehat9d2bd732009-09-22 16:44:22 -07003731 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
3732 if (!mmc) {
3733 ret = -ENOMEM;
3734 goto out;
3735 }
3736
3737 host = mmc_priv(mmc);
3738 host->pdev_id = pdev->id;
3739 host->plat = plat;
3740 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08003741 host->curr.cmd = NULL;
Sahitya Tummalad9df3272011-08-19 16:50:46 +05303742
3743 if (!plat->disable_bam && bam_memres && dml_memres && bam_irqres)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744 host->is_sps_mode = 1;
3745 else if (dmares)
3746 host->is_dma_mode = 1;
San Mehat9d2bd732009-09-22 16:44:22 -07003747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748 host->base = ioremap(core_memres->start,
3749 resource_size(core_memres));
San Mehat9d2bd732009-09-22 16:44:22 -07003750 if (!host->base) {
3751 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 goto host_free;
San Mehat9d2bd732009-09-22 16:44:22 -07003753 }
3754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003755 host->core_irqres = core_irqres;
3756 host->bam_irqres = bam_irqres;
3757 host->core_memres = core_memres;
3758 host->dml_memres = dml_memres;
3759 host->bam_memres = bam_memres;
San Mehat9d2bd732009-09-22 16:44:22 -07003760 host->dmares = dmares;
Krishna Konda25786ec2011-07-25 16:21:36 -07003761 host->dma_crci_res = dma_crci_res;
San Mehat9d2bd732009-09-22 16:44:22 -07003762 spin_lock_init(&host->lock);
3763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764#ifdef CONFIG_MMC_EMBEDDED_SDIO
3765 if (plat->embedded_sdio)
3766 mmc_set_embedded_sdio_data(mmc,
3767 &plat->embedded_sdio->cis,
3768 &plat->embedded_sdio->cccr,
3769 plat->embedded_sdio->funcs,
3770 plat->embedded_sdio->num_funcs);
3771#endif
3772
Sahitya Tummala62612cf2010-12-08 15:03:03 +05303773 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
3774 (unsigned long)host);
3775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776 tasklet_init(&host->sps.tlet, msmsdcc_sps_complete_tlet,
3777 (unsigned long)host);
3778 if (host->is_dma_mode) {
3779 /* Setup DMA */
3780 ret = msmsdcc_init_dma(host);
3781 if (ret)
3782 goto ioremap_free;
3783 } else {
3784 host->dma.channel = -1;
Krishna Konda25786ec2011-07-25 16:21:36 -07003785 host->dma.crci = -1;
San Mehat9d2bd732009-09-22 16:44:22 -07003786 }
3787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003788 /*
3789 * Setup SDCC clock if derived from Dayatona
3790 * fabric core clock.
3791 */
3792 if (plat->pclk_src_dfab) {
Matt Wagantall37ce3842011-08-17 16:00:36 -07003793 host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003794 if (!IS_ERR(host->dfab_pclk)) {
3795 /* Set the clock rate to 64MHz for max. performance */
3796 ret = clk_set_rate(host->dfab_pclk, 64000000);
3797 if (ret)
3798 goto dfab_pclk_put;
3799 ret = clk_enable(host->dfab_pclk);
3800 if (ret)
3801 goto dfab_pclk_put;
3802 } else
3803 goto dma_free;
3804 }
3805
3806 /*
3807 * Setup main peripheral bus clock
3808 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003809 host->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 if (!IS_ERR(host->pclk)) {
3811 ret = clk_enable(host->pclk);
3812 if (ret)
3813 goto pclk_put;
3814
3815 host->pclk_rate = clk_get_rate(host->pclk);
3816 }
3817
3818 /*
3819 * Setup SDC MMC clock
3820 */
Matt Wagantall37ce3842011-08-17 16:00:36 -07003821 host->clk = clk_get(&pdev->dev, "core_clk");
San Mehat9d2bd732009-09-22 16:44:22 -07003822 if (IS_ERR(host->clk)) {
3823 ret = PTR_ERR(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 goto pclk_disable;
San Mehat9d2bd732009-09-22 16:44:22 -07003825 }
3826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003827 ret = clk_set_rate(host->clk, msmsdcc_get_min_sup_clk_rate(host));
3828 if (ret) {
3829 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
3830 goto clk_put;
3831 }
3832
3833 ret = clk_enable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07003834 if (ret)
3835 goto clk_put;
3836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837 host->clk_rate = clk_get_rate(host->clk);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303838 if (!host->clk_rate)
3839 dev_err(&pdev->dev, "Failed to read MCLK\n");
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303840
3841 /*
3842 * Lookup the Controller Version, to identify the supported features
3843 * Version number read as 0 would indicate SDCC3 or earlier versions
3844 */
3845 host->sdcc_version = readl_relaxed(host->base + MCI_VERSION);
3846 pr_info("%s: mci-version: %x\n", mmc_hostname(host->mmc),
3847 host->sdcc_version);
Sujith Reddy Thummac1824d52011-09-28 10:05:44 +05303848 /*
3849 * Set the register write delay according to min. clock frequency
3850 * supported and update later when the host->clk_rate changes.
3851 */
3852 host->reg_write_delay =
3853 (1 + ((3 * USEC_PER_SEC) /
3854 msmsdcc_get_min_sup_clk_rate(host)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855
3856 host->clks_on = 1;
Subhash Jadavani15f29db2011-10-13 09:57:13 +05303857 /* Apply Hard reset to SDCC to put it in power on default state */
3858 msmsdcc_hard_reset(host);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859
3860 ret = msmsdcc_vreg_init(host, true);
San Mehat9d2bd732009-09-22 16:44:22 -07003861 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07003863 goto clk_disable;
3864 }
3865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003866
3867 /* Clocks has to be running before accessing SPS/DML HW blocks */
3868 if (host->is_sps_mode) {
3869 /* Initialize SPS */
3870 ret = msmsdcc_sps_init(host);
3871 if (ret)
3872 goto vreg_deinit;
3873 /* Initialize DML */
3874 ret = msmsdcc_dml_init(host);
3875 if (ret)
3876 goto sps_exit;
3877 }
San Mehat9d2bd732009-09-22 16:44:22 -07003878
San Mehat9d2bd732009-09-22 16:44:22 -07003879 /*
3880 * Setup MMC host structure
3881 */
3882 mmc->ops = &msmsdcc_ops;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
3884 mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
San Mehat9d2bd732009-09-22 16:44:22 -07003885 mmc->ocr_avail = plat->ocr_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003886 mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
3887 mmc->caps |= plat->mmc_bus_width;
San Mehat9d2bd732009-09-22 16:44:22 -07003888
San Mehat9d2bd732009-09-22 16:44:22 -07003889 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
Subhash Jadavani7d8c94d2011-10-18 18:00:07 +05303890 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303891
3892 /*
3893 * If we send the CMD23 before multi block write/read command
3894 * then we need not to send CMD12 at the end of the transfer.
3895 * If we don't send the CMD12 then only way to detect the PROG_DONE
3896 * status is to use the AUTO_PROG_DONE status provided by SDCC4
3897 * controller. So let's enable the CMD23 for SDCC4 only.
3898 */
Pratibhasagar V1c11da62011-11-14 12:36:35 +05303899 if (!plat->disable_cmd23 && host->sdcc_version)
Subhash Jadavania8e5ecb2011-08-25 19:19:58 +05303900 mmc->caps |= MMC_CAP_CMD23;
3901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 mmc->caps |= plat->uhs_caps;
3903 /*
3904 * XPC controls the maximum current in the default speed mode of SDXC
3905 * card. XPC=0 means 100mA (max.) but speed class is not supported.
3906 * XPC=1 means 150mA (max.) and speed class is supported.
3907 */
3908 if (plat->xpc_cap)
3909 mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
3910 MMC_CAP_SET_XPC_180);
3911
3912 if (plat->nonremovable)
3913 mmc->caps |= MMC_CAP_NONREMOVABLE;
3914#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
3915 mmc->caps |= MMC_CAP_SDIO_IRQ;
3916#endif
3917
3918 if (plat->is_sdio_al_client)
3919 mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
San Mehat9d2bd732009-09-22 16:44:22 -07003920
Martin K. Petersena36274e2010-09-10 01:33:59 -04003921 mmc->max_segs = NR_SG;
San Mehat9d2bd732009-09-22 16:44:22 -07003922 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003923 mmc->max_blk_count = 65535;
San Mehat9d2bd732009-09-22 16:44:22 -07003924
3925 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
3926 mmc->max_seg_size = mmc->max_req_size;
3927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 writel_relaxed(0, host->base + MMCIMASK0);
3929 writel_relaxed(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07003930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 writel_relaxed(MCI_IRQENABLE, host->base + MMCIMASK0);
3932 mb();
3933 host->mci_irqenable = MCI_IRQENABLE;
San Mehat9d2bd732009-09-22 16:44:22 -07003934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,
3936 DRIVER_NAME " (cmd)", host);
3937 if (ret)
3938 goto dml_exit;
3939
3940 ret = request_irq(core_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
3941 DRIVER_NAME " (pio)", host);
3942 if (ret)
3943 goto irq_free;
3944
3945 /*
3946 * Enable SDCC IRQ only when host is powered on. Otherwise, this
3947 * IRQ is un-necessarily being monitored by MPM (Modem power
3948 * management block) during idle-power collapse. The MPM will be
3949 * configured to monitor the DATA1 GPIO line with level-low trigger
3950 * and thus depending on the GPIO status, it prevents TCXO shutdown
3951 * during idle-power collapse.
3952 */
3953 disable_irq(core_irqres->start);
3954 host->sdcc_irq_disabled = 1;
3955
3956 if (plat->sdiowakeup_irq) {
3957 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3958 mmc_hostname(mmc));
3959 ret = request_irq(plat->sdiowakeup_irq,
3960 msmsdcc_platform_sdiowakeup_irq,
3961 IRQF_SHARED | IRQF_TRIGGER_LOW,
3962 DRIVER_NAME "sdiowakeup", host);
3963 if (ret) {
3964 pr_err("Unable to get sdio wakeup IRQ %d (%d)\n",
3965 plat->sdiowakeup_irq, ret);
3966 goto pio_irq_free;
3967 } else {
3968 spin_lock_irqsave(&host->lock, flags);
3969 if (!host->sdio_irq_disabled) {
3970 disable_irq_nosync(plat->sdiowakeup_irq);
3971 host->sdio_irq_disabled = 1;
3972 }
3973 spin_unlock_irqrestore(&host->lock, flags);
3974 }
3975 }
3976
3977 if (plat->cfg_mpm_sdiowakeup) {
3978 wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
3979 mmc_hostname(mmc));
3980 }
3981
3982 wake_lock_init(&host->sdio_suspend_wlock, WAKE_LOCK_SUSPEND,
3983 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07003984 /*
3985 * Setup card detect change
3986 */
3987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 if (plat->status || plat->status_gpio) {
3989 if (plat->status)
3990 host->oldstat = plat->status(mmc_dev(host->mmc));
3991 else
3992 host->oldstat = msmsdcc_slot_status(host);
3993 host->eject = !host->oldstat;
3994 }
San Mehat9d2bd732009-09-22 16:44:22 -07003995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003996 if (plat->status_irq) {
3997 ret = request_threaded_irq(plat->status_irq, NULL,
San Mehat9d2bd732009-09-22 16:44:22 -07003998 msmsdcc_platform_status_irq,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003999 plat->irq_flags,
San Mehat9d2bd732009-09-22 16:44:22 -07004000 DRIVER_NAME " (slot)",
4001 host);
4002 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004003 pr_err("Unable to get slot IRQ %d (%d)\n",
4004 plat->status_irq, ret);
4005 goto sdiowakeup_irq_free;
San Mehat9d2bd732009-09-22 16:44:22 -07004006 }
4007 } else if (plat->register_status_notify) {
4008 plat->register_status_notify(msmsdcc_status_notify_cb, host);
4009 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004010 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07004011 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004012
4013 mmc_set_drvdata(pdev, mmc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014
4015 ret = pm_runtime_set_active(&(pdev)->dev);
4016 if (ret < 0)
4017 pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
4018 __func__, ret);
4019 /*
4020 * There is no notion of suspend/resume for SD/MMC/SDIO
4021 * cards. So host can be suspended/resumed with out
4022 * worrying about its children.
4023 */
4024 pm_suspend_ignore_children(&(pdev)->dev, true);
4025
4026 /*
4027 * MMC/SD/SDIO bus suspend/resume operations are defined
4028 * only for the slots that will be used for non-removable
4029 * media or for all slots when CONFIG_MMC_UNSAFE_RESUME is
4030 * defined. Otherwise, they simply become card removal and
4031 * insertion events during suspend and resume respectively.
4032 * Hence, enable run-time PM only for slots for which bus
4033 * suspend/resume operations are defined.
4034 */
4035#ifdef CONFIG_MMC_UNSAFE_RESUME
4036 /*
4037 * If this capability is set, MMC core will enable/disable host
4038 * for every claim/release operation on a host. We use this
4039 * notification to increment/decrement runtime pm usage count.
4040 */
4041 mmc->caps |= MMC_CAP_DISABLE;
4042 pm_runtime_enable(&(pdev)->dev);
4043#else
4044 if (mmc->caps & MMC_CAP_NONREMOVABLE) {
4045 mmc->caps |= MMC_CAP_DISABLE;
4046 pm_runtime_enable(&(pdev)->dev);
4047 }
4048#endif
4049 setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
4050 (unsigned long)host);
4051
San Mehat9d2bd732009-09-22 16:44:22 -07004052 mmc_add_host(mmc);
4053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054#ifdef CONFIG_HAS_EARLYSUSPEND
4055 host->early_suspend.suspend = msmsdcc_early_suspend;
4056 host->early_suspend.resume = msmsdcc_late_resume;
4057 host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
4058 register_early_suspend(&host->early_suspend);
4059#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004060
Krishna Konda25786ec2011-07-25 16:21:36 -07004061 pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
4062 " dmacrcri %d\n", mmc_hostname(mmc),
4063 (unsigned long long)core_memres->start,
4064 (unsigned int) core_irqres->start,
4065 (unsigned int) plat->status_irq, host->dma.channel,
4066 host->dma.crci);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067
4068 pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc),
4069 (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled"));
4070 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
4071 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
4072 pr_info("%s: polling status mode %s\n", mmc_hostname(mmc),
4073 (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled"));
4074 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
4075 mmc_hostname(mmc), msmsdcc_get_min_sup_clk_rate(host),
4076 msmsdcc_get_max_sup_clk_rate(host), host->pclk_rate);
4077 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc),
4078 host->eject);
4079 pr_info("%s: Power save feature enable = %d\n",
4080 mmc_hostname(mmc), msmsdcc_pwrsave);
4081
Krishna Konda25786ec2011-07-25 16:21:36 -07004082 if (host->is_dma_mode && host->dma.channel != -1
4083 && host->dma.crci != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004084 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004086 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 mmc_hostname(mmc), host->dma.cmd_busaddr,
4088 host->dma.cmdptr_busaddr);
4089 } else if (host->is_sps_mode) {
4090 pr_info("%s: SPS-BAM data transfer mode available\n",
4091 mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004092 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07004093 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07004094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004095#if defined(CONFIG_DEBUG_FS)
4096 msmsdcc_dbg_createhost(host);
4097#endif
4098 if (!plat->status_irq) {
4099 ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
4100 if (ret)
4101 goto platform_irq_free;
4102 }
San Mehat9d2bd732009-09-22 16:44:22 -07004103 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104
4105 platform_irq_free:
4106 del_timer_sync(&host->req_tout_timer);
4107 pm_runtime_disable(&(pdev)->dev);
4108 pm_runtime_set_suspended(&(pdev)->dev);
4109
4110 if (plat->status_irq)
4111 free_irq(plat->status_irq, host);
4112 sdiowakeup_irq_free:
4113 wake_lock_destroy(&host->sdio_suspend_wlock);
4114 if (plat->sdiowakeup_irq)
4115 free_irq(plat->sdiowakeup_irq, host);
4116 pio_irq_free:
4117 if (plat->sdiowakeup_irq)
4118 wake_lock_destroy(&host->sdio_wlock);
4119 free_irq(core_irqres->start, host);
4120 irq_free:
4121 free_irq(core_irqres->start, host);
4122 dml_exit:
4123 if (host->is_sps_mode)
4124 msmsdcc_dml_exit(host);
4125 sps_exit:
4126 if (host->is_sps_mode)
4127 msmsdcc_sps_exit(host);
4128 vreg_deinit:
4129 msmsdcc_vreg_init(host, false);
San Mehat9d2bd732009-09-22 16:44:22 -07004130 clk_disable:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 clk_disable(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07004132 clk_put:
4133 clk_put(host->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134 pclk_disable:
4135 if (!IS_ERR(host->pclk))
4136 clk_disable(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07004137 pclk_put:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138 if (!IS_ERR(host->pclk))
4139 clk_put(host->pclk);
4140 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4141 clk_disable(host->dfab_pclk);
4142 dfab_pclk_put:
4143 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4144 clk_put(host->dfab_pclk);
4145 dma_free:
4146 if (host->is_dma_mode) {
4147 if (host->dmares)
4148 dma_free_coherent(NULL,
4149 sizeof(struct msmsdcc_nc_dmadata),
4150 host->dma.nc, host->dma.nc_busaddr);
4151 }
4152 ioremap_free:
4153 iounmap(host->base);
San Mehat9d2bd732009-09-22 16:44:22 -07004154 host_free:
4155 mmc_free_host(mmc);
4156 out:
4157 return ret;
4158}
4159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160static int msmsdcc_remove(struct platform_device *pdev)
Daniel Walker08ecfde2010-06-23 12:32:20 -07004161{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162 struct mmc_host *mmc = mmc_get_drvdata(pdev);
4163 struct mmc_platform_data *plat;
4164 struct msmsdcc_host *host;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004166 if (!mmc)
4167 return -ENXIO;
4168
4169 if (pm_runtime_suspended(&(pdev)->dev))
4170 pm_runtime_resume(&(pdev)->dev);
4171
4172 host = mmc_priv(mmc);
4173
4174 DBG(host, "Removing SDCC device = %d\n", pdev->id);
4175 plat = host->plat;
4176
4177 if (!plat->status_irq)
4178 sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
4179
4180 del_timer_sync(&host->req_tout_timer);
4181 tasklet_kill(&host->dma_tlet);
4182 tasklet_kill(&host->sps.tlet);
4183 mmc_remove_host(mmc);
4184
4185 if (plat->status_irq)
4186 free_irq(plat->status_irq, host);
4187
4188 wake_lock_destroy(&host->sdio_suspend_wlock);
4189 if (plat->sdiowakeup_irq) {
4190 wake_lock_destroy(&host->sdio_wlock);
4191 irq_set_irq_wake(plat->sdiowakeup_irq, 0);
4192 free_irq(plat->sdiowakeup_irq, host);
Daniel Walker08ecfde2010-06-23 12:32:20 -07004193 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194
4195 free_irq(host->core_irqres->start, host);
4196 free_irq(host->core_irqres->start, host);
4197
4198 clk_put(host->clk);
4199 if (!IS_ERR(host->pclk))
4200 clk_put(host->pclk);
4201 if (!IS_ERR_OR_NULL(host->dfab_pclk))
4202 clk_put(host->dfab_pclk);
4203
4204 msmsdcc_vreg_init(host, false);
4205
4206 if (host->is_dma_mode) {
4207 if (host->dmares)
4208 dma_free_coherent(NULL,
4209 sizeof(struct msmsdcc_nc_dmadata),
4210 host->dma.nc, host->dma.nc_busaddr);
4211 }
4212
4213 if (host->is_sps_mode) {
4214 msmsdcc_dml_exit(host);
4215 msmsdcc_sps_exit(host);
4216 }
4217
4218 iounmap(host->base);
4219 mmc_free_host(mmc);
4220
4221#ifdef CONFIG_HAS_EARLYSUSPEND
4222 unregister_early_suspend(&host->early_suspend);
4223#endif
4224 pm_runtime_disable(&(pdev)->dev);
4225 pm_runtime_set_suspended(&(pdev)->dev);
4226
4227 return 0;
4228}
4229
4230#ifdef CONFIG_MSM_SDIO_AL
4231int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4232{
4233 struct msmsdcc_host *host = mmc_priv(mmc);
4234 unsigned long flags;
4235
4236 spin_lock_irqsave(&host->lock, flags);
4237 pr_debug("%s: %sabling LPM\n", mmc_hostname(mmc),
4238 enable ? "En" : "Dis");
4239
4240 if (enable) {
4241 if (!host->sdcc_irq_disabled) {
4242 writel_relaxed(0, host->base + MMCIMASK0);
Sujith Reddy Thummade773b82011-08-03 19:58:15 +05304243 disable_irq_nosync(host->core_irqres->start);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004244 host->sdcc_irq_disabled = 1;
4245 }
4246
4247 if (host->clks_on) {
4248 msmsdcc_setup_clocks(host, false);
4249 host->clks_on = 0;
4250 }
4251
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304252 if (host->plat->sdio_lpm_gpio_setup &&
4253 !host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004254 spin_unlock_irqrestore(&host->lock, flags);
4255 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 0);
4256 spin_lock_irqsave(&host->lock, flags);
4257 host->sdio_gpio_lpm = 1;
4258 }
4259
4260 if (host->sdio_irq_disabled) {
4261 msmsdcc_enable_irq_wake(host);
4262 enable_irq(host->plat->sdiowakeup_irq);
4263 host->sdio_irq_disabled = 0;
4264 }
4265 } else {
4266 if (!host->sdio_irq_disabled) {
4267 disable_irq_nosync(host->plat->sdiowakeup_irq);
4268 host->sdio_irq_disabled = 1;
4269 msmsdcc_disable_irq_wake(host);
4270 }
4271
Sujith Reddy Thumma84a0f512011-08-29 09:57:03 +05304272 if (host->plat->sdio_lpm_gpio_setup &&
4273 host->sdio_gpio_lpm) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004274 spin_unlock_irqrestore(&host->lock, flags);
4275 host->plat->sdio_lpm_gpio_setup(mmc_dev(mmc), 1);
4276 spin_lock_irqsave(&host->lock, flags);
4277 host->sdio_gpio_lpm = 0;
4278 }
4279
4280 if (!host->clks_on) {
4281 msmsdcc_setup_clocks(host, true);
4282 host->clks_on = 1;
4283 }
4284
4285 if (host->sdcc_irq_disabled) {
4286 writel_relaxed(host->mci_irqenable,
4287 host->base + MMCIMASK0);
4288 mb();
4289 enable_irq(host->core_irqres->start);
4290 host->sdcc_irq_disabled = 0;
4291 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004292 }
4293 spin_unlock_irqrestore(&host->lock, flags);
4294 return 0;
4295}
4296#else
4297int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
4298{
4299 return 0;
Daniel Walker08ecfde2010-06-23 12:32:20 -07004300}
4301#endif
4302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004303#ifdef CONFIG_PM
San Mehat9d2bd732009-09-22 16:44:22 -07004304static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004305msmsdcc_runtime_suspend(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004306{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307 struct mmc_host *mmc = dev_get_drvdata(dev);
4308 struct msmsdcc_host *host = mmc_priv(mmc);
San Mehat9d2bd732009-09-22 16:44:22 -07004309 int rc = 0;
4310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004311 if (host->plat->is_sdio_al_client)
4312 return 0;
4313
Sahitya Tummala7661a452011-07-18 13:28:35 +05304314 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004315 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316 host->sdcc_suspending = 1;
4317 mmc->suspend_task = current;
San Mehat9d2bd732009-09-22 16:44:22 -07004318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004319 /*
4320 * If the clocks are already turned off by SDIO clients (as
4321 * part of LPM), then clocks should be turned on before
4322 * calling mmc_suspend_host() because mmc_suspend_host might
4323 * send some commands to the card. The clocks will be turned
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304324 * off again after mmc_suspend_host. Thus for SDIO
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004325 * cards, clocks will be turned on before mmc_suspend_host
4326 * and turned off after mmc_suspend_host.
4327 */
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304328 if (mmc->card && mmc_card_sdio(mmc->card)) {
4329 mmc->ios.clock = host->clk_rate;
4330 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4331 }
San Mehat9d2bd732009-09-22 16:44:22 -07004332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333 /*
4334 * MMC core thinks that host is disabled by now since
4335 * runtime suspend is scheduled after msmsdcc_disable()
4336 * is called. Thus, MMC core will try to enable the host
4337 * while suspending it. This results in a synchronous
4338 * runtime resume request while in runtime suspending
4339 * context and hence inorder to complete this resume
4340 * requet, it will wait for suspend to be complete,
4341 * but runtime suspend also can not proceed further
4342 * until the host is resumed. Thus, it leads to a hang.
4343 * Hence, increase the pm usage count before suspending
4344 * the host so that any resume requests after this will
4345 * simple become pm usage counter increment operations.
4346 */
4347 pm_runtime_get_noresume(dev);
4348 rc = mmc_suspend_host(mmc);
4349 pm_runtime_put_noidle(dev);
4350
4351 if (!rc) {
4352 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO) &&
4353 (mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) {
4354 disable_irq(host->core_irqres->start);
4355 host->sdcc_irq_disabled = 1;
4356
4357 /*
4358 * If MMC core level suspend is not supported,
4359 * turn off clocks to allow deep sleep (TCXO
4360 * shutdown).
4361 */
4362 mmc->ios.clock = 0;
4363 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
4364 enable_irq(host->core_irqres->start);
4365 host->sdcc_irq_disabled = 0;
4366
4367 if (host->plat->sdiowakeup_irq) {
4368 host->sdio_irq_disabled = 0;
4369 msmsdcc_enable_irq_wake(host);
4370 enable_irq(host->plat->sdiowakeup_irq);
4371 }
4372 }
4373 }
4374 host->sdcc_suspending = 0;
4375 mmc->suspend_task = NULL;
4376 if (rc && wake_lock_active(&host->sdio_suspend_wlock))
4377 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004378 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304379 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004380 return rc;
4381}
4382
4383static int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004384msmsdcc_runtime_resume(struct device *dev)
San Mehat9d2bd732009-09-22 16:44:22 -07004385{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004386 struct mmc_host *mmc = dev_get_drvdata(dev);
4387 struct msmsdcc_host *host = mmc_priv(mmc);
4388 unsigned long flags;
4389
4390 if (host->plat->is_sdio_al_client)
4391 return 0;
San Mehat9d2bd732009-09-22 16:44:22 -07004392
Sahitya Tummala7661a452011-07-18 13:28:35 +05304393 pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004394 if (mmc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004395 if (mmc->card && mmc->card->type == MMC_TYPE_SDIO) {
4396 if (host->sdcc_irq_disabled) {
4397 enable_irq(host->core_irqres->start);
4398 host->sdcc_irq_disabled = 0;
4399 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304400 mmc->ios.clock = host->clk_rate;
4401 mmc->ops->set_ios(host->mmc, &host->mmc->ios);
San Mehat9d2bd732009-09-22 16:44:22 -07004402
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304403 spin_lock_irqsave(&host->lock, flags);
4404 writel_relaxed(host->mci_irqenable,
4405 host->base + MMCIMASK0);
4406 mb();
San Mehat9d2bd732009-09-22 16:44:22 -07004407
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304408 if ((mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ) &&
4409 !host->sdio_irq_disabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004410 if (host->plat->sdiowakeup_irq) {
4411 disable_irq_nosync(
4412 host->plat->sdiowakeup_irq);
4413 msmsdcc_disable_irq_wake(host);
4414 host->sdio_irq_disabled = 1;
4415 }
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304416 }
San Mehat9d2bd732009-09-22 16:44:22 -07004417
Sujit Reddy Thummad16214c2011-10-19 11:06:50 +05304418 spin_unlock_irqrestore(&host->lock, flags);
4419 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004420
4421 mmc_resume_host(mmc);
4422
4423 /*
4424 * FIXME: Clearing of flags must be handled in clients
4425 * resume handler.
4426 */
4427 spin_lock_irqsave(&host->lock, flags);
4428 mmc->pm_flags = 0;
4429 spin_unlock_irqrestore(&host->lock, flags);
4430
4431 /*
4432 * After resuming the host wait for sometime so that
4433 * the SDIO work will be processed.
4434 */
4435 if (mmc->card && (mmc->card->type == MMC_TYPE_SDIO)) {
4436 if ((host->plat->cfg_mpm_sdiowakeup ||
4437 host->plat->sdiowakeup_irq) &&
4438 wake_lock_active(&host->sdio_wlock))
4439 wake_lock_timeout(&host->sdio_wlock, 1);
4440 }
4441
4442 wake_unlock(&host->sdio_suspend_wlock);
San Mehat9d2bd732009-09-22 16:44:22 -07004443 }
Sahitya Tummala7661a452011-07-18 13:28:35 +05304444 pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07004445 return 0;
4446}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004447
4448static int msmsdcc_runtime_idle(struct device *dev)
4449{
4450 struct mmc_host *mmc = dev_get_drvdata(dev);
4451 struct msmsdcc_host *host = mmc_priv(mmc);
4452
4453 if (host->plat->is_sdio_al_client)
4454 return 0;
4455
4456 /* Idle timeout is not configurable for now */
4457 pm_schedule_suspend(dev, MSM_MMC_IDLE_TIMEOUT);
4458
4459 return -EAGAIN;
4460}
4461
4462static int msmsdcc_pm_suspend(struct device *dev)
4463{
4464 struct mmc_host *mmc = dev_get_drvdata(dev);
4465 struct msmsdcc_host *host = mmc_priv(mmc);
4466 int rc = 0;
4467
4468 if (host->plat->is_sdio_al_client)
4469 return 0;
4470
4471
4472 if (host->plat->status_irq)
4473 disable_irq(host->plat->status_irq);
4474
4475 if (!pm_runtime_suspended(dev))
4476 rc = msmsdcc_runtime_suspend(dev);
4477
4478 return rc;
4479}
4480
4481static int msmsdcc_pm_resume(struct device *dev)
4482{
4483 struct mmc_host *mmc = dev_get_drvdata(dev);
4484 struct msmsdcc_host *host = mmc_priv(mmc);
4485 int rc = 0;
4486
4487 if (host->plat->is_sdio_al_client)
4488 return 0;
4489
Sahitya Tummalafb486372011-09-02 19:01:49 +05304490 if (!pm_runtime_suspended(dev))
4491 rc = msmsdcc_runtime_resume(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004492 if (host->plat->status_irq) {
4493 msmsdcc_check_status((unsigned long)host);
4494 enable_irq(host->plat->status_irq);
4495 }
4496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004497 return rc;
4498}
4499
Daniel Walker08ecfde2010-06-23 12:32:20 -07004500#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004501#define msmsdcc_runtime_suspend NULL
4502#define msmsdcc_runtime_resume NULL
4503#define msmsdcc_runtime_idle NULL
4504#define msmsdcc_pm_suspend NULL
4505#define msmsdcc_pm_resume NULL
Daniel Walker08ecfde2010-06-23 12:32:20 -07004506#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
4509 .runtime_suspend = msmsdcc_runtime_suspend,
4510 .runtime_resume = msmsdcc_runtime_resume,
4511 .runtime_idle = msmsdcc_runtime_idle,
4512 .suspend = msmsdcc_pm_suspend,
4513 .resume = msmsdcc_pm_resume,
4514};
4515
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304516static const struct of_device_id msmsdcc_dt_match[] = {
4517 {.compatible = "qcom,msm-sdcc"},
4518
4519};
4520MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
4521
San Mehat9d2bd732009-09-22 16:44:22 -07004522static struct platform_driver msmsdcc_driver = {
4523 .probe = msmsdcc_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 .remove = msmsdcc_remove,
San Mehat9d2bd732009-09-22 16:44:22 -07004525 .driver = {
4526 .name = "msm_sdcc",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004527 .pm = &msmsdcc_dev_pm_ops,
Sujit Reddy Thumma7285c2e2011-11-04 10:18:15 +05304528 .of_match_table = msmsdcc_dt_match,
San Mehat9d2bd732009-09-22 16:44:22 -07004529 },
4530};
4531
4532static int __init msmsdcc_init(void)
4533{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004534#if defined(CONFIG_DEBUG_FS)
4535 int ret = 0;
4536 ret = msmsdcc_dbg_init();
4537 if (ret) {
4538 pr_err("Failed to create debug fs dir \n");
4539 return ret;
4540 }
4541#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004542 return platform_driver_register(&msmsdcc_driver);
4543}
4544
4545static void __exit msmsdcc_exit(void)
4546{
4547 platform_driver_unregister(&msmsdcc_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548
4549#if defined(CONFIG_DEBUG_FS)
4550 debugfs_remove(debugfs_file);
4551 debugfs_remove(debugfs_dir);
4552#endif
San Mehat9d2bd732009-09-22 16:44:22 -07004553}
4554
4555module_init(msmsdcc_init);
4556module_exit(msmsdcc_exit);
4557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558MODULE_DESCRIPTION("Qualcomm Multimedia Card Interface driver");
San Mehat9d2bd732009-09-22 16:44:22 -07004559MODULE_LICENSE("GPL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004560
4561#if defined(CONFIG_DEBUG_FS)
4562
4563static int
4564msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
4565{
4566 file->private_data = inode->i_private;
4567 return 0;
4568}
4569
4570static ssize_t
4571msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
4572 size_t count, loff_t *ppos)
4573{
4574 struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
4575 char buf[1024];
4576 int max, i;
4577
4578 i = 0;
4579 max = sizeof(buf) - 1;
4580
4581 i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
4582 host->curr.cmd, host->curr.data);
4583 if (host->curr.cmd) {
4584 struct mmc_command *cmd = host->curr.cmd;
4585
4586 i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
4587 cmd->opcode, cmd->arg, cmd->flags);
4588 }
4589 if (host->curr.data) {
4590 struct mmc_data *data = host->curr.data;
4591 i += scnprintf(buf + i, max - i,
4592 "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
4593 data->timeout_ns, data->timeout_clks,
4594 data->blksz, data->blocks, data->error,
4595 data->flags);
4596 i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
4597 host->curr.xfer_size, host->curr.xfer_remain,
4598 host->curr.data_xfered, host->dma.sg);
4599 }
4600
4601 return simple_read_from_buffer(ubuf, count, ppos, buf, i);
4602}
4603
4604static const struct file_operations msmsdcc_dbg_state_ops = {
4605 .read = msmsdcc_dbg_state_read,
4606 .open = msmsdcc_dbg_state_open,
4607};
4608
4609static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
4610{
4611 if (debugfs_dir) {
4612 debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
4613 0644, debugfs_dir, host,
4614 &msmsdcc_dbg_state_ops);
4615 }
4616}
4617
4618static int __init msmsdcc_dbg_init(void)
4619{
4620 int err;
4621
4622 debugfs_dir = debugfs_create_dir("msmsdcc", 0);
4623 if (IS_ERR(debugfs_dir)) {
4624 err = PTR_ERR(debugfs_dir);
4625 debugfs_dir = NULL;
4626 return err;
4627 }
4628
4629 return 0;
4630}
4631#endif