aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/atmel-mci.c
diff options
context:
space:
mode:
authorAnders Grahn <anders.grahn@hd-wireless.se>2010-05-26 17:42:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-27 12:12:39 -0400
commit88ff82ed4ff048c5548db9313b3de327c91234f8 (patch)
tree410aad3f7b8ad92983c64982f0dc5d2f6fefb6d5 /drivers/mmc/host/atmel-mci.c
parentfdc50a9444b9781f4dd5aa5f7453300d2688cc5f (diff)
mmc: atmel-mci: Add support for SDIO interrupts
Atmel-mci support for SDIO interrupts. This adds the enable_sdio_irq() function and the configuration of sdio irq mask per slot. With this irq mask information, we keep the idea of multiple slot per sd/mmc host (not only A and B). MMC_CAP_SDIO_IRQ is added according to slot configuration. A new little function is added to run mmc_signal_sdio_irq() during interrupt handling routine. Signed-off-by: Anders Grahn <anders.grahn@hd-wireless.se> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: Haavard Skinnemoen <hskinnemoen@atmel.com> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r--drivers/mmc/host/atmel-mci.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index f6013ccbc619..95ef864ad8f9 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -173,6 +173,7 @@ struct atmel_mci {
173 * @mmc: The mmc_host representing this slot. 173 * @mmc: The mmc_host representing this slot.
174 * @host: The MMC controller this slot is using. 174 * @host: The MMC controller this slot is using.
175 * @sdc_reg: Value of SDCR to be written before using this slot. 175 * @sdc_reg: Value of SDCR to be written before using this slot.
176 * @sdio_irq: SDIO irq mask for this slot.
176 * @mrq: mmc_request currently being processed or waiting to be 177 * @mrq: mmc_request currently being processed or waiting to be
177 * processed, or NULL when the slot is idle. 178 * processed, or NULL when the slot is idle.
178 * @queue_node: List node for placing this node in the @queue list of 179 * @queue_node: List node for placing this node in the @queue list of
@@ -191,6 +192,7 @@ struct atmel_mci_slot {
191 struct atmel_mci *host; 192 struct atmel_mci *host;
192 193
193 u32 sdc_reg; 194 u32 sdc_reg;
195 u32 sdio_irq;
194 196
195 struct mmc_request *mrq; 197 struct mmc_request *mrq;
196 struct list_head queue_node; 198 struct list_head queue_node;
@@ -792,7 +794,7 @@ static void atmci_start_request(struct atmel_mci *host,
792 mci_writel(host, SDCR, slot->sdc_reg); 794 mci_writel(host, SDCR, slot->sdc_reg);
793 795
794 iflags = mci_readl(host, IMR); 796 iflags = mci_readl(host, IMR);
795 if (iflags) 797 if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB))
796 dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", 798 dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
797 iflags); 799 iflags);
798 800
@@ -1041,11 +1043,23 @@ static int atmci_get_cd(struct mmc_host *mmc)
1041 return present; 1043 return present;
1042} 1044}
1043 1045
1046static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
1047{
1048 struct atmel_mci_slot *slot = mmc_priv(mmc);
1049 struct atmel_mci *host = slot->host;
1050
1051 if (enable)
1052 mci_writel(host, IER, slot->sdio_irq);
1053 else
1054 mci_writel(host, IDR, slot->sdio_irq);
1055}
1056
1044static const struct mmc_host_ops atmci_ops = { 1057static const struct mmc_host_ops atmci_ops = {
1045 .request = atmci_request, 1058 .request = atmci_request,
1046 .set_ios = atmci_set_ios, 1059 .set_ios = atmci_set_ios,
1047 .get_ro = atmci_get_ro, 1060 .get_ro = atmci_get_ro,
1048 .get_cd = atmci_get_cd, 1061 .get_cd = atmci_get_cd,
1062 .enable_sdio_irq = atmci_enable_sdio_irq,
1049}; 1063};
1050 1064
1051/* Called with host->lock held */ 1065/* Called with host->lock held */
@@ -1497,6 +1511,19 @@ static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
1497 tasklet_schedule(&host->tasklet); 1511 tasklet_schedule(&host->tasklet);
1498} 1512}
1499 1513
1514static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
1515{
1516 int i;
1517
1518 for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
1519 struct atmel_mci_slot *slot = host->slot[i];
1520 if (slot && (status & slot->sdio_irq)) {
1521 mmc_signal_sdio_irq(slot->mmc);
1522 }
1523 }
1524}
1525
1526
1500static irqreturn_t atmci_interrupt(int irq, void *dev_id) 1527static irqreturn_t atmci_interrupt(int irq, void *dev_id)
1501{ 1528{
1502 struct atmel_mci *host = dev_id; 1529 struct atmel_mci *host = dev_id;
@@ -1536,6 +1563,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
1536 1563
1537 if (pending & MCI_CMDRDY) 1564 if (pending & MCI_CMDRDY)
1538 atmci_cmd_interrupt(host, status); 1565 atmci_cmd_interrupt(host, status);
1566
1567 if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB))
1568 atmci_sdio_interrupt(host, status);
1569
1539 } while (pass_count++ < 5); 1570 } while (pass_count++ < 5);
1540 1571
1541 return pass_count ? IRQ_HANDLED : IRQ_NONE; 1572 return pass_count ? IRQ_HANDLED : IRQ_NONE;
@@ -1558,7 +1589,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
1558 1589
1559static int __init atmci_init_slot(struct atmel_mci *host, 1590static int __init atmci_init_slot(struct atmel_mci *host,
1560 struct mci_slot_pdata *slot_data, unsigned int id, 1591 struct mci_slot_pdata *slot_data, unsigned int id,
1561 u32 sdc_reg) 1592 u32 sdc_reg, u32 sdio_irq)
1562{ 1593{
1563 struct mmc_host *mmc; 1594 struct mmc_host *mmc;
1564 struct atmel_mci_slot *slot; 1595 struct atmel_mci_slot *slot;
@@ -1574,11 +1605,14 @@ static int __init atmci_init_slot(struct atmel_mci *host,
1574 slot->wp_pin = slot_data->wp_pin; 1605 slot->wp_pin = slot_data->wp_pin;
1575 slot->detect_is_active_high = slot_data->detect_is_active_high; 1606 slot->detect_is_active_high = slot_data->detect_is_active_high;
1576 slot->sdc_reg = sdc_reg; 1607 slot->sdc_reg = sdc_reg;
1608 slot->sdio_irq = sdio_irq;
1577 1609
1578 mmc->ops = &atmci_ops; 1610 mmc->ops = &atmci_ops;
1579 mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); 1611 mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
1580 mmc->f_max = host->bus_hz / 2; 1612 mmc->f_max = host->bus_hz / 2;
1581 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 1613 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
1614 if (sdio_irq)
1615 mmc->caps |= MMC_CAP_SDIO_IRQ;
1582 if (atmci_is_mci2()) 1616 if (atmci_is_mci2())
1583 mmc->caps |= MMC_CAP_SD_HIGHSPEED; 1617 mmc->caps |= MMC_CAP_SD_HIGHSPEED;
1584 if (slot_data->bus_width >= 4) 1618 if (slot_data->bus_width >= 4)
@@ -1769,13 +1803,13 @@ static int __init atmci_probe(struct platform_device *pdev)
1769 ret = -ENODEV; 1803 ret = -ENODEV;
1770 if (pdata->slot[0].bus_width) { 1804 if (pdata->slot[0].bus_width) {
1771 ret = atmci_init_slot(host, &pdata->slot[0], 1805 ret = atmci_init_slot(host, &pdata->slot[0],
1772 0, MCI_SDCSEL_SLOT_A); 1806 0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA);
1773 if (!ret) 1807 if (!ret)
1774 nr_slots++; 1808 nr_slots++;
1775 } 1809 }
1776 if (pdata->slot[1].bus_width) { 1810 if (pdata->slot[1].bus_width) {
1777 ret = atmci_init_slot(host, &pdata->slot[1], 1811 ret = atmci_init_slot(host, &pdata->slot[1],
1778 1, MCI_SDCSEL_SLOT_B); 1812 1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB);
1779 if (!ret) 1813 if (!ret)
1780 nr_slots++; 1814 nr_slots++;
1781 } 1815 }