aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/pxamci.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-11 21:57:31 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-11 21:57:31 -0400
commit6abd2c860e34add677de50e8b134f5af6f4b0893 (patch)
treed201de170ca4851d66dbd02046fea7d95214fad7 /drivers/mmc/host/pxamci.c
parentd2c75f2f4b8be1c78f275c49e399d5a9b21ce924 (diff)
parent019a5f56ec195aceadada18aaaad0f67294bdaef (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.c71
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
401static 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
389static const struct mmc_host_ops pxamci_ops = { 411static 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
395static void pxamci_dma_irq(int dma, void *devid) 418static 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
401static irqreturn_t pxamci_detect_irq(int irq, void *devid) 434static 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) {