diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 103 |
1 files changed, 28 insertions, 75 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 1e97916914ad..76bfe16c09b1 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -55,7 +55,6 @@ enum atmel_mci_state { | |||
55 | 55 | ||
56 | struct atmel_mci_dma { | 56 | struct atmel_mci_dma { |
57 | #ifdef CONFIG_MMC_ATMELMCI_DMA | 57 | #ifdef CONFIG_MMC_ATMELMCI_DMA |
58 | struct dma_client client; | ||
59 | struct dma_chan *chan; | 58 | struct dma_chan *chan; |
60 | struct dma_async_tx_descriptor *data_desc; | 59 | struct dma_async_tx_descriptor *data_desc; |
61 | #endif | 60 | #endif |
@@ -593,10 +592,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) | |||
593 | 592 | ||
594 | /* If we don't have a channel, we can't do DMA */ | 593 | /* If we don't have a channel, we can't do DMA */ |
595 | chan = host->dma.chan; | 594 | chan = host->dma.chan; |
596 | if (chan) { | 595 | if (chan) |
597 | dma_chan_get(chan); | ||
598 | host->data_chan = chan; | 596 | host->data_chan = chan; |
599 | } | ||
600 | 597 | ||
601 | if (!chan) | 598 | if (!chan) |
602 | return -ENODEV; | 599 | return -ENODEV; |
@@ -1443,60 +1440,6 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) | |||
1443 | return IRQ_HANDLED; | 1440 | return IRQ_HANDLED; |
1444 | } | 1441 | } |
1445 | 1442 | ||
1446 | #ifdef CONFIG_MMC_ATMELMCI_DMA | ||
1447 | |||
1448 | static inline struct atmel_mci * | ||
1449 | dma_client_to_atmel_mci(struct dma_client *client) | ||
1450 | { | ||
1451 | return container_of(client, struct atmel_mci, dma.client); | ||
1452 | } | ||
1453 | |||
1454 | static enum dma_state_client atmci_dma_event(struct dma_client *client, | ||
1455 | struct dma_chan *chan, enum dma_state state) | ||
1456 | { | ||
1457 | struct atmel_mci *host; | ||
1458 | enum dma_state_client ret = DMA_NAK; | ||
1459 | |||
1460 | host = dma_client_to_atmel_mci(client); | ||
1461 | |||
1462 | switch (state) { | ||
1463 | case DMA_RESOURCE_AVAILABLE: | ||
1464 | spin_lock_bh(&host->lock); | ||
1465 | if (!host->dma.chan) { | ||
1466 | host->dma.chan = chan; | ||
1467 | ret = DMA_ACK; | ||
1468 | } | ||
1469 | spin_unlock_bh(&host->lock); | ||
1470 | |||
1471 | if (ret == DMA_ACK) | ||
1472 | dev_info(&host->pdev->dev, | ||
1473 | "Using %s for DMA transfers\n", | ||
1474 | chan->dev.bus_id); | ||
1475 | break; | ||
1476 | |||
1477 | case DMA_RESOURCE_REMOVED: | ||
1478 | spin_lock_bh(&host->lock); | ||
1479 | if (host->dma.chan == chan) { | ||
1480 | host->dma.chan = NULL; | ||
1481 | ret = DMA_ACK; | ||
1482 | } | ||
1483 | spin_unlock_bh(&host->lock); | ||
1484 | |||
1485 | if (ret == DMA_ACK) | ||
1486 | dev_info(&host->pdev->dev, | ||
1487 | "Lost %s, falling back to PIO\n", | ||
1488 | chan->dev.bus_id); | ||
1489 | break; | ||
1490 | |||
1491 | default: | ||
1492 | break; | ||
1493 | } | ||
1494 | |||
1495 | |||
1496 | return ret; | ||
1497 | } | ||
1498 | #endif /* CONFIG_MMC_ATMELMCI_DMA */ | ||
1499 | |||
1500 | static int __init atmci_init_slot(struct atmel_mci *host, | 1443 | static int __init atmci_init_slot(struct atmel_mci *host, |
1501 | struct mci_slot_pdata *slot_data, unsigned int id, | 1444 | struct mci_slot_pdata *slot_data, unsigned int id, |
1502 | u32 sdc_reg) | 1445 | u32 sdc_reg) |
@@ -1600,6 +1543,18 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, | |||
1600 | mmc_free_host(slot->mmc); | 1543 | mmc_free_host(slot->mmc); |
1601 | } | 1544 | } |
1602 | 1545 | ||
1546 | #ifdef CONFIG_MMC_ATMELMCI_DMA | ||
1547 | static bool filter(struct dma_chan *chan, void *slave) | ||
1548 | { | ||
1549 | struct dw_dma_slave *dws = slave; | ||
1550 | |||
1551 | if (dws->dma_dev == chan->device->dev) | ||
1552 | return true; | ||
1553 | else | ||
1554 | return false; | ||
1555 | } | ||
1556 | #endif | ||
1557 | |||
1603 | static int __init atmci_probe(struct platform_device *pdev) | 1558 | static int __init atmci_probe(struct platform_device *pdev) |
1604 | { | 1559 | { |
1605 | struct mci_platform_data *pdata; | 1560 | struct mci_platform_data *pdata; |
@@ -1652,22 +1607,20 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
1652 | goto err_request_irq; | 1607 | goto err_request_irq; |
1653 | 1608 | ||
1654 | #ifdef CONFIG_MMC_ATMELMCI_DMA | 1609 | #ifdef CONFIG_MMC_ATMELMCI_DMA |
1655 | if (pdata->dma_slave) { | 1610 | if (pdata->dma_slave.dma_dev) { |
1656 | struct dma_slave *slave = pdata->dma_slave; | 1611 | struct dw_dma_slave *dws = &pdata->dma_slave; |
1612 | dma_cap_mask_t mask; | ||
1657 | 1613 | ||
1658 | slave->tx_reg = regs->start + MCI_TDR; | 1614 | dws->tx_reg = regs->start + MCI_TDR; |
1659 | slave->rx_reg = regs->start + MCI_RDR; | 1615 | dws->rx_reg = regs->start + MCI_RDR; |
1660 | 1616 | ||
1661 | /* Try to grab a DMA channel */ | 1617 | /* Try to grab a DMA channel */ |
1662 | host->dma.client.event_callback = atmci_dma_event; | 1618 | dma_cap_zero(mask); |
1663 | dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask); | 1619 | dma_cap_set(DMA_SLAVE, mask); |
1664 | host->dma.client.slave = slave; | 1620 | host->dma.chan = dma_request_channel(mask, filter, dws); |
1665 | |||
1666 | dma_async_client_register(&host->dma.client); | ||
1667 | dma_async_client_chan_request(&host->dma.client); | ||
1668 | } else { | ||
1669 | dev_notice(&pdev->dev, "DMA not available, using PIO\n"); | ||
1670 | } | 1621 | } |
1622 | if (!host->dma.chan) | ||
1623 | dev_notice(&pdev->dev, "DMA not available, using PIO\n"); | ||
1671 | #endif /* CONFIG_MMC_ATMELMCI_DMA */ | 1624 | #endif /* CONFIG_MMC_ATMELMCI_DMA */ |
1672 | 1625 | ||
1673 | platform_set_drvdata(pdev, host); | 1626 | platform_set_drvdata(pdev, host); |
@@ -1699,8 +1652,8 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
1699 | 1652 | ||
1700 | err_init_slot: | 1653 | err_init_slot: |
1701 | #ifdef CONFIG_MMC_ATMELMCI_DMA | 1654 | #ifdef CONFIG_MMC_ATMELMCI_DMA |
1702 | if (pdata->dma_slave) | 1655 | if (host->dma.chan) |
1703 | dma_async_client_unregister(&host->dma.client); | 1656 | dma_release_channel(host->dma.chan); |
1704 | #endif | 1657 | #endif |
1705 | free_irq(irq, host); | 1658 | free_irq(irq, host); |
1706 | err_request_irq: | 1659 | err_request_irq: |
@@ -1731,8 +1684,8 @@ static int __exit atmci_remove(struct platform_device *pdev) | |||
1731 | clk_disable(host->mck); | 1684 | clk_disable(host->mck); |
1732 | 1685 | ||
1733 | #ifdef CONFIG_MMC_ATMELMCI_DMA | 1686 | #ifdef CONFIG_MMC_ATMELMCI_DMA |
1734 | if (host->dma.client.slave) | 1687 | if (host->dma.chan) |
1735 | dma_async_client_unregister(&host->dma.client); | 1688 | dma_release_channel(host->dma.chan); |
1736 | #endif | 1689 | #endif |
1737 | 1690 | ||
1738 | free_irq(platform_get_irq(pdev, 0), host); | 1691 | free_irq(platform_get_irq(pdev, 0), host); |
@@ -1761,7 +1714,7 @@ static void __exit atmci_exit(void) | |||
1761 | platform_driver_unregister(&atmci_driver); | 1714 | platform_driver_unregister(&atmci_driver); |
1762 | } | 1715 | } |
1763 | 1716 | ||
1764 | module_init(atmci_init); | 1717 | late_initcall(atmci_init); /* try to load after dma driver when built-in */ |
1765 | module_exit(atmci_exit); | 1718 | module_exit(atmci_exit); |
1766 | 1719 | ||
1767 | MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); | 1720 | MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); |