diff options
author | Anders Grahn <anders.grahn@hd-wireless.se> | 2010-05-26 17:42:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 12:12:39 -0400 |
commit | 88ff82ed4ff048c5548db9313b3de327c91234f8 (patch) | |
tree | 410aad3f7b8ad92983c64982f0dc5d2f6fefb6d5 /drivers/mmc/host/atmel-mci.c | |
parent | fdc50a9444b9781f4dd5aa5f7453300d2688cc5f (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.c | 42 |
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 | ||
1046 | static 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 | |||
1044 | static const struct mmc_host_ops atmci_ops = { | 1057 | static 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 | ||
1514 | static 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 | |||
1500 | static irqreturn_t atmci_interrupt(int irq, void *dev_id) | 1527 | static 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 | ||
1559 | static int __init atmci_init_slot(struct atmel_mci *host, | 1590 | static 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 | } |