diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-11 21:57:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-11 21:57:31 -0400 |
commit | 6abd2c860e34add677de50e8b134f5af6f4b0893 (patch) | |
tree | d201de170ca4851d66dbd02046fea7d95214fad7 /drivers/mmc/host/pxamci.c | |
parent | d2c75f2f4b8be1c78f275c49e399d5a9b21ce924 (diff) | |
parent | 019a5f56ec195aceadada18aaaad0f67294bdaef (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (67 commits)
mmc: don't use weight32()
pxamci: support arbitrary block size
sdio: make the IRQ thread more resilient in the presence of bad states
sdio: fix IRQ diagnostic message
sdhci: remove old dma module params
sdhci: add SDHCI_QUIRK_BROKEN_DMA quirk
sdhci: remove DMA capability check from controller's PCI Class reg
sdhci: fix a typo
mmc: Disabler for Ricoh MMC controller
sdio: adaptive interrupt polling
mmc: pxamci: add SDIO card interrupt reporting capability
mmc: pxamci: set proper buswidth capabilities according to PXA flavor
mmc: pxamci: set proper block capabilities according to PXA flavor
mmc: pxamci: better pending IRQ determination
arm: i.MX/MX1 SDHC implements SD cards read-only switch read-back
mmc: add led trigger
mmc_spi host driver
MMC core learns about SPI
MMC/SD card driver learns SPI
MMC headers learn about SPI
...
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
-rw-r--r-- | drivers/mmc/host/pxamci.c | 71 |
1 files changed, 55 insertions, 16 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index ff960334b337..657901eecfce 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
@@ -142,6 +142,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) | |||
142 | host->dma_dir); | 142 | host->dma_dir); |
143 | 143 | ||
144 | for (i = 0; i < host->dma_len; i++) { | 144 | for (i = 0; i < host->dma_len; i++) { |
145 | unsigned int length = sg_dma_len(&data->sg[i]); | ||
146 | host->sg_cpu[i].dcmd = dcmd | length; | ||
147 | if (length & 31 && !(data->flags & MMC_DATA_READ)) | ||
148 | host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; | ||
145 | if (data->flags & MMC_DATA_READ) { | 149 | if (data->flags & MMC_DATA_READ) { |
146 | host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; | 150 | host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; |
147 | host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); | 151 | host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); |
@@ -149,7 +153,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) | |||
149 | host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); | 153 | host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); |
150 | host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; | 154 | host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; |
151 | } | 155 | } |
152 | host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]); | ||
153 | host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * | 156 | host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * |
154 | sizeof(struct pxa_dma_desc); | 157 | sizeof(struct pxa_dma_desc); |
155 | } | 158 | } |
@@ -226,7 +229,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) | |||
226 | } | 229 | } |
227 | 230 | ||
228 | if (stat & STAT_TIME_OUT_RESPONSE) { | 231 | if (stat & STAT_TIME_OUT_RESPONSE) { |
229 | cmd->error = MMC_ERR_TIMEOUT; | 232 | cmd->error = -ETIMEDOUT; |
230 | } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { | 233 | } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { |
231 | #ifdef CONFIG_PXA27x | 234 | #ifdef CONFIG_PXA27x |
232 | /* | 235 | /* |
@@ -239,11 +242,11 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) | |||
239 | pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); | 242 | pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); |
240 | } else | 243 | } else |
241 | #endif | 244 | #endif |
242 | cmd->error = MMC_ERR_BADCRC; | 245 | cmd->error = -EILSEQ; |
243 | } | 246 | } |
244 | 247 | ||
245 | pxamci_disable_irq(host, END_CMD_RES); | 248 | pxamci_disable_irq(host, END_CMD_RES); |
246 | if (host->data && cmd->error == MMC_ERR_NONE) { | 249 | if (host->data && !cmd->error) { |
247 | pxamci_enable_irq(host, DATA_TRAN_DONE); | 250 | pxamci_enable_irq(host, DATA_TRAN_DONE); |
248 | } else { | 251 | } else { |
249 | pxamci_finish_request(host, host->mrq); | 252 | pxamci_finish_request(host, host->mrq); |
@@ -264,9 +267,9 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) | |||
264 | host->dma_dir); | 267 | host->dma_dir); |
265 | 268 | ||
266 | if (stat & STAT_READ_TIME_OUT) | 269 | if (stat & STAT_READ_TIME_OUT) |
267 | data->error = MMC_ERR_TIMEOUT; | 270 | data->error = -ETIMEDOUT; |
268 | else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) | 271 | else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) |
269 | data->error = MMC_ERR_BADCRC; | 272 | data->error = -EILSEQ; |
270 | 273 | ||
271 | /* | 274 | /* |
272 | * There appears to be a hardware design bug here. There seems to | 275 | * There appears to be a hardware design bug here. There seems to |
@@ -274,7 +277,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) | |||
274 | * This means that if there was an error on any block, we mark all | 277 | * This means that if there was an error on any block, we mark all |
275 | * data blocks as being in error. | 278 | * data blocks as being in error. |
276 | */ | 279 | */ |
277 | if (data->error == MMC_ERR_NONE) | 280 | if (!data->error) |
278 | data->bytes_xfered = data->blocks * data->blksz; | 281 | data->bytes_xfered = data->blocks * data->blksz; |
279 | else | 282 | else |
280 | data->bytes_xfered = 0; | 283 | data->bytes_xfered = 0; |
@@ -284,7 +287,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) | |||
284 | host->data = NULL; | 287 | host->data = NULL; |
285 | if (host->mrq->stop) { | 288 | if (host->mrq->stop) { |
286 | pxamci_stop_clock(host); | 289 | pxamci_stop_clock(host); |
287 | pxamci_start_cmd(host, host->mrq->stop, 0); | 290 | pxamci_start_cmd(host, host->mrq->stop, host->cmdat); |
288 | } else { | 291 | } else { |
289 | pxamci_finish_request(host, host->mrq); | 292 | pxamci_finish_request(host, host->mrq); |
290 | } | 293 | } |
@@ -298,7 +301,7 @@ static irqreturn_t pxamci_irq(int irq, void *devid) | |||
298 | unsigned int ireg; | 301 | unsigned int ireg; |
299 | int handled = 0; | 302 | int handled = 0; |
300 | 303 | ||
301 | ireg = readl(host->base + MMC_I_REG); | 304 | ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); |
302 | 305 | ||
303 | if (ireg) { | 306 | if (ireg) { |
304 | unsigned stat = readl(host->base + MMC_STAT); | 307 | unsigned stat = readl(host->base + MMC_STAT); |
@@ -309,6 +312,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid) | |||
309 | handled |= pxamci_cmd_done(host, stat); | 312 | handled |= pxamci_cmd_done(host, stat); |
310 | if (ireg & DATA_TRAN_DONE) | 313 | if (ireg & DATA_TRAN_DONE) |
311 | handled |= pxamci_data_done(host, stat); | 314 | handled |= pxamci_data_done(host, stat); |
315 | if (ireg & SDIO_INT) { | ||
316 | mmc_signal_sdio_irq(host->mmc); | ||
317 | handled = 1; | ||
318 | } | ||
312 | } | 319 | } |
313 | 320 | ||
314 | return IRQ_RETVAL(handled); | 321 | return IRQ_RETVAL(handled); |
@@ -382,20 +389,46 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
382 | host->cmdat |= CMDAT_INIT; | 389 | host->cmdat |= CMDAT_INIT; |
383 | } | 390 | } |
384 | 391 | ||
392 | if (ios->bus_width == MMC_BUS_WIDTH_4) | ||
393 | host->cmdat |= CMDAT_SD_4DAT; | ||
394 | else | ||
395 | host->cmdat &= ~CMDAT_SD_4DAT; | ||
396 | |||
385 | pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", | 397 | pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", |
386 | host->clkrt, host->cmdat); | 398 | host->clkrt, host->cmdat); |
387 | } | 399 | } |
388 | 400 | ||
401 | static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) | ||
402 | { | ||
403 | struct pxamci_host *pxa_host = mmc_priv(host); | ||
404 | |||
405 | if (enable) | ||
406 | pxamci_enable_irq(pxa_host, SDIO_INT); | ||
407 | else | ||
408 | pxamci_disable_irq(pxa_host, SDIO_INT); | ||
409 | } | ||
410 | |||
389 | static const struct mmc_host_ops pxamci_ops = { | 411 | static const struct mmc_host_ops pxamci_ops = { |
390 | .request = pxamci_request, | 412 | .request = pxamci_request, |
391 | .get_ro = pxamci_get_ro, | 413 | .get_ro = pxamci_get_ro, |
392 | .set_ios = pxamci_set_ios, | 414 | .set_ios = pxamci_set_ios, |
415 | .enable_sdio_irq = pxamci_enable_sdio_irq, | ||
393 | }; | 416 | }; |
394 | 417 | ||
395 | static void pxamci_dma_irq(int dma, void *devid) | 418 | static void pxamci_dma_irq(int dma, void *devid) |
396 | { | 419 | { |
397 | printk(KERN_ERR "DMA%d: IRQ???\n", dma); | 420 | struct pxamci_host *host = devid; |
398 | DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | 421 | int dcsr = DCSR(dma); |
422 | DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; | ||
423 | |||
424 | if (dcsr & DCSR_ENDINTR) { | ||
425 | writel(BUF_PART_FULL, host->base + MMC_PRTBUF); | ||
426 | } else { | ||
427 | printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||
428 | mmc_hostname(host->mmc), dma, dcsr); | ||
429 | host->data->error = -EIO; | ||
430 | pxamci_data_done(host, 0); | ||
431 | } | ||
399 | } | 432 | } |
400 | 433 | ||
401 | static irqreturn_t pxamci_detect_irq(int irq, void *devid) | 434 | static irqreturn_t pxamci_detect_irq(int irq, void *devid) |
@@ -444,9 +477,9 @@ static int pxamci_probe(struct platform_device *pdev) | |||
444 | mmc->max_seg_size = PAGE_SIZE; | 477 | mmc->max_seg_size = PAGE_SIZE; |
445 | 478 | ||
446 | /* | 479 | /* |
447 | * Block length register is 10 bits. | 480 | * Block length register is only 10 bits before PXA27x. |
448 | */ | 481 | */ |
449 | mmc->max_blk_size = 1023; | 482 | mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048; |
450 | 483 | ||
451 | /* | 484 | /* |
452 | * Block count register is 16 bits. | 485 | * Block count register is 16 bits. |
@@ -460,6 +493,12 @@ static int pxamci_probe(struct platform_device *pdev) | |||
460 | mmc->ocr_avail = host->pdata ? | 493 | mmc->ocr_avail = host->pdata ? |
461 | host->pdata->ocr_mask : | 494 | host->pdata->ocr_mask : |
462 | MMC_VDD_32_33|MMC_VDD_33_34; | 495 | MMC_VDD_32_33|MMC_VDD_33_34; |
496 | mmc->caps = 0; | ||
497 | host->cmdat = 0; | ||
498 | if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { | ||
499 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; | ||
500 | host->cmdat |= CMDAT_SDIO_INT_EN; | ||
501 | } | ||
463 | 502 | ||
464 | host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); | 503 | host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); |
465 | if (!host->sg_cpu) { | 504 | if (!host->sg_cpu) { |