blob: 84b284e3a288c221b68ee2b6cf830725bc9e8074 [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.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Based on mmci.c
12 *
13 * Author: San Mehat (san@android.com)
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/init.h>
20#include <linux/ioport.h>
21#include <linux/device.h>
22#include <linux/interrupt.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/highmem.h>
26#include <linux/log2.h>
27#include <linux/mmc/host.h>
28#include <linux/mmc/card.h>
San Mehatb3fa5792009-11-02 18:46:09 -080029#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070030#include <linux/clk.h>
31#include <linux/scatterlist.h>
32#include <linux/platform_device.h>
33#include <linux/dma-mapping.h>
34#include <linux/debugfs.h>
35#include <linux/io.h>
36#include <linux/memory.h>
37
38#include <asm/cacheflush.h>
39#include <asm/div64.h>
40#include <asm/sizes.h>
41
Pavel Machek3989d172009-12-08 11:11:36 -080042#include <mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070043#include <mach/msm_iomap.h>
44#include <mach/dma.h>
San Mehat9d2bd732009-09-22 16:44:22 -070045
San Mehat9d2bd732009-09-22 16:44:22 -070046#include "msm_sdcc.h"
47
48#define DRIVER_NAME "msm-sdcc"
49
50static unsigned int msmsdcc_fmin = 144000;
51static unsigned int msmsdcc_fmax = 50000000;
52static unsigned int msmsdcc_4bit = 1;
53static unsigned int msmsdcc_pwrsave = 1;
54static unsigned int msmsdcc_piopoll = 1;
55static unsigned int msmsdcc_sdioirq;
56
57#define PIO_SPINMAX 30
58#define CMD_SPINMAX 20
59
San Mehat865c80642009-11-13 13:42:06 -080060
61static inline int
62msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
63{
64 int rc;
San Mehat8b1c2ba2009-11-16 10:17:30 -080065
San Mehat865c80642009-11-13 13:42:06 -080066 WARN_ON(enable == host->clks_on);
67 if (enable) {
68 rc = clk_enable(host->pclk);
69 if (rc)
70 return rc;
71 rc = clk_enable(host->clk);
72 if (rc) {
73 clk_disable(host->pclk);
74 return rc;
75 }
San Mehat8b1c2ba2009-11-16 10:17:30 -080076 udelay(1 + ((3 * USEC_PER_SEC) /
77 (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
San Mehat865c80642009-11-13 13:42:06 -080078 host->clks_on = 1;
79 } else {
80 clk_disable(host->clk);
81 clk_disable(host->pclk);
82 host->clks_on = 0;
83 }
84 return 0;
85}
86
San Mehat8b1c2ba2009-11-16 10:17:30 -080087static inline unsigned int
88msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg)
89{
90 return readl(host->base + reg);
91}
92
93static inline void
94msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg)
95{
96 writel(data, host->base + reg);
97 /* 3 clk delay required! */
98 udelay(1 + ((3 * USEC_PER_SEC) /
99 (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
100}
San Mehat865c80642009-11-13 13:42:06 -0800101
San Mehat9d2bd732009-09-22 16:44:22 -0700102static void
103msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
104 u32 c);
105
106static void
107msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
108{
San Mehat8b1c2ba2009-11-16 10:17:30 -0800109 msmsdcc_writel(host, 0, MMCICOMMAND);
San Mehat9d2bd732009-09-22 16:44:22 -0700110
111 BUG_ON(host->curr.data);
112
113 host->curr.mrq = NULL;
114 host->curr.cmd = NULL;
115
116 if (mrq->data)
117 mrq->data->bytes_xfered = host->curr.data_xfered;
118 if (mrq->cmd->error == -ETIMEDOUT)
119 mdelay(5);
120
San Mehat865c80642009-11-13 13:42:06 -0800121 if (host->use_bustimer)
122 mod_timer(&host->busclk_timer, jiffies + HZ);
San Mehat9d2bd732009-09-22 16:44:22 -0700123 /*
124 * Need to drop the host lock here; mmc_request_done may call
125 * back into the driver...
126 */
127 spin_unlock(&host->lock);
128 mmc_request_done(host->mmc, mrq);
129 spin_lock(&host->lock);
130}
131
132static void
133msmsdcc_stop_data(struct msmsdcc_host *host)
134{
San Mehat8b1c2ba2009-11-16 10:17:30 -0800135 msmsdcc_writel(host, 0, MMCIDATACTRL);
San Mehat9d2bd732009-09-22 16:44:22 -0700136 host->curr.data = NULL;
137 host->curr.got_dataend = host->curr.got_datablkend = 0;
138}
139
140uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
141{
Joe Perches75d14522009-09-22 16:44:24 -0700142 switch (host->pdev_id) {
143 case 1:
San Mehat9d2bd732009-09-22 16:44:22 -0700144 return MSM_SDC1_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700145 case 2:
San Mehat9d2bd732009-09-22 16:44:22 -0700146 return MSM_SDC2_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700147 case 3:
San Mehat9d2bd732009-09-22 16:44:22 -0700148 return MSM_SDC3_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700149 case 4:
San Mehat9d2bd732009-09-22 16:44:22 -0700150 return MSM_SDC4_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700151 }
152 BUG();
San Mehat9d2bd732009-09-22 16:44:22 -0700153 return 0;
154}
155
156static void
157msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
158 unsigned int result,
159 struct msm_dmov_errdata *err)
160{
161 struct msmsdcc_dma_data *dma_data =
162 container_of(cmd, struct msmsdcc_dma_data, hdr);
163 struct msmsdcc_host *host = dma_data->host;
164 unsigned long flags;
165 struct mmc_request *mrq;
166
167 spin_lock_irqsave(&host->lock, flags);
168 mrq = host->curr.mrq;
169 BUG_ON(!mrq);
170
171 if (!(result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700172 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700173 goto out;
174 }
175
176 if (result & DMOV_RSLT_DONE) {
177 host->curr.data_xfered = host->curr.xfer_size;
178 } else {
179 /* Error or flush */
180 if (result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700181 pr_err("%s: DMA error (0x%.8x)\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700182 mmc_hostname(host->mmc), result);
183 if (result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700184 pr_err("%s: DMA channel flushed (0x%.8x)\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700185 mmc_hostname(host->mmc), result);
186 if (err)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700187 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700188 err->flush[0], err->flush[1], err->flush[2],
189 err->flush[3], err->flush[4], err->flush[5]);
190 if (!mrq->data->error)
191 mrq->data->error = -EIO;
192 }
193 host->dma.busy = 0;
194 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
195 host->dma.dir);
196
197 if (host->curr.user_pages) {
198 struct scatterlist *sg = host->dma.sg;
199 int i;
200
Joe Perches75d14522009-09-22 16:44:24 -0700201 for (i = 0; i < host->dma.num_ents; i++)
202 flush_dcache_page(sg_page(sg++));
San Mehat9d2bd732009-09-22 16:44:22 -0700203 }
204
205 host->dma.sg = NULL;
206
207 if ((host->curr.got_dataend && host->curr.got_datablkend)
208 || mrq->data->error) {
209
210 /*
211 * If we've already gotten our DATAEND / DATABLKEND
212 * for this request, then complete it through here.
213 */
214 msmsdcc_stop_data(host);
215
216 if (!mrq->data->error)
217 host->curr.data_xfered = host->curr.xfer_size;
218 if (!mrq->data->stop || mrq->cmd->error) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800219 msmsdcc_writel(host, 0, MMCICOMMAND);
San Mehat9d2bd732009-09-22 16:44:22 -0700220 host->curr.mrq = NULL;
221 host->curr.cmd = NULL;
222 mrq->data->bytes_xfered = host->curr.data_xfered;
223
224 spin_unlock_irqrestore(&host->lock, flags);
225 mmc_request_done(host->mmc, mrq);
226 return;
227 } else
228 msmsdcc_start_command(host, mrq->data->stop, 0);
229 }
230
231out:
232 spin_unlock_irqrestore(&host->lock, flags);
233 return;
234}
235
236static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
237{
238 if (host->dma.channel == -1)
239 return -ENOENT;
240
241 if ((data->blksz * data->blocks) < MCI_FIFOSIZE)
242 return -EINVAL;
243 if ((data->blksz * data->blocks) % MCI_FIFOSIZE)
244 return -EINVAL;
245 return 0;
246}
247
248static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
249{
250 struct msmsdcc_nc_dmadata *nc;
251 dmov_box *box;
252 uint32_t rows;
253 uint32_t crci;
254 unsigned int n;
255 int i, rc;
256 struct scatterlist *sg = data->sg;
257
258 rc = validate_dma(host, data);
259 if (rc)
260 return rc;
261
262 host->dma.sg = data->sg;
263 host->dma.num_ents = data->sg_len;
264
265 nc = host->dma.nc;
266
Joe Perches75d14522009-09-22 16:44:24 -0700267 switch (host->pdev_id) {
268 case 1:
San Mehat9d2bd732009-09-22 16:44:22 -0700269 crci = MSMSDCC_CRCI_SDC1;
Joe Perches75d14522009-09-22 16:44:24 -0700270 break;
271 case 2:
San Mehat9d2bd732009-09-22 16:44:22 -0700272 crci = MSMSDCC_CRCI_SDC2;
Joe Perches75d14522009-09-22 16:44:24 -0700273 break;
274 case 3:
San Mehat9d2bd732009-09-22 16:44:22 -0700275 crci = MSMSDCC_CRCI_SDC3;
Joe Perches75d14522009-09-22 16:44:24 -0700276 break;
277 case 4:
San Mehat9d2bd732009-09-22 16:44:22 -0700278 crci = MSMSDCC_CRCI_SDC4;
Joe Perches75d14522009-09-22 16:44:24 -0700279 break;
280 default:
San Mehat9d2bd732009-09-22 16:44:22 -0700281 host->dma.sg = NULL;
282 host->dma.num_ents = 0;
283 return -ENOENT;
284 }
285
286 if (data->flags & MMC_DATA_READ)
287 host->dma.dir = DMA_FROM_DEVICE;
288 else
289 host->dma.dir = DMA_TO_DEVICE;
290
291 host->curr.user_pages = 0;
292
293 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
Joe Perches75d14522009-09-22 16:44:24 -0700294 host->dma.num_ents, host->dma.dir);
San Mehat9d2bd732009-09-22 16:44:22 -0700295
296 if (n != host->dma.num_ents) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700297 pr_err("%s: Unable to map in all sg elements\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700298 mmc_hostname(host->mmc));
299 host->dma.sg = NULL;
300 host->dma.num_ents = 0;
301 return -ENOMEM;
302 }
303
304 box = &nc->cmd[0];
305 for (i = 0; i < host->dma.num_ents; i++) {
306 box->cmd = CMD_MODE_BOX;
307
308 if (i == (host->dma.num_ents - 1))
309 box->cmd |= CMD_LC;
310 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
311 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
312 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
313
314 if (data->flags & MMC_DATA_READ) {
315 box->src_row_addr = msmsdcc_fifo_addr(host);
316 box->dst_row_addr = sg_dma_address(sg);
317
318 box->src_dst_len = (MCI_FIFOSIZE << 16) |
319 (MCI_FIFOSIZE);
320 box->row_offset = MCI_FIFOSIZE;
321
322 box->num_rows = rows * ((1 << 16) + 1);
323 box->cmd |= CMD_SRC_CRCI(crci);
324 } else {
325 box->src_row_addr = sg_dma_address(sg);
326 box->dst_row_addr = msmsdcc_fifo_addr(host);
327
328 box->src_dst_len = (MCI_FIFOSIZE << 16) |
329 (MCI_FIFOSIZE);
330 box->row_offset = (MCI_FIFOSIZE << 16);
331
332 box->num_rows = rows * ((1 << 16) + 1);
333 box->cmd |= CMD_DST_CRCI(crci);
334 }
335 box++;
336 sg++;
337 }
338
339 /* location of command block must be 64 bit aligned */
340 BUG_ON(host->dma.cmd_busaddr & 0x07);
341
342 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
343 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
344 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
345 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
San Mehat5b00f402009-11-21 09:22:14 -0800346 host->dma.hdr.execute_func = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -0700347
348 return 0;
349}
350
351static void
352msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data)
353{
354 unsigned int datactrl, timeout;
355 unsigned long long clks;
San Mehat9d2bd732009-09-22 16:44:22 -0700356 unsigned int pio_irqmask = 0;
357
358 host->curr.data = data;
359 host->curr.xfer_size = data->blksz * data->blocks;
360 host->curr.xfer_remain = host->curr.xfer_size;
361 host->curr.data_xfered = 0;
362 host->curr.got_dataend = 0;
363 host->curr.got_datablkend = 0;
364
365 memset(&host->pio, 0, sizeof(host->pio));
366
367 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
Joe Perches75d14522009-09-22 16:44:24 -0700368 do_div(clks, NSEC_PER_SEC);
San Mehat9d2bd732009-09-22 16:44:22 -0700369 timeout = data->timeout_clks + (unsigned int)clks;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800370 msmsdcc_writel(host, timeout, MMCIDATATIMER);
San Mehat9d2bd732009-09-22 16:44:22 -0700371
San Mehat8b1c2ba2009-11-16 10:17:30 -0800372 msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
San Mehat9d2bd732009-09-22 16:44:22 -0700373
374 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
375
376 if (!msmsdcc_config_dma(host, data))
377 datactrl |= MCI_DPSM_DMAENABLE;
378 else {
379 host->pio.sg = data->sg;
380 host->pio.sg_len = data->sg_len;
381 host->pio.sg_off = 0;
382
383 if (data->flags & MMC_DATA_READ) {
384 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
385 if (host->curr.xfer_remain < MCI_FIFOSIZE)
386 pio_irqmask |= MCI_RXDATAAVLBLMASK;
387 } else
388 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK;
389 }
390
391 if (data->flags & MMC_DATA_READ)
392 datactrl |= MCI_DPSM_DIRECTION;
393
San Mehat8b1c2ba2009-11-16 10:17:30 -0800394 msmsdcc_writel(host, pio_irqmask, MMCIMASK1);
395 msmsdcc_writel(host, datactrl, MMCIDATACTRL);
San Mehat9d2bd732009-09-22 16:44:22 -0700396
397 if (datactrl & MCI_DPSM_DMAENABLE) {
398 host->dma.busy = 1;
399 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
400 }
401}
402
San Mehatb3fa5792009-11-02 18:46:09 -0800403static int
404snoop_cccr_abort(struct mmc_command *cmd)
405{
406 if ((cmd->opcode == 52) &&
407 (cmd->arg & 0x80000000) &&
408 (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT))
409 return 1;
410 return 0;
411}
412
San Mehat9d2bd732009-09-22 16:44:22 -0700413static void
414msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
415{
San Mehat8b1c2ba2009-11-16 10:17:30 -0800416 if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE)
417 msmsdcc_writel(host, 0, MMCICOMMAND);
San Mehat9d2bd732009-09-22 16:44:22 -0700418
419 c |= cmd->opcode | MCI_CPSM_ENABLE;
420
421 if (cmd->flags & MMC_RSP_PRESENT) {
422 if (cmd->flags & MMC_RSP_136)
423 c |= MCI_CPSM_LONGRSP;
424 c |= MCI_CPSM_RESPONSE;
425 }
426
Joe Perches75d14522009-09-22 16:44:24 -0700427 if (cmd->opcode == 17 || cmd->opcode == 18 ||
428 cmd->opcode == 24 || cmd->opcode == 25 ||
429 cmd->opcode == 53)
San Mehat9d2bd732009-09-22 16:44:22 -0700430 c |= MCI_CSPM_DATCMD;
431
432 if (cmd == cmd->mrq->stop)
433 c |= MCI_CSPM_MCIABORT;
434
San Mehatb3fa5792009-11-02 18:46:09 -0800435 if (snoop_cccr_abort(cmd))
436 c |= MCI_CSPM_MCIABORT;
437
San Mehat9d2bd732009-09-22 16:44:22 -0700438 host->curr.cmd = cmd;
439
440 host->stats.cmds++;
441
San Mehat8b1c2ba2009-11-16 10:17:30 -0800442 msmsdcc_writel(host, cmd->arg, MMCIARGUMENT);
443 msmsdcc_writel(host, c, MMCICOMMAND);
San Mehat9d2bd732009-09-22 16:44:22 -0700444}
445
446static void
447msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
448 unsigned int status)
449{
450 if (status & MCI_DATACRCFAIL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700451 pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc));
452 pr_err("%s: opcode 0x%.8x\n", __func__,
San Mehat9d2bd732009-09-22 16:44:22 -0700453 data->mrq->cmd->opcode);
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700454 pr_err("%s: blksz %d, blocks %d\n", __func__,
San Mehat9d2bd732009-09-22 16:44:22 -0700455 data->blksz, data->blocks);
456 data->error = -EILSEQ;
457 } else if (status & MCI_DATATIMEOUT) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700458 pr_err("%s: Data timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700459 data->error = -ETIMEDOUT;
460 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700461 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700462 data->error = -EIO;
463 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700464 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700465 data->error = -EIO;
466 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700467 pr_err("%s: Unknown error (0x%.8x)\n",
468 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -0700469 data->error = -EIO;
470 }
471}
472
473
474static int
475msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
476{
San Mehat9d2bd732009-09-22 16:44:22 -0700477 uint32_t *ptr = (uint32_t *) buffer;
478 int count = 0;
479
San Mehat8b1c2ba2009-11-16 10:17:30 -0800480 while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
481 *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -0700482 ptr++;
483 count += sizeof(uint32_t);
484
485 remain -= sizeof(uint32_t);
486 if (remain == 0)
487 break;
488 }
489 return count;
490}
491
492static int
493msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
494 unsigned int remain, u32 status)
495{
496 void __iomem *base = host->base;
497 char *ptr = buffer;
498
499 do {
500 unsigned int count, maxcnt;
501
502 maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
503 MCI_FIFOHALFSIZE;
504 count = min(remain, maxcnt);
505
506 writesl(base + MMCIFIFO, ptr, count >> 2);
507 ptr += count;
508 remain -= count;
509
510 if (remain == 0)
511 break;
512
San Mehat8b1c2ba2009-11-16 10:17:30 -0800513 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700514 } while (status & MCI_TXFIFOHALFEMPTY);
515
516 return ptr - buffer;
517}
518
519static int
520msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin)
521{
522 while (maxspin) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800523 if ((msmsdcc_readl(host, MMCISTATUS) & mask))
San Mehat9d2bd732009-09-22 16:44:22 -0700524 return 0;
525 udelay(1);
526 --maxspin;
527 }
528 return -ETIMEDOUT;
529}
530
531static int
532msmsdcc_pio_irq(int irq, void *dev_id)
533{
534 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -0700535 uint32_t status;
536
San Mehat8b1c2ba2009-11-16 10:17:30 -0800537 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700538
539 do {
540 unsigned long flags;
541 unsigned int remain, len;
542 char *buffer;
543
544 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) {
545 if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll)
546 break;
547
548 if (msmsdcc_spin_on_status(host,
549 (MCI_TXFIFOHALFEMPTY |
550 MCI_RXDATAAVLBL),
551 PIO_SPINMAX)) {
552 break;
553 }
554 }
555
556 /* Map the current scatter buffer */
557 local_irq_save(flags);
558 buffer = kmap_atomic(sg_page(host->pio.sg),
559 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
560 buffer += host->pio.sg_off;
561 remain = host->pio.sg->length - host->pio.sg_off;
562 len = 0;
563 if (status & MCI_RXACTIVE)
564 len = msmsdcc_pio_read(host, buffer, remain);
565 if (status & MCI_TXACTIVE)
566 len = msmsdcc_pio_write(host, buffer, remain, status);
567
568 /* Unmap the buffer */
569 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
570 local_irq_restore(flags);
571
572 host->pio.sg_off += len;
573 host->curr.xfer_remain -= len;
574 host->curr.data_xfered += len;
575 remain -= len;
576
577 if (remain == 0) {
578 /* This sg page is full - do some housekeeping */
579 if (status & MCI_RXACTIVE && host->curr.user_pages)
580 flush_dcache_page(sg_page(host->pio.sg));
581
582 if (!--host->pio.sg_len) {
583 memset(&host->pio, 0, sizeof(host->pio));
584 break;
585 }
586
587 /* Advance to next sg */
588 host->pio.sg++;
589 host->pio.sg_off = 0;
590 }
591
San Mehat8b1c2ba2009-11-16 10:17:30 -0800592 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700593 } while (1);
594
595 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE)
San Mehat8b1c2ba2009-11-16 10:17:30 -0800596 msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1);
San Mehat9d2bd732009-09-22 16:44:22 -0700597
598 if (!host->curr.xfer_remain)
San Mehat8b1c2ba2009-11-16 10:17:30 -0800599 msmsdcc_writel(host, 0, MMCIMASK1);
San Mehat9d2bd732009-09-22 16:44:22 -0700600
601 return IRQ_HANDLED;
602}
603
604static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
605{
606 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700607
608 host->curr.cmd = NULL;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800609 cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0);
610 cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1);
611 cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
612 cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -0700613
614 del_timer(&host->command_timer);
615 if (status & MCI_CMDTIMEOUT) {
616 cmd->error = -ETIMEDOUT;
617 } else if (status & MCI_CMDCRCFAIL &&
618 cmd->flags & MMC_RSP_CRC) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700619 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700620 cmd->error = -EILSEQ;
621 }
622
623 if (!cmd->data || cmd->error) {
624 if (host->curr.data && host->dma.sg)
625 msm_dmov_stop_cmd(host->dma.channel,
626 &host->dma.hdr, 0);
627 else if (host->curr.data) { /* Non DMA */
628 msmsdcc_stop_data(host);
629 msmsdcc_request_end(host, cmd->mrq);
630 } else /* host->data == NULL */
631 msmsdcc_request_end(host, cmd->mrq);
632 } else if (!(cmd->data->flags & MMC_DATA_READ))
633 msmsdcc_start_data(host, cmd->data);
634}
635
Joe Perchesb5a74d62009-09-22 16:44:25 -0700636static void
637msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
638 void __iomem *base)
639{
640 struct mmc_data *data = host->curr.data;
641
642 if (!data)
643 return;
644
645 /* Check for data errors */
646 if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
647 MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
648 msmsdcc_data_err(host, data, status);
649 host->curr.data_xfered = 0;
650 if (host->dma.sg)
651 msm_dmov_stop_cmd(host->dma.channel,
652 &host->dma.hdr, 0);
653 else {
654 msmsdcc_stop_data(host);
655 if (!data->stop)
656 msmsdcc_request_end(host, data->mrq);
657 else
658 msmsdcc_start_command(host, data->stop, 0);
659 }
660 }
661
662 /* Check for data done */
663 if (!host->curr.got_dataend && (status & MCI_DATAEND))
664 host->curr.got_dataend = 1;
665
666 if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND))
667 host->curr.got_datablkend = 1;
668
669 /*
670 * If DMA is still in progress, we complete via the completion handler
671 */
672 if (host->curr.got_dataend && host->curr.got_datablkend &&
673 !host->dma.busy) {
674 /*
675 * There appears to be an issue in the controller where
676 * if you request a small block transfer (< fifo size),
677 * you may get your DATAEND/DATABLKEND irq without the
678 * PIO data irq.
679 *
680 * Check to see if there is still data to be read,
681 * and simulate a PIO irq.
682 */
683 if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL)
684 msmsdcc_pio_irq(1, host);
685
686 msmsdcc_stop_data(host);
687 if (!data->error)
688 host->curr.data_xfered = host->curr.xfer_size;
689
690 if (!data->stop)
691 msmsdcc_request_end(host, data->mrq);
692 else
693 msmsdcc_start_command(host, data->stop, 0);
694 }
695}
696
San Mehat9d2bd732009-09-22 16:44:22 -0700697static irqreturn_t
698msmsdcc_irq(int irq, void *dev_id)
699{
700 struct msmsdcc_host *host = dev_id;
701 void __iomem *base = host->base;
702 u32 status;
703 int ret = 0;
704 int cardint = 0;
705
706 spin_lock(&host->lock);
707
708 do {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800709 struct mmc_data *data;
710 status = msmsdcc_readl(host, MMCISTATUS);
711 status &= (msmsdcc_readl(host, MMCIMASK0) |
712 MCI_DATABLOCKENDMASK);
713 msmsdcc_writel(host, status, MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -0700714
San Mehat865c80642009-11-13 13:42:06 -0800715 if (status & MCI_SDIOINTR)
716 status &= ~MCI_SDIOINTR;
717
718 if (!status)
719 break;
720
Joe Perchesb5a74d62009-09-22 16:44:25 -0700721 msmsdcc_handle_irq_data(host, status, base);
San Mehat9d2bd732009-09-22 16:44:22 -0700722
723 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
724 MCI_CMDTIMEOUT) && host->curr.cmd) {
725 msmsdcc_do_cmdirq(host, status);
726 }
727
728 if (status & MCI_SDIOINTOPER) {
729 cardint = 1;
730 status &= ~MCI_SDIOINTOPER;
731 }
732 ret = 1;
733 } while (status);
734
735 spin_unlock(&host->lock);
736
737 /*
738 * We have to delay handling the card interrupt as it calls
739 * back into the driver.
740 */
741 if (cardint)
742 mmc_signal_sdio_irq(host->mmc);
743
744 return IRQ_RETVAL(ret);
745}
746
747static void
748msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
749{
750 struct msmsdcc_host *host = mmc_priv(mmc);
751 unsigned long flags;
752
753 WARN_ON(host->curr.mrq != NULL);
754 WARN_ON(host->pwr == 0);
755
756 spin_lock_irqsave(&host->lock, flags);
757
758 host->stats.reqs++;
759
760 if (host->eject) {
761 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
762 mrq->cmd->error = 0;
763 mrq->data->bytes_xfered = mrq->data->blksz *
764 mrq->data->blocks;
765 } else
766 mrq->cmd->error = -ENOMEDIUM;
767
768 spin_unlock_irqrestore(&host->lock, flags);
769 mmc_request_done(mmc, mrq);
770 return;
771 }
772
773 host->curr.mrq = mrq;
San Mehat865c80642009-11-13 13:42:06 -0800774 if (!host->clks_on)
775 msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -0700776
777 if (mrq->data && mrq->data->flags & MMC_DATA_READ)
778 msmsdcc_start_data(host, mrq->data);
779
780 msmsdcc_start_command(host, mrq->cmd, 0);
781
782 if (host->cmdpoll && !msmsdcc_spin_on_status(host,
783 MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
784 CMD_SPINMAX)) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800785 uint32_t status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700786 msmsdcc_do_cmdirq(host, status);
San Mehat8b1c2ba2009-11-16 10:17:30 -0800787 msmsdcc_writel(host,
788 MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT,
789 MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -0700790 host->stats.cmdpoll_hits++;
791 } else {
792 host->stats.cmdpoll_misses++;
793 mod_timer(&host->command_timer, jiffies + HZ);
794 }
795 spin_unlock_irqrestore(&host->lock, flags);
796}
797
798static void
799msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
800{
801 struct msmsdcc_host *host = mmc_priv(mmc);
802 u32 clk = 0, pwr = 0;
803 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -0800804 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -0700805
San Mehat4adbbcc2009-11-08 13:00:37 -0800806 spin_lock_irqsave(&host->lock, flags);
San Mehat865c80642009-11-13 13:42:06 -0800807 if (!host->clks_on)
808 msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -0700809
San Mehat865c80642009-11-13 13:42:06 -0800810 if (ios->clock) {
San Mehat9d2bd732009-09-22 16:44:22 -0700811 if (ios->clock != host->clk_rate) {
812 rc = clk_set_rate(host->clk, ios->clock);
813 if (rc < 0)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700814 pr_err("%s: Error setting clock rate (%d)\n",
815 mmc_hostname(host->mmc), rc);
San Mehat9d2bd732009-09-22 16:44:22 -0700816 else
817 host->clk_rate = ios->clock;
818 }
819 clk |= MCI_CLK_ENABLE;
820 }
821
822 if (ios->bus_width == MMC_BUS_WIDTH_4)
823 clk |= (2 << 10); /* Set WIDEBUS */
824
825 if (ios->clock > 400000 && msmsdcc_pwrsave)
826 clk |= (1 << 9); /* PWRSAVE */
827
828 clk |= (1 << 12); /* FLOW_ENA */
829 clk |= (1 << 15); /* feedback clock */
830
831 if (host->plat->translate_vdd)
832 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
833
834 switch (ios->power_mode) {
835 case MMC_POWER_OFF:
San Mehat9d2bd732009-09-22 16:44:22 -0700836 break;
837 case MMC_POWER_UP:
838 pwr |= MCI_PWR_UP;
839 break;
840 case MMC_POWER_ON:
San Mehat9d2bd732009-09-22 16:44:22 -0700841 pwr |= MCI_PWR_ON;
842 break;
843 }
844
845 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
846 pwr |= MCI_OD;
847
San Mehat8b1c2ba2009-11-16 10:17:30 -0800848 msmsdcc_writel(host, clk, MMCICLOCK);
San Mehat9d2bd732009-09-22 16:44:22 -0700849
850 if (host->pwr != pwr) {
851 host->pwr = pwr;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800852 msmsdcc_writel(host, pwr, MMCIPOWER);
San Mehat9d2bd732009-09-22 16:44:22 -0700853 }
San Mehat865c80642009-11-13 13:42:06 -0800854 if (host->clks_on)
San Mehat4adbbcc2009-11-08 13:00:37 -0800855 msmsdcc_enable_clocks(host, 0);
856 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -0700857}
858
859static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
860{
861 struct msmsdcc_host *host = mmc_priv(mmc);
862 unsigned long flags;
863 u32 status;
864
865 spin_lock_irqsave(&host->lock, flags);
866 if (msmsdcc_sdioirq == 1) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800867 status = msmsdcc_readl(host, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -0700868 if (enable)
869 status |= MCI_SDIOINTOPERMASK;
870 else
871 status &= ~MCI_SDIOINTOPERMASK;
872 host->saved_irq0mask = status;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800873 msmsdcc_writel(host, status, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -0700874 }
875 spin_unlock_irqrestore(&host->lock, flags);
876}
877
878static const struct mmc_host_ops msmsdcc_ops = {
879 .request = msmsdcc_request,
880 .set_ios = msmsdcc_set_ios,
881 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
882};
883
884static void
885msmsdcc_check_status(unsigned long data)
886{
887 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
888 unsigned int status;
889
890 if (!host->plat->status) {
891 mmc_detect_change(host->mmc, 0);
892 goto out;
893 }
894
895 status = host->plat->status(mmc_dev(host->mmc));
896 host->eject = !status;
897 if (status ^ host->oldstat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700898 pr_info("%s: Slot status change detected (%d -> %d)\n",
899 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -0700900 if (status)
901 mmc_detect_change(host->mmc, (5 * HZ) / 2);
902 else
903 mmc_detect_change(host->mmc, 0);
904 }
905
906 host->oldstat = status;
907
908out:
909 if (host->timer.function)
910 mod_timer(&host->timer, jiffies + HZ);
911}
912
913static irqreturn_t
914msmsdcc_platform_status_irq(int irq, void *dev_id)
915{
916 struct msmsdcc_host *host = dev_id;
917
918 printk(KERN_DEBUG "%s: %d\n", __func__, irq);
919 msmsdcc_check_status((unsigned long) host);
920 return IRQ_HANDLED;
921}
922
923static void
924msmsdcc_status_notify_cb(int card_present, void *dev_id)
925{
926 struct msmsdcc_host *host = dev_id;
927
928 printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc),
929 card_present);
930 msmsdcc_check_status((unsigned long) host);
931}
932
San Mehat865c80642009-11-13 13:42:06 -0800933static void
934msmsdcc_busclk_expired(unsigned long _data)
935{
936 struct msmsdcc_host *host = (struct msmsdcc_host *) _data;
937 unsigned long flags;
938
939 spin_lock_irqsave(&host->lock, flags);
940 if (host->clks_on)
941 msmsdcc_enable_clocks(host, 0);
942
943 spin_unlock_irqrestore(&host->lock, flags);
944}
945
San Mehat9d2bd732009-09-22 16:44:22 -0700946/*
947 * called when a command expires.
948 * Dump some debugging, and then error
949 * out the transaction.
950 */
951static void
952msmsdcc_command_expired(unsigned long _data)
953{
954 struct msmsdcc_host *host = (struct msmsdcc_host *) _data;
955 struct mmc_request *mrq;
956 unsigned long flags;
957
958 spin_lock_irqsave(&host->lock, flags);
959 mrq = host->curr.mrq;
960
961 if (!mrq) {
San Mehat9d2bd732009-09-22 16:44:22 -0700962 spin_unlock_irqrestore(&host->lock, flags);
963 return;
964 }
965
San Mehat8b1c2ba2009-11-16 10:17:30 -0800966 pr_err("%s: Controller lockup detected\n",
967 mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700968 mrq->cmd->error = -ETIMEDOUT;
969 msmsdcc_stop_data(host);
970
San Mehat8b1c2ba2009-11-16 10:17:30 -0800971 msmsdcc_writel(host, 0, MMCICOMMAND);
San Mehat9d2bd732009-09-22 16:44:22 -0700972
973 host->curr.mrq = NULL;
974 host->curr.cmd = NULL;
975
San Mehat865c80642009-11-13 13:42:06 -0800976 if (host->clks_on)
977 msmsdcc_enable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -0700978 spin_unlock_irqrestore(&host->lock, flags);
979 mmc_request_done(host->mmc, mrq);
980}
981
982static int
983msmsdcc_init_dma(struct msmsdcc_host *host)
984{
985 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
986 host->dma.host = host;
987 host->dma.channel = -1;
988
989 if (!host->dmares)
990 return -ENODEV;
991
992 host->dma.nc = dma_alloc_coherent(NULL,
993 sizeof(struct msmsdcc_nc_dmadata),
994 &host->dma.nc_busaddr,
995 GFP_KERNEL);
996 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700997 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700998 return -ENOMEM;
999 }
1000 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
1001 host->dma.cmd_busaddr = host->dma.nc_busaddr;
1002 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
1003 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
1004 host->dma.channel = host->dmares->start;
1005
1006 return 0;
1007}
1008
1009#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
1010static void
1011do_resume_work(struct work_struct *work)
1012{
1013 struct msmsdcc_host *host =
1014 container_of(work, struct msmsdcc_host, resume_task);
1015 struct mmc_host *mmc = host->mmc;
1016
1017 if (mmc) {
1018 mmc_resume_host(mmc);
1019 if (host->stat_irq)
1020 enable_irq(host->stat_irq);
1021 }
1022}
1023#endif
1024
1025static int
1026msmsdcc_probe(struct platform_device *pdev)
1027{
1028 struct mmc_platform_data *plat = pdev->dev.platform_data;
1029 struct msmsdcc_host *host;
1030 struct mmc_host *mmc;
1031 struct resource *cmd_irqres = NULL;
1032 struct resource *pio_irqres = NULL;
1033 struct resource *stat_irqres = NULL;
1034 struct resource *memres = NULL;
1035 struct resource *dmares = NULL;
1036 int ret;
1037
1038 /* must have platform data */
1039 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001040 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001041 ret = -EINVAL;
1042 goto out;
1043 }
1044
1045 if (pdev->id < 1 || pdev->id > 4)
1046 return -EINVAL;
1047
1048 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001049 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001050 return -ENXIO;
1051 }
1052
1053 memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1054 dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1055 cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1056 "cmd_irq");
1057 pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1058 "pio_irq");
1059 stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1060 "status_irq");
1061
1062 if (!cmd_irqres || !pio_irqres || !memres) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001063 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001064 return -ENXIO;
1065 }
1066
1067 /*
1068 * Setup our host structure
1069 */
1070
1071 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
1072 if (!mmc) {
1073 ret = -ENOMEM;
1074 goto out;
1075 }
1076
1077 host = mmc_priv(mmc);
1078 host->pdev_id = pdev->id;
1079 host->plat = plat;
1080 host->mmc = mmc;
1081
1082 host->cmdpoll = 1;
1083
San Mehat865c80642009-11-13 13:42:06 -08001084 host->use_bustimer = 1;
1085
San Mehat9d2bd732009-09-22 16:44:22 -07001086 host->base = ioremap(memres->start, PAGE_SIZE);
1087 if (!host->base) {
1088 ret = -ENOMEM;
1089 goto out;
1090 }
1091
1092 host->cmd_irqres = cmd_irqres;
1093 host->pio_irqres = pio_irqres;
1094 host->memres = memres;
1095 host->dmares = dmares;
1096 spin_lock_init(&host->lock);
1097
1098 /*
1099 * Setup DMA
1100 */
1101 msmsdcc_init_dma(host);
1102
San Mehat4adbbcc2009-11-08 13:00:37 -08001103 /* Get our clocks */
San Mehat9d2bd732009-09-22 16:44:22 -07001104 host->pclk = clk_get(&pdev->dev, "sdc_pclk");
1105 if (IS_ERR(host->pclk)) {
1106 ret = PTR_ERR(host->pclk);
1107 goto host_free;
1108 }
1109
San Mehat9d2bd732009-09-22 16:44:22 -07001110 host->clk = clk_get(&pdev->dev, "sdc_clk");
1111 if (IS_ERR(host->clk)) {
1112 ret = PTR_ERR(host->clk);
San Mehat4adbbcc2009-11-08 13:00:37 -08001113 goto pclk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07001114 }
1115
San Mehat4adbbcc2009-11-08 13:00:37 -08001116 /* Enable clocks */
1117 ret = msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -07001118 if (ret)
1119 goto clk_put;
1120
1121 ret = clk_set_rate(host->clk, msmsdcc_fmin);
1122 if (ret) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001123 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07001124 goto clk_disable;
1125 }
1126
San Mehat4adbbcc2009-11-08 13:00:37 -08001127 host->pclk_rate = clk_get_rate(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07001128 host->clk_rate = clk_get_rate(host->clk);
1129
San Mehat9d2bd732009-09-22 16:44:22 -07001130 /*
1131 * Setup MMC host structure
1132 */
1133 mmc->ops = &msmsdcc_ops;
1134 mmc->f_min = msmsdcc_fmin;
1135 mmc->f_max = msmsdcc_fmax;
1136 mmc->ocr_avail = plat->ocr_mask;
1137
1138 if (msmsdcc_4bit)
1139 mmc->caps |= MMC_CAP_4_BIT_DATA;
1140 if (msmsdcc_sdioirq)
1141 mmc->caps |= MMC_CAP_SDIO_IRQ;
1142 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
1143
1144 mmc->max_phys_segs = NR_SG;
1145 mmc->max_hw_segs = NR_SG;
1146 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
1147 mmc->max_blk_count = 65536;
1148
1149 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
1150 mmc->max_seg_size = mmc->max_req_size;
1151
San Mehat8b1c2ba2009-11-16 10:17:30 -08001152 msmsdcc_writel(host, 0, MMCIMASK0);
1153 msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07001154
San Mehat8b1c2ba2009-11-16 10:17:30 -08001155 msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001156 host->saved_irq0mask = MCI_IRQENABLE;
1157
1158 /*
1159 * Setup card detect change
1160 */
1161
1162 memset(&host->timer, 0, sizeof(host->timer));
1163
1164 if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) {
1165 unsigned long irqflags = IRQF_SHARED |
1166 (stat_irqres->flags & IRQF_TRIGGER_MASK);
1167
1168 host->stat_irq = stat_irqres->start;
1169 ret = request_irq(host->stat_irq,
1170 msmsdcc_platform_status_irq,
1171 irqflags,
1172 DRIVER_NAME " (slot)",
1173 host);
1174 if (ret) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001175 pr_err("%s: Unable to get slot IRQ %d (%d)\n",
1176 mmc_hostname(mmc), host->stat_irq, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07001177 goto clk_disable;
1178 }
1179 } else if (plat->register_status_notify) {
1180 plat->register_status_notify(msmsdcc_status_notify_cb, host);
1181 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001182 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07001183 mmc_hostname(mmc));
1184 else {
1185 init_timer(&host->timer);
1186 host->timer.data = (unsigned long)host;
1187 host->timer.function = msmsdcc_check_status;
1188 host->timer.expires = jiffies + HZ;
1189 add_timer(&host->timer);
1190 }
1191
1192 if (plat->status) {
1193 host->oldstat = host->plat->status(mmc_dev(host->mmc));
1194 host->eject = !host->oldstat;
1195 }
1196
1197 /*
1198 * Setup a command timer. We currently need this due to
1199 * some 'strange' timeout / error handling situations.
1200 */
1201 init_timer(&host->command_timer);
1202 host->command_timer.data = (unsigned long) host;
1203 host->command_timer.function = msmsdcc_command_expired;
1204
San Mehat865c80642009-11-13 13:42:06 -08001205 init_timer(&host->busclk_timer);
1206 host->busclk_timer.data = (unsigned long) host;
1207 host->busclk_timer.function = msmsdcc_busclk_expired;
1208
San Mehat9d2bd732009-09-22 16:44:22 -07001209 ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
1210 DRIVER_NAME " (cmd)", host);
1211 if (ret)
1212 goto stat_irq_free;
1213
1214 ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
1215 DRIVER_NAME " (pio)", host);
1216 if (ret)
1217 goto cmd_irq_free;
1218
1219 mmc_set_drvdata(pdev, mmc);
1220 mmc_add_host(mmc);
1221
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001222 pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
1223 mmc_hostname(mmc), (unsigned long long)memres->start,
1224 (unsigned int) cmd_irqres->start,
1225 (unsigned int) host->stat_irq, host->dma.channel);
1226 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
1227 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
1228 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
1229 mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate);
1230 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject);
1231 pr_info("%s: Power save feature enable = %d\n",
1232 mmc_hostname(mmc), msmsdcc_pwrsave);
San Mehat9d2bd732009-09-22 16:44:22 -07001233
1234 if (host->dma.channel != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001235 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
1236 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
1237 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
1238 mmc_hostname(mmc), host->dma.cmd_busaddr,
1239 host->dma.cmdptr_busaddr);
San Mehat9d2bd732009-09-22 16:44:22 -07001240 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001241 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001242 if (host->timer.function)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001243 pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001244
San Mehat51905dc2009-11-16 11:59:01 -08001245 if (host->use_bustimer)
1246 mod_timer(&host->busclk_timer, jiffies + HZ);
San Mehat9d2bd732009-09-22 16:44:22 -07001247 return 0;
1248 cmd_irq_free:
1249 free_irq(cmd_irqres->start, host);
1250 stat_irq_free:
1251 if (host->stat_irq)
1252 free_irq(host->stat_irq, host);
1253 clk_disable:
San Mehat4adbbcc2009-11-08 13:00:37 -08001254 msmsdcc_enable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07001255 clk_put:
1256 clk_put(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07001257 pclk_put:
1258 clk_put(host->pclk);
1259 host_free:
1260 mmc_free_host(mmc);
1261 out:
1262 return ret;
1263}
1264
1265static int
1266msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
1267{
1268 struct mmc_host *mmc = mmc_get_drvdata(dev);
1269 int rc = 0;
1270
1271 if (mmc) {
1272 struct msmsdcc_host *host = mmc_priv(mmc);
1273
1274 if (host->stat_irq)
1275 disable_irq(host->stat_irq);
1276
1277 if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
1278 rc = mmc_suspend_host(mmc, state);
1279 if (!rc) {
San Mehat8b1c2ba2009-11-16 10:17:30 -08001280 msmsdcc_writel(host, 0, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001281
San Mehat4adbbcc2009-11-08 13:00:37 -08001282 if (host->clks_on)
1283 msmsdcc_enable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07001284 }
1285 }
1286 return rc;
1287}
1288
1289static int
1290msmsdcc_resume(struct platform_device *dev)
1291{
1292 struct mmc_host *mmc = mmc_get_drvdata(dev);
1293 unsigned long flags;
1294
1295 if (mmc) {
1296 struct msmsdcc_host *host = mmc_priv(mmc);
1297
1298 spin_lock_irqsave(&host->lock, flags);
1299
San Mehat4adbbcc2009-11-08 13:00:37 -08001300 if (!host->clks_on)
1301 msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -07001302
San Mehat8b1c2ba2009-11-16 10:17:30 -08001303 msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001304
1305 spin_unlock_irqrestore(&host->lock, flags);
1306
1307 if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
1308 mmc_resume_host(mmc);
Roel Kluin5b8a2fb2010-01-17 20:25:36 +01001309 if (host->stat_irq)
San Mehat9d2bd732009-09-22 16:44:22 -07001310 enable_irq(host->stat_irq);
1311 }
1312 return 0;
1313}
1314
1315static struct platform_driver msmsdcc_driver = {
1316 .probe = msmsdcc_probe,
1317 .suspend = msmsdcc_suspend,
1318 .resume = msmsdcc_resume,
1319 .driver = {
1320 .name = "msm_sdcc",
1321 },
1322};
1323
1324static int __init msmsdcc_init(void)
1325{
1326 return platform_driver_register(&msmsdcc_driver);
1327}
1328
1329static void __exit msmsdcc_exit(void)
1330{
1331 platform_driver_unregister(&msmsdcc_driver);
1332}
1333
1334module_init(msmsdcc_init);
1335module_exit(msmsdcc_exit);
1336
1337MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
1338MODULE_LICENSE("GPL");