blob: 524858597901a32bfc69dd83f9e3e4d822c5078c [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.
San Mehat56a8b5b2009-11-21 12:29:46 -08006 * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
22#include <linux/device.h>
23#include <linux/interrupt.h>
24#include <linux/delay.h>
25#include <linux/err.h>
26#include <linux/highmem.h>
27#include <linux/log2.h>
28#include <linux/mmc/host.h>
29#include <linux/mmc/card.h>
San Mehatb3fa5792009-11-02 18:46:09 -080030#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070031#include <linux/clk.h>
32#include <linux/scatterlist.h>
33#include <linux/platform_device.h>
34#include <linux/dma-mapping.h>
35#include <linux/debugfs.h>
36#include <linux/io.h>
37#include <linux/memory.h>
38
39#include <asm/cacheflush.h>
40#include <asm/div64.h>
41#include <asm/sizes.h>
42
Pavel Machek3989d172009-12-08 11:11:36 -080043#include <mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070044#include <mach/msm_iomap.h>
45#include <mach/dma.h>
San Mehat9d2bd732009-09-22 16:44:22 -070046
San Mehat9d2bd732009-09-22 16:44:22 -070047#include "msm_sdcc.h"
48
49#define DRIVER_NAME "msm-sdcc"
50
San Mehat56a8b5b2009-11-21 12:29:46 -080051#define BUSCLK_TIMEOUT (HZ * 5)
San Mehat9d2bd732009-09-22 16:44:22 -070052static unsigned int msmsdcc_fmin = 144000;
53static unsigned int msmsdcc_fmax = 50000000;
54static unsigned int msmsdcc_4bit = 1;
55static unsigned int msmsdcc_pwrsave = 1;
56static unsigned int msmsdcc_piopoll = 1;
57static unsigned int msmsdcc_sdioirq;
58
59#define PIO_SPINMAX 30
60#define CMD_SPINMAX 20
61
San Mehat865c80642009-11-13 13:42:06 -080062
63static inline int
64msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
65{
66 int rc;
San Mehat8b1c2ba2009-11-16 10:17:30 -080067
San Mehat865c80642009-11-13 13:42:06 -080068 WARN_ON(enable == host->clks_on);
69 if (enable) {
70 rc = clk_enable(host->pclk);
71 if (rc)
72 return rc;
73 rc = clk_enable(host->clk);
74 if (rc) {
75 clk_disable(host->pclk);
76 return rc;
77 }
San Mehat8b1c2ba2009-11-16 10:17:30 -080078 udelay(1 + ((3 * USEC_PER_SEC) /
79 (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
San Mehat865c80642009-11-13 13:42:06 -080080 host->clks_on = 1;
81 } else {
82 clk_disable(host->clk);
83 clk_disable(host->pclk);
84 host->clks_on = 0;
85 }
86 return 0;
87}
88
San Mehat8b1c2ba2009-11-16 10:17:30 -080089static inline unsigned int
90msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg)
91{
92 return readl(host->base + reg);
93}
94
95static inline void
96msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg)
97{
98 writel(data, host->base + reg);
99 /* 3 clk delay required! */
100 udelay(1 + ((3 * USEC_PER_SEC) /
101 (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
102}
San Mehat865c80642009-11-13 13:42:06 -0800103
San Mehat9d2bd732009-09-22 16:44:22 -0700104static void
105msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
106 u32 c);
107
108static void
109msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
110{
San Mehat9d2bd732009-09-22 16:44:22 -0700111 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)
San Mehat56a8b5b2009-11-21 12:29:46 -0800122 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
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 Mehat9d2bd732009-09-22 16:44:22 -0700135 host->curr.data = NULL;
136 host->curr.got_dataend = host->curr.got_datablkend = 0;
137}
138
139uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
140{
Joe Perches75d14522009-09-22 16:44:24 -0700141 switch (host->pdev_id) {
142 case 1:
San Mehat9d2bd732009-09-22 16:44:22 -0700143 return MSM_SDC1_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700144 case 2:
San Mehat9d2bd732009-09-22 16:44:22 -0700145 return MSM_SDC2_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700146 case 3:
San Mehat9d2bd732009-09-22 16:44:22 -0700147 return MSM_SDC3_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700148 case 4:
San Mehat9d2bd732009-09-22 16:44:22 -0700149 return MSM_SDC4_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700150 }
151 BUG();
San Mehat9d2bd732009-09-22 16:44:22 -0700152 return 0;
153}
154
San Mehat56a8b5b2009-11-21 12:29:46 -0800155static inline void
156msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) {
157 msmsdcc_writel(host, arg, MMCIARGUMENT);
158 msmsdcc_writel(host, c, MMCICOMMAND);
159}
160
161static void
162msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
163{
164 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data;
165
166 writel(host->cmd_timeout, host->base + MMCIDATATIMER);
167 writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH);
168 writel(host->cmd_pio_irqmask, host->base + MMCIMASK1);
169 writel(host->cmd_datactrl, host->base + MMCIDATACTRL);
170
171 if (host->cmd_cmd) {
172 msmsdcc_start_command_exec(host,
173 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
174 }
175 host->dma.active = 1;
176}
177
San Mehat9d2bd732009-09-22 16:44:22 -0700178static void
179msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
180 unsigned int result,
181 struct msm_dmov_errdata *err)
182{
183 struct msmsdcc_dma_data *dma_data =
184 container_of(cmd, struct msmsdcc_dma_data, hdr);
185 struct msmsdcc_host *host = dma_data->host;
186 unsigned long flags;
187 struct mmc_request *mrq;
188
189 spin_lock_irqsave(&host->lock, flags);
San Mehat56a8b5b2009-11-21 12:29:46 -0800190 host->dma.active = 0;
191
San Mehat9d2bd732009-09-22 16:44:22 -0700192 mrq = host->curr.mrq;
193 BUG_ON(!mrq);
194
195 if (!(result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700196 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700197 goto out;
198 }
199
200 if (result & DMOV_RSLT_DONE) {
201 host->curr.data_xfered = host->curr.xfer_size;
202 } else {
203 /* Error or flush */
204 if (result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700205 pr_err("%s: DMA error (0x%.8x)\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700206 mmc_hostname(host->mmc), result);
207 if (result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700208 pr_err("%s: DMA channel flushed (0x%.8x)\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700209 mmc_hostname(host->mmc), result);
210 if (err)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700211 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700212 err->flush[0], err->flush[1], err->flush[2],
213 err->flush[3], err->flush[4], err->flush[5]);
214 if (!mrq->data->error)
215 mrq->data->error = -EIO;
216 }
San Mehat9d2bd732009-09-22 16:44:22 -0700217 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
218 host->dma.dir);
219
220 if (host->curr.user_pages) {
221 struct scatterlist *sg = host->dma.sg;
222 int i;
223
Joe Perches75d14522009-09-22 16:44:24 -0700224 for (i = 0; i < host->dma.num_ents; i++)
225 flush_dcache_page(sg_page(sg++));
San Mehat9d2bd732009-09-22 16:44:22 -0700226 }
227
228 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800229 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700230
231 if ((host->curr.got_dataend && host->curr.got_datablkend)
232 || mrq->data->error) {
233
234 /*
235 * If we've already gotten our DATAEND / DATABLKEND
236 * for this request, then complete it through here.
237 */
238 msmsdcc_stop_data(host);
239
240 if (!mrq->data->error)
241 host->curr.data_xfered = host->curr.xfer_size;
242 if (!mrq->data->stop || mrq->cmd->error) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800243 msmsdcc_writel(host, 0, MMCICOMMAND);
San Mehat9d2bd732009-09-22 16:44:22 -0700244 host->curr.mrq = NULL;
245 host->curr.cmd = NULL;
246 mrq->data->bytes_xfered = host->curr.data_xfered;
247
248 spin_unlock_irqrestore(&host->lock, flags);
249 mmc_request_done(host->mmc, mrq);
250 return;
251 } else
252 msmsdcc_start_command(host, mrq->data->stop, 0);
253 }
254
255out:
256 spin_unlock_irqrestore(&host->lock, flags);
257 return;
258}
259
260static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
261{
262 if (host->dma.channel == -1)
263 return -ENOENT;
264
265 if ((data->blksz * data->blocks) < MCI_FIFOSIZE)
266 return -EINVAL;
267 if ((data->blksz * data->blocks) % MCI_FIFOSIZE)
268 return -EINVAL;
269 return 0;
270}
271
272static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
273{
274 struct msmsdcc_nc_dmadata *nc;
275 dmov_box *box;
276 uint32_t rows;
277 uint32_t crci;
278 unsigned int n;
279 int i, rc;
280 struct scatterlist *sg = data->sg;
281
282 rc = validate_dma(host, data);
283 if (rc)
284 return rc;
285
286 host->dma.sg = data->sg;
287 host->dma.num_ents = data->sg_len;
288
San Mehat56a8b5b2009-11-21 12:29:46 -0800289 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
290
San Mehat9d2bd732009-09-22 16:44:22 -0700291 nc = host->dma.nc;
292
Joe Perches75d14522009-09-22 16:44:24 -0700293 switch (host->pdev_id) {
294 case 1:
San Mehat9d2bd732009-09-22 16:44:22 -0700295 crci = MSMSDCC_CRCI_SDC1;
Joe Perches75d14522009-09-22 16:44:24 -0700296 break;
297 case 2:
San Mehat9d2bd732009-09-22 16:44:22 -0700298 crci = MSMSDCC_CRCI_SDC2;
Joe Perches75d14522009-09-22 16:44:24 -0700299 break;
300 case 3:
San Mehat9d2bd732009-09-22 16:44:22 -0700301 crci = MSMSDCC_CRCI_SDC3;
Joe Perches75d14522009-09-22 16:44:24 -0700302 break;
303 case 4:
San Mehat9d2bd732009-09-22 16:44:22 -0700304 crci = MSMSDCC_CRCI_SDC4;
Joe Perches75d14522009-09-22 16:44:24 -0700305 break;
306 default:
San Mehat9d2bd732009-09-22 16:44:22 -0700307 host->dma.sg = NULL;
308 host->dma.num_ents = 0;
309 return -ENOENT;
310 }
311
312 if (data->flags & MMC_DATA_READ)
313 host->dma.dir = DMA_FROM_DEVICE;
314 else
315 host->dma.dir = DMA_TO_DEVICE;
316
317 host->curr.user_pages = 0;
318
San Mehat9d2bd732009-09-22 16:44:22 -0700319 box = &nc->cmd[0];
320 for (i = 0; i < host->dma.num_ents; i++) {
321 box->cmd = CMD_MODE_BOX;
322
San Mehat56a8b5b2009-11-21 12:29:46 -0800323 /* Initialize sg dma address */
324 sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg))
325 + sg->offset;
326
327 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700328 box->cmd |= CMD_LC;
329 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
330 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
331 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
332
333 if (data->flags & MMC_DATA_READ) {
334 box->src_row_addr = msmsdcc_fifo_addr(host);
335 box->dst_row_addr = sg_dma_address(sg);
336
337 box->src_dst_len = (MCI_FIFOSIZE << 16) |
338 (MCI_FIFOSIZE);
339 box->row_offset = MCI_FIFOSIZE;
340
341 box->num_rows = rows * ((1 << 16) + 1);
342 box->cmd |= CMD_SRC_CRCI(crci);
343 } else {
344 box->src_row_addr = sg_dma_address(sg);
345 box->dst_row_addr = msmsdcc_fifo_addr(host);
346
347 box->src_dst_len = (MCI_FIFOSIZE << 16) |
348 (MCI_FIFOSIZE);
349 box->row_offset = (MCI_FIFOSIZE << 16);
350
351 box->num_rows = rows * ((1 << 16) + 1);
352 box->cmd |= CMD_DST_CRCI(crci);
353 }
354 box++;
355 sg++;
356 }
357
358 /* location of command block must be 64 bit aligned */
359 BUG_ON(host->dma.cmd_busaddr & 0x07);
360
361 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
362 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
363 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
364 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
San Mehat56a8b5b2009-11-21 12:29:46 -0800365
366 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
367 host->dma.num_ents, host->dma.dir);
368/* dsb inside dma_map_sg will write nc out to mem as well */
369
370 if (n != host->dma.num_ents) {
371 printk(KERN_ERR "%s: Unable to map in all sg elements\n",
372 mmc_hostname(host->mmc));
373 host->dma.sg = NULL;
374 host->dma.num_ents = 0;
375 return -ENOMEM;
376 }
San Mehat9d2bd732009-09-22 16:44:22 -0700377
378 return 0;
379}
380
San Mehat56a8b5b2009-11-21 12:29:46 -0800381static int
382snoop_cccr_abort(struct mmc_command *cmd)
383{
384 if ((cmd->opcode == 52) &&
385 (cmd->arg & 0x80000000) &&
386 (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT))
387 return 1;
388 return 0;
389}
390
San Mehat9d2bd732009-09-22 16:44:22 -0700391static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800392msmsdcc_start_command_deferred(struct msmsdcc_host *host,
393 struct mmc_command *cmd, u32 *c)
394{
395 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
396
397 if (cmd->flags & MMC_RSP_PRESENT) {
398 if (cmd->flags & MMC_RSP_136)
399 *c |= MCI_CPSM_LONGRSP;
400 *c |= MCI_CPSM_RESPONSE;
401 }
402
403 if (/*interrupt*/0)
404 *c |= MCI_CPSM_INTERRUPT;
405
406 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
407 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
408 (cmd->opcode == 53))
409 *c |= MCI_CSPM_DATCMD;
410
411 if (cmd == cmd->mrq->stop)
412 *c |= MCI_CSPM_MCIABORT;
413
414 if (snoop_cccr_abort(cmd))
415 *c |= MCI_CSPM_MCIABORT;
416
417 if (host->curr.cmd != NULL) {
418 printk(KERN_ERR "%s: Overlapping command requests\n",
419 mmc_hostname(host->mmc));
420 }
421 host->curr.cmd = cmd;
422}
423
424static void
425msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
426 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700427{
428 unsigned int datactrl, timeout;
429 unsigned long long clks;
San Mehat9d2bd732009-09-22 16:44:22 -0700430 unsigned int pio_irqmask = 0;
431
432 host->curr.data = data;
433 host->curr.xfer_size = data->blksz * data->blocks;
434 host->curr.xfer_remain = host->curr.xfer_size;
435 host->curr.data_xfered = 0;
436 host->curr.got_dataend = 0;
437 host->curr.got_datablkend = 0;
438
439 memset(&host->pio, 0, sizeof(host->pio));
440
San Mehat9d2bd732009-09-22 16:44:22 -0700441 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
442
443 if (!msmsdcc_config_dma(host, data))
444 datactrl |= MCI_DPSM_DMAENABLE;
445 else {
446 host->pio.sg = data->sg;
447 host->pio.sg_len = data->sg_len;
448 host->pio.sg_off = 0;
449
450 if (data->flags & MMC_DATA_READ) {
451 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
452 if (host->curr.xfer_remain < MCI_FIFOSIZE)
453 pio_irqmask |= MCI_RXDATAAVLBLMASK;
454 } else
455 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK;
456 }
457
458 if (data->flags & MMC_DATA_READ)
459 datactrl |= MCI_DPSM_DIRECTION;
460
San Mehat56a8b5b2009-11-21 12:29:46 -0800461 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
462 do_div(clks, NSEC_PER_SEC);
463 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -0700464
465 if (datactrl & MCI_DPSM_DMAENABLE) {
San Mehat56a8b5b2009-11-21 12:29:46 -0800466 /* Save parameters for the exec function */
467 host->cmd_timeout = timeout;
468 host->cmd_pio_irqmask = pio_irqmask;
469 host->cmd_datactrl = datactrl;
470 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700471
San Mehat56a8b5b2009-11-21 12:29:46 -0800472 host->dma.hdr.execute_func = msmsdcc_dma_exec_func;
473 host->dma.hdr.data = (void *)host;
474 host->dma.busy = 1;
475
476 if (cmd) {
477 msmsdcc_start_command_deferred(host, cmd, &c);
478 host->cmd_c = c;
479 }
480 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
481 } else {
482 msmsdcc_writel(host, timeout, MMCIDATATIMER);
483
484 msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
485
486 msmsdcc_writel(host, pio_irqmask, MMCIMASK1);
487 msmsdcc_writel(host, datactrl, MMCIDATACTRL);
488
489 if (cmd) {
490 /* Daisy-chain the command if requested */
491 msmsdcc_start_command(host, cmd, c);
492 }
493 }
San Mehatb3fa5792009-11-02 18:46:09 -0800494}
495
San Mehat9d2bd732009-09-22 16:44:22 -0700496static void
497msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
498{
San Mehat9d2bd732009-09-22 16:44:22 -0700499 if (cmd == cmd->mrq->stop)
500 c |= MCI_CSPM_MCIABORT;
501
San Mehat9d2bd732009-09-22 16:44:22 -0700502 host->stats.cmds++;
503
San Mehat56a8b5b2009-11-21 12:29:46 -0800504 msmsdcc_start_command_deferred(host, cmd, &c);
505 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -0700506}
507
508static void
509msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
510 unsigned int status)
511{
512 if (status & MCI_DATACRCFAIL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700513 pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc));
514 pr_err("%s: opcode 0x%.8x\n", __func__,
San Mehat9d2bd732009-09-22 16:44:22 -0700515 data->mrq->cmd->opcode);
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700516 pr_err("%s: blksz %d, blocks %d\n", __func__,
San Mehat9d2bd732009-09-22 16:44:22 -0700517 data->blksz, data->blocks);
518 data->error = -EILSEQ;
519 } else if (status & MCI_DATATIMEOUT) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700520 pr_err("%s: Data timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700521 data->error = -ETIMEDOUT;
522 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700523 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700524 data->error = -EIO;
525 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700526 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700527 data->error = -EIO;
528 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700529 pr_err("%s: Unknown error (0x%.8x)\n",
530 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -0700531 data->error = -EIO;
532 }
533}
534
535
536static int
537msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
538{
San Mehat9d2bd732009-09-22 16:44:22 -0700539 uint32_t *ptr = (uint32_t *) buffer;
540 int count = 0;
541
San Mehat8b1c2ba2009-11-16 10:17:30 -0800542 while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
543 *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -0700544 ptr++;
545 count += sizeof(uint32_t);
546
547 remain -= sizeof(uint32_t);
548 if (remain == 0)
549 break;
550 }
551 return count;
552}
553
554static int
555msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
556 unsigned int remain, u32 status)
557{
558 void __iomem *base = host->base;
559 char *ptr = buffer;
560
561 do {
562 unsigned int count, maxcnt;
563
564 maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
565 MCI_FIFOHALFSIZE;
566 count = min(remain, maxcnt);
567
568 writesl(base + MMCIFIFO, ptr, count >> 2);
569 ptr += count;
570 remain -= count;
571
572 if (remain == 0)
573 break;
574
San Mehat8b1c2ba2009-11-16 10:17:30 -0800575 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700576 } while (status & MCI_TXFIFOHALFEMPTY);
577
578 return ptr - buffer;
579}
580
581static int
582msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin)
583{
584 while (maxspin) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800585 if ((msmsdcc_readl(host, MMCISTATUS) & mask))
San Mehat9d2bd732009-09-22 16:44:22 -0700586 return 0;
587 udelay(1);
588 --maxspin;
589 }
590 return -ETIMEDOUT;
591}
592
593static int
594msmsdcc_pio_irq(int irq, void *dev_id)
595{
596 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -0700597 uint32_t status;
598
San Mehat8b1c2ba2009-11-16 10:17:30 -0800599 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700600
601 do {
602 unsigned long flags;
603 unsigned int remain, len;
604 char *buffer;
605
606 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) {
607 if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll)
608 break;
609
610 if (msmsdcc_spin_on_status(host,
611 (MCI_TXFIFOHALFEMPTY |
612 MCI_RXDATAAVLBL),
613 PIO_SPINMAX)) {
614 break;
615 }
616 }
617
618 /* Map the current scatter buffer */
619 local_irq_save(flags);
620 buffer = kmap_atomic(sg_page(host->pio.sg),
621 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
622 buffer += host->pio.sg_off;
623 remain = host->pio.sg->length - host->pio.sg_off;
624 len = 0;
625 if (status & MCI_RXACTIVE)
626 len = msmsdcc_pio_read(host, buffer, remain);
627 if (status & MCI_TXACTIVE)
628 len = msmsdcc_pio_write(host, buffer, remain, status);
629
630 /* Unmap the buffer */
631 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
632 local_irq_restore(flags);
633
634 host->pio.sg_off += len;
635 host->curr.xfer_remain -= len;
636 host->curr.data_xfered += len;
637 remain -= len;
638
639 if (remain == 0) {
640 /* This sg page is full - do some housekeeping */
641 if (status & MCI_RXACTIVE && host->curr.user_pages)
642 flush_dcache_page(sg_page(host->pio.sg));
643
644 if (!--host->pio.sg_len) {
645 memset(&host->pio, 0, sizeof(host->pio));
646 break;
647 }
648
649 /* Advance to next sg */
650 host->pio.sg++;
651 host->pio.sg_off = 0;
652 }
653
San Mehat8b1c2ba2009-11-16 10:17:30 -0800654 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700655 } while (1);
656
657 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE)
San Mehat8b1c2ba2009-11-16 10:17:30 -0800658 msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1);
San Mehat9d2bd732009-09-22 16:44:22 -0700659
660 if (!host->curr.xfer_remain)
San Mehat8b1c2ba2009-11-16 10:17:30 -0800661 msmsdcc_writel(host, 0, MMCIMASK1);
San Mehat9d2bd732009-09-22 16:44:22 -0700662
663 return IRQ_HANDLED;
664}
665
666static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
667{
668 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700669
670 host->curr.cmd = NULL;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800671 cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0);
672 cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1);
673 cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
674 cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -0700675
San Mehat9d2bd732009-09-22 16:44:22 -0700676 if (status & MCI_CMDTIMEOUT) {
677 cmd->error = -ETIMEDOUT;
678 } else if (status & MCI_CMDCRCFAIL &&
679 cmd->flags & MMC_RSP_CRC) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700680 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700681 cmd->error = -EILSEQ;
682 }
683
684 if (!cmd->data || cmd->error) {
685 if (host->curr.data && host->dma.sg)
686 msm_dmov_stop_cmd(host->dma.channel,
687 &host->dma.hdr, 0);
688 else if (host->curr.data) { /* Non DMA */
689 msmsdcc_stop_data(host);
690 msmsdcc_request_end(host, cmd->mrq);
691 } else /* host->data == NULL */
692 msmsdcc_request_end(host, cmd->mrq);
San Mehat56a8b5b2009-11-21 12:29:46 -0800693 } else if (cmd->data)
694 if (!(cmd->data->flags & MMC_DATA_READ))
695 msmsdcc_start_data(host, cmd->data,
696 NULL, 0);
San Mehat9d2bd732009-09-22 16:44:22 -0700697}
698
Joe Perchesb5a74d62009-09-22 16:44:25 -0700699static void
700msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
701 void __iomem *base)
702{
San Mehat56a8b5b2009-11-21 12:29:46 -0800703 struct mmc_data *data;
Joe Perchesb5a74d62009-09-22 16:44:25 -0700704
San Mehat56a8b5b2009-11-21 12:29:46 -0800705 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
706 MCI_CMDTIMEOUT) && host->curr.cmd) {
707 msmsdcc_do_cmdirq(host, status);
708 }
709
710 data = host->curr.data;
Joe Perchesb5a74d62009-09-22 16:44:25 -0700711 if (!data)
712 return;
713
714 /* Check for data errors */
715 if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
716 MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
717 msmsdcc_data_err(host, data, status);
718 host->curr.data_xfered = 0;
719 if (host->dma.sg)
720 msm_dmov_stop_cmd(host->dma.channel,
721 &host->dma.hdr, 0);
722 else {
723 msmsdcc_stop_data(host);
724 if (!data->stop)
725 msmsdcc_request_end(host, data->mrq);
726 else
727 msmsdcc_start_command(host, data->stop, 0);
728 }
729 }
730
731 /* Check for data done */
732 if (!host->curr.got_dataend && (status & MCI_DATAEND))
733 host->curr.got_dataend = 1;
734
735 if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND))
736 host->curr.got_datablkend = 1;
737
738 /*
739 * If DMA is still in progress, we complete via the completion handler
740 */
741 if (host->curr.got_dataend && host->curr.got_datablkend &&
742 !host->dma.busy) {
743 /*
744 * There appears to be an issue in the controller where
745 * if you request a small block transfer (< fifo size),
746 * you may get your DATAEND/DATABLKEND irq without the
747 * PIO data irq.
748 *
749 * Check to see if there is still data to be read,
750 * and simulate a PIO irq.
751 */
752 if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL)
753 msmsdcc_pio_irq(1, host);
754
755 msmsdcc_stop_data(host);
756 if (!data->error)
757 host->curr.data_xfered = host->curr.xfer_size;
758
759 if (!data->stop)
760 msmsdcc_request_end(host, data->mrq);
761 else
762 msmsdcc_start_command(host, data->stop, 0);
763 }
764}
765
San Mehat9d2bd732009-09-22 16:44:22 -0700766static irqreturn_t
767msmsdcc_irq(int irq, void *dev_id)
768{
769 struct msmsdcc_host *host = dev_id;
770 void __iomem *base = host->base;
771 u32 status;
772 int ret = 0;
773 int cardint = 0;
774
775 spin_lock(&host->lock);
776
777 do {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800778 struct mmc_data *data;
779 status = msmsdcc_readl(host, MMCISTATUS);
780 status &= (msmsdcc_readl(host, MMCIMASK0) |
781 MCI_DATABLOCKENDMASK);
782 msmsdcc_writel(host, status, MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -0700783
San Mehat865c80642009-11-13 13:42:06 -0800784 if (status & MCI_SDIOINTR)
785 status &= ~MCI_SDIOINTR;
786
787 if (!status)
788 break;
789
Joe Perchesb5a74d62009-09-22 16:44:25 -0700790 msmsdcc_handle_irq_data(host, status, base);
San Mehat9d2bd732009-09-22 16:44:22 -0700791
San Mehat9d2bd732009-09-22 16:44:22 -0700792 if (status & MCI_SDIOINTOPER) {
793 cardint = 1;
794 status &= ~MCI_SDIOINTOPER;
795 }
796 ret = 1;
797 } while (status);
798
799 spin_unlock(&host->lock);
800
801 /*
802 * We have to delay handling the card interrupt as it calls
803 * back into the driver.
804 */
805 if (cardint)
806 mmc_signal_sdio_irq(host->mmc);
807
808 return IRQ_RETVAL(ret);
809}
810
811static void
812msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
813{
814 struct msmsdcc_host *host = mmc_priv(mmc);
815 unsigned long flags;
816
817 WARN_ON(host->curr.mrq != NULL);
818 WARN_ON(host->pwr == 0);
819
820 spin_lock_irqsave(&host->lock, flags);
821
822 host->stats.reqs++;
823
824 if (host->eject) {
825 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
826 mrq->cmd->error = 0;
827 mrq->data->bytes_xfered = mrq->data->blksz *
828 mrq->data->blocks;
829 } else
830 mrq->cmd->error = -ENOMEDIUM;
831
832 spin_unlock_irqrestore(&host->lock, flags);
833 mmc_request_done(mmc, mrq);
834 return;
835 }
836
837 host->curr.mrq = mrq;
San Mehat865c80642009-11-13 13:42:06 -0800838 if (!host->clks_on)
839 msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -0700840
841 if (mrq->data && mrq->data->flags & MMC_DATA_READ)
San Mehat56a8b5b2009-11-21 12:29:46 -0800842 /* Queue/read data, daisy-chain command when data starts */
843 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
844 else
845 msmsdcc_start_command(host, mrq->cmd, 0);
San Mehat9d2bd732009-09-22 16:44:22 -0700846
847 if (host->cmdpoll && !msmsdcc_spin_on_status(host,
848 MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
849 CMD_SPINMAX)) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800850 uint32_t status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700851 msmsdcc_do_cmdirq(host, status);
San Mehat8b1c2ba2009-11-16 10:17:30 -0800852 msmsdcc_writel(host,
853 MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT,
854 MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -0700855 host->stats.cmdpoll_hits++;
856 } else {
857 host->stats.cmdpoll_misses++;
San Mehat9d2bd732009-09-22 16:44:22 -0700858 }
859 spin_unlock_irqrestore(&host->lock, flags);
860}
861
862static void
863msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
864{
865 struct msmsdcc_host *host = mmc_priv(mmc);
866 u32 clk = 0, pwr = 0;
867 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -0800868 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -0700869
San Mehat4adbbcc2009-11-08 13:00:37 -0800870 spin_lock_irqsave(&host->lock, flags);
San Mehat865c80642009-11-13 13:42:06 -0800871 if (!host->clks_on)
872 msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -0700873
San Mehat865c80642009-11-13 13:42:06 -0800874 if (ios->clock) {
San Mehat9d2bd732009-09-22 16:44:22 -0700875 if (ios->clock != host->clk_rate) {
876 rc = clk_set_rate(host->clk, ios->clock);
877 if (rc < 0)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700878 pr_err("%s: Error setting clock rate (%d)\n",
879 mmc_hostname(host->mmc), rc);
San Mehat9d2bd732009-09-22 16:44:22 -0700880 else
881 host->clk_rate = ios->clock;
882 }
883 clk |= MCI_CLK_ENABLE;
884 }
885
886 if (ios->bus_width == MMC_BUS_WIDTH_4)
887 clk |= (2 << 10); /* Set WIDEBUS */
888
889 if (ios->clock > 400000 && msmsdcc_pwrsave)
890 clk |= (1 << 9); /* PWRSAVE */
891
892 clk |= (1 << 12); /* FLOW_ENA */
893 clk |= (1 << 15); /* feedback clock */
894
895 if (host->plat->translate_vdd)
896 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
897
898 switch (ios->power_mode) {
899 case MMC_POWER_OFF:
San Mehat9d2bd732009-09-22 16:44:22 -0700900 break;
901 case MMC_POWER_UP:
902 pwr |= MCI_PWR_UP;
903 break;
904 case MMC_POWER_ON:
San Mehat9d2bd732009-09-22 16:44:22 -0700905 pwr |= MCI_PWR_ON;
906 break;
907 }
908
909 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
910 pwr |= MCI_OD;
911
San Mehat8b1c2ba2009-11-16 10:17:30 -0800912 msmsdcc_writel(host, clk, MMCICLOCK);
San Mehat9d2bd732009-09-22 16:44:22 -0700913
914 if (host->pwr != pwr) {
915 host->pwr = pwr;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800916 msmsdcc_writel(host, pwr, MMCIPOWER);
San Mehat9d2bd732009-09-22 16:44:22 -0700917 }
San Mehat865c80642009-11-13 13:42:06 -0800918 if (host->clks_on)
San Mehat4adbbcc2009-11-08 13:00:37 -0800919 msmsdcc_enable_clocks(host, 0);
920 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -0700921}
922
923static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
924{
925 struct msmsdcc_host *host = mmc_priv(mmc);
926 unsigned long flags;
927 u32 status;
928
929 spin_lock_irqsave(&host->lock, flags);
930 if (msmsdcc_sdioirq == 1) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800931 status = msmsdcc_readl(host, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -0700932 if (enable)
933 status |= MCI_SDIOINTOPERMASK;
934 else
935 status &= ~MCI_SDIOINTOPERMASK;
936 host->saved_irq0mask = status;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800937 msmsdcc_writel(host, status, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -0700938 }
939 spin_unlock_irqrestore(&host->lock, flags);
940}
941
942static const struct mmc_host_ops msmsdcc_ops = {
943 .request = msmsdcc_request,
944 .set_ios = msmsdcc_set_ios,
945 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
946};
947
948static void
949msmsdcc_check_status(unsigned long data)
950{
951 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
952 unsigned int status;
953
954 if (!host->plat->status) {
955 mmc_detect_change(host->mmc, 0);
956 goto out;
957 }
958
959 status = host->plat->status(mmc_dev(host->mmc));
960 host->eject = !status;
961 if (status ^ host->oldstat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700962 pr_info("%s: Slot status change detected (%d -> %d)\n",
963 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -0700964 if (status)
965 mmc_detect_change(host->mmc, (5 * HZ) / 2);
966 else
967 mmc_detect_change(host->mmc, 0);
968 }
969
970 host->oldstat = status;
971
972out:
973 if (host->timer.function)
974 mod_timer(&host->timer, jiffies + HZ);
975}
976
977static irqreturn_t
978msmsdcc_platform_status_irq(int irq, void *dev_id)
979{
980 struct msmsdcc_host *host = dev_id;
981
982 printk(KERN_DEBUG "%s: %d\n", __func__, irq);
983 msmsdcc_check_status((unsigned long) host);
984 return IRQ_HANDLED;
985}
986
987static void
988msmsdcc_status_notify_cb(int card_present, void *dev_id)
989{
990 struct msmsdcc_host *host = dev_id;
991
992 printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc),
993 card_present);
994 msmsdcc_check_status((unsigned long) host);
995}
996
San Mehat865c80642009-11-13 13:42:06 -0800997static void
998msmsdcc_busclk_expired(unsigned long _data)
999{
1000 struct msmsdcc_host *host = (struct msmsdcc_host *) _data;
1001 unsigned long flags;
1002
1003 spin_lock_irqsave(&host->lock, flags);
1004 if (host->clks_on)
1005 msmsdcc_enable_clocks(host, 0);
1006
1007 spin_unlock_irqrestore(&host->lock, flags);
1008}
1009
San Mehat9d2bd732009-09-22 16:44:22 -07001010static int
1011msmsdcc_init_dma(struct msmsdcc_host *host)
1012{
1013 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
1014 host->dma.host = host;
1015 host->dma.channel = -1;
1016
1017 if (!host->dmares)
1018 return -ENODEV;
1019
1020 host->dma.nc = dma_alloc_coherent(NULL,
1021 sizeof(struct msmsdcc_nc_dmadata),
1022 &host->dma.nc_busaddr,
1023 GFP_KERNEL);
1024 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001025 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001026 return -ENOMEM;
1027 }
1028 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
1029 host->dma.cmd_busaddr = host->dma.nc_busaddr;
1030 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
1031 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
1032 host->dma.channel = host->dmares->start;
1033
1034 return 0;
1035}
1036
1037#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
1038static void
1039do_resume_work(struct work_struct *work)
1040{
1041 struct msmsdcc_host *host =
1042 container_of(work, struct msmsdcc_host, resume_task);
1043 struct mmc_host *mmc = host->mmc;
1044
1045 if (mmc) {
1046 mmc_resume_host(mmc);
1047 if (host->stat_irq)
1048 enable_irq(host->stat_irq);
1049 }
1050}
1051#endif
1052
1053static int
1054msmsdcc_probe(struct platform_device *pdev)
1055{
1056 struct mmc_platform_data *plat = pdev->dev.platform_data;
1057 struct msmsdcc_host *host;
1058 struct mmc_host *mmc;
1059 struct resource *cmd_irqres = NULL;
1060 struct resource *pio_irqres = NULL;
1061 struct resource *stat_irqres = NULL;
1062 struct resource *memres = NULL;
1063 struct resource *dmares = NULL;
1064 int ret;
1065
1066 /* must have platform data */
1067 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001068 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001069 ret = -EINVAL;
1070 goto out;
1071 }
1072
1073 if (pdev->id < 1 || pdev->id > 4)
1074 return -EINVAL;
1075
1076 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001077 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001078 return -ENXIO;
1079 }
1080
1081 memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1082 dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1083 cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1084 "cmd_irq");
1085 pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1086 "pio_irq");
1087 stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1088 "status_irq");
1089
1090 if (!cmd_irqres || !pio_irqres || !memres) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001091 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001092 return -ENXIO;
1093 }
1094
1095 /*
1096 * Setup our host structure
1097 */
1098
1099 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
1100 if (!mmc) {
1101 ret = -ENOMEM;
1102 goto out;
1103 }
1104
1105 host = mmc_priv(mmc);
1106 host->pdev_id = pdev->id;
1107 host->plat = plat;
1108 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08001109 host->curr.cmd = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07001110
1111 host->cmdpoll = 1;
1112
San Mehat865c80642009-11-13 13:42:06 -08001113 host->use_bustimer = 1;
1114
San Mehat9d2bd732009-09-22 16:44:22 -07001115 host->base = ioremap(memres->start, PAGE_SIZE);
1116 if (!host->base) {
1117 ret = -ENOMEM;
1118 goto out;
1119 }
1120
1121 host->cmd_irqres = cmd_irqres;
1122 host->pio_irqres = pio_irqres;
1123 host->memres = memres;
1124 host->dmares = dmares;
1125 spin_lock_init(&host->lock);
1126
1127 /*
1128 * Setup DMA
1129 */
1130 msmsdcc_init_dma(host);
1131
San Mehat4adbbcc2009-11-08 13:00:37 -08001132 /* Get our clocks */
San Mehat9d2bd732009-09-22 16:44:22 -07001133 host->pclk = clk_get(&pdev->dev, "sdc_pclk");
1134 if (IS_ERR(host->pclk)) {
1135 ret = PTR_ERR(host->pclk);
1136 goto host_free;
1137 }
1138
San Mehat9d2bd732009-09-22 16:44:22 -07001139 host->clk = clk_get(&pdev->dev, "sdc_clk");
1140 if (IS_ERR(host->clk)) {
1141 ret = PTR_ERR(host->clk);
San Mehat4adbbcc2009-11-08 13:00:37 -08001142 goto pclk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07001143 }
1144
San Mehat4adbbcc2009-11-08 13:00:37 -08001145 /* Enable clocks */
1146 ret = msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -07001147 if (ret)
1148 goto clk_put;
1149
1150 ret = clk_set_rate(host->clk, msmsdcc_fmin);
1151 if (ret) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001152 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07001153 goto clk_disable;
1154 }
1155
San Mehat4adbbcc2009-11-08 13:00:37 -08001156 host->pclk_rate = clk_get_rate(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07001157 host->clk_rate = clk_get_rate(host->clk);
1158
San Mehat9d2bd732009-09-22 16:44:22 -07001159 /*
1160 * Setup MMC host structure
1161 */
1162 mmc->ops = &msmsdcc_ops;
1163 mmc->f_min = msmsdcc_fmin;
1164 mmc->f_max = msmsdcc_fmax;
1165 mmc->ocr_avail = plat->ocr_mask;
1166
1167 if (msmsdcc_4bit)
1168 mmc->caps |= MMC_CAP_4_BIT_DATA;
1169 if (msmsdcc_sdioirq)
1170 mmc->caps |= MMC_CAP_SDIO_IRQ;
1171 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
1172
1173 mmc->max_phys_segs = NR_SG;
1174 mmc->max_hw_segs = NR_SG;
1175 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
1176 mmc->max_blk_count = 65536;
1177
1178 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
1179 mmc->max_seg_size = mmc->max_req_size;
1180
San Mehat8b1c2ba2009-11-16 10:17:30 -08001181 msmsdcc_writel(host, 0, MMCIMASK0);
1182 msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07001183
San Mehat8b1c2ba2009-11-16 10:17:30 -08001184 msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001185 host->saved_irq0mask = MCI_IRQENABLE;
1186
1187 /*
1188 * Setup card detect change
1189 */
1190
1191 memset(&host->timer, 0, sizeof(host->timer));
1192
1193 if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) {
1194 unsigned long irqflags = IRQF_SHARED |
1195 (stat_irqres->flags & IRQF_TRIGGER_MASK);
1196
1197 host->stat_irq = stat_irqres->start;
1198 ret = request_irq(host->stat_irq,
1199 msmsdcc_platform_status_irq,
1200 irqflags,
1201 DRIVER_NAME " (slot)",
1202 host);
1203 if (ret) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001204 pr_err("%s: Unable to get slot IRQ %d (%d)\n",
1205 mmc_hostname(mmc), host->stat_irq, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07001206 goto clk_disable;
1207 }
1208 } else if (plat->register_status_notify) {
1209 plat->register_status_notify(msmsdcc_status_notify_cb, host);
1210 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001211 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07001212 mmc_hostname(mmc));
1213 else {
1214 init_timer(&host->timer);
1215 host->timer.data = (unsigned long)host;
1216 host->timer.function = msmsdcc_check_status;
1217 host->timer.expires = jiffies + HZ;
1218 add_timer(&host->timer);
1219 }
1220
1221 if (plat->status) {
1222 host->oldstat = host->plat->status(mmc_dev(host->mmc));
1223 host->eject = !host->oldstat;
1224 }
1225
San Mehat865c80642009-11-13 13:42:06 -08001226 init_timer(&host->busclk_timer);
1227 host->busclk_timer.data = (unsigned long) host;
1228 host->busclk_timer.function = msmsdcc_busclk_expired;
1229
San Mehat9d2bd732009-09-22 16:44:22 -07001230 ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
1231 DRIVER_NAME " (cmd)", host);
1232 if (ret)
1233 goto stat_irq_free;
1234
1235 ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
1236 DRIVER_NAME " (pio)", host);
1237 if (ret)
1238 goto cmd_irq_free;
1239
1240 mmc_set_drvdata(pdev, mmc);
1241 mmc_add_host(mmc);
1242
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001243 pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
1244 mmc_hostname(mmc), (unsigned long long)memres->start,
1245 (unsigned int) cmd_irqres->start,
1246 (unsigned int) host->stat_irq, host->dma.channel);
1247 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
1248 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
1249 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
1250 mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate);
1251 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject);
1252 pr_info("%s: Power save feature enable = %d\n",
1253 mmc_hostname(mmc), msmsdcc_pwrsave);
San Mehat9d2bd732009-09-22 16:44:22 -07001254
1255 if (host->dma.channel != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001256 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
1257 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
1258 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
1259 mmc_hostname(mmc), host->dma.cmd_busaddr,
1260 host->dma.cmdptr_busaddr);
San Mehat9d2bd732009-09-22 16:44:22 -07001261 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001262 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001263 if (host->timer.function)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001264 pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001265
San Mehat51905dc2009-11-16 11:59:01 -08001266 if (host->use_bustimer)
San Mehat56a8b5b2009-11-21 12:29:46 -08001267 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
San Mehat9d2bd732009-09-22 16:44:22 -07001268 return 0;
1269 cmd_irq_free:
1270 free_irq(cmd_irqres->start, host);
1271 stat_irq_free:
1272 if (host->stat_irq)
1273 free_irq(host->stat_irq, host);
1274 clk_disable:
San Mehat4adbbcc2009-11-08 13:00:37 -08001275 msmsdcc_enable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07001276 clk_put:
1277 clk_put(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07001278 pclk_put:
1279 clk_put(host->pclk);
1280 host_free:
1281 mmc_free_host(mmc);
1282 out:
1283 return ret;
1284}
1285
1286static int
1287msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
1288{
1289 struct mmc_host *mmc = mmc_get_drvdata(dev);
1290 int rc = 0;
San Mehat56a8b5b2009-11-21 12:29:46 -08001291 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001292
1293 if (mmc) {
1294 struct msmsdcc_host *host = mmc_priv(mmc);
1295
San Mehat56a8b5b2009-11-21 12:29:46 -08001296 if (host->use_bustimer)
1297 del_timer_sync(&host->busclk_timer);
1298 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001299 if (host->stat_irq)
1300 disable_irq(host->stat_irq);
1301
1302 if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
1303 rc = mmc_suspend_host(mmc, state);
1304 if (!rc) {
San Mehat8b1c2ba2009-11-16 10:17:30 -08001305 msmsdcc_writel(host, 0, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001306
San Mehat4adbbcc2009-11-08 13:00:37 -08001307 if (host->clks_on)
1308 msmsdcc_enable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07001309 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001310 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001311 }
1312 return rc;
1313}
1314
1315static int
1316msmsdcc_resume(struct platform_device *dev)
1317{
1318 struct mmc_host *mmc = mmc_get_drvdata(dev);
1319 unsigned long flags;
1320
1321 if (mmc) {
1322 struct msmsdcc_host *host = mmc_priv(mmc);
1323
1324 spin_lock_irqsave(&host->lock, flags);
1325
San Mehat4adbbcc2009-11-08 13:00:37 -08001326 if (!host->clks_on)
1327 msmsdcc_enable_clocks(host, 1);
San Mehat9d2bd732009-09-22 16:44:22 -07001328
San Mehat56a8b5b2009-11-21 12:29:46 -08001329 if (host->use_bustimer)
1330 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
1331
San Mehat8b1c2ba2009-11-16 10:17:30 -08001332 msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001333
1334 spin_unlock_irqrestore(&host->lock, flags);
1335
1336 if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
1337 mmc_resume_host(mmc);
Roel Kluin5b8a2fb2010-01-17 20:25:36 +01001338 if (host->stat_irq)
San Mehat9d2bd732009-09-22 16:44:22 -07001339 enable_irq(host->stat_irq);
1340 }
1341 return 0;
1342}
1343
1344static struct platform_driver msmsdcc_driver = {
1345 .probe = msmsdcc_probe,
1346 .suspend = msmsdcc_suspend,
1347 .resume = msmsdcc_resume,
1348 .driver = {
1349 .name = "msm_sdcc",
1350 },
1351};
1352
1353static int __init msmsdcc_init(void)
1354{
1355 return platform_driver_register(&msmsdcc_driver);
1356}
1357
1358static void __exit msmsdcc_exit(void)
1359{
1360 platform_driver_unregister(&msmsdcc_driver);
1361}
1362
1363module_init(msmsdcc_init);
1364module_exit(msmsdcc_exit);
1365
1366MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
1367MODULE_LICENSE("GPL");