Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anders Grahn and committed by
Linus Torvalds
88ff82ed fdc50a94

+38 -4
+38 -4
drivers/mmc/host/atmel-mci.c
··· 173 173 * @mmc: The mmc_host representing this slot. 174 174 * @host: The MMC controller this slot is using. 175 175 * @sdc_reg: Value of SDCR to be written before using this slot. 176 + * @sdio_irq: SDIO irq mask for this slot. 176 177 * @mrq: mmc_request currently being processed or waiting to be 177 178 * processed, or NULL when the slot is idle. 178 179 * @queue_node: List node for placing this node in the @queue list of ··· 192 191 struct atmel_mci *host; 193 192 194 193 u32 sdc_reg; 194 + u32 sdio_irq; 195 195 196 196 struct mmc_request *mrq; 197 197 struct list_head queue_node; ··· 794 792 mci_writel(host, SDCR, slot->sdc_reg); 795 793 796 794 iflags = mci_readl(host, IMR); 797 - if (iflags) 795 + if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB)) 798 796 dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", 799 797 iflags); 800 798 ··· 1043 1041 return present; 1044 1042 } 1045 1043 1044 + static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) 1045 + { 1046 + struct atmel_mci_slot *slot = mmc_priv(mmc); 1047 + struct atmel_mci *host = slot->host; 1048 + 1049 + if (enable) 1050 + mci_writel(host, IER, slot->sdio_irq); 1051 + else 1052 + mci_writel(host, IDR, slot->sdio_irq); 1053 + } 1054 + 1046 1055 static const struct mmc_host_ops atmci_ops = { 1047 1056 .request = atmci_request, 1048 1057 .set_ios = atmci_set_ios, 1049 1058 .get_ro = atmci_get_ro, 1050 1059 .get_cd = atmci_get_cd, 1060 + .enable_sdio_irq = atmci_enable_sdio_irq, 1051 1061 }; 1052 1062 1053 1063 /* Called with host->lock held */ ··· 1511 1497 tasklet_schedule(&host->tasklet); 1512 1498 } 1513 1499 1500 + static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) 1501 + { 1502 + int i; 1503 + 1504 + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { 1505 + struct atmel_mci_slot *slot = host->slot[i]; 1506 + if (slot && (status & slot->sdio_irq)) { 1507 + mmc_signal_sdio_irq(slot->mmc); 1508 + } 1509 + } 1510 + } 1511 + 1512 + 1514 1513 static irqreturn_t atmci_interrupt(int irq, void *dev_id) 1515 1514 { 1516 1515 struct atmel_mci *host = dev_id; ··· 1563 1536 1564 1537 if (pending & MCI_CMDRDY) 1565 1538 atmci_cmd_interrupt(host, status); 1539 + 1540 + if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB)) 1541 + atmci_sdio_interrupt(host, status); 1542 + 1566 1543 } while (pass_count++ < 5); 1567 1544 1568 1545 return pass_count ? IRQ_HANDLED : IRQ_NONE; ··· 1589 1558 1590 1559 static int __init atmci_init_slot(struct atmel_mci *host, 1591 1560 struct mci_slot_pdata *slot_data, unsigned int id, 1592 - u32 sdc_reg) 1561 + u32 sdc_reg, u32 sdio_irq) 1593 1562 { 1594 1563 struct mmc_host *mmc; 1595 1564 struct atmel_mci_slot *slot; ··· 1605 1574 slot->wp_pin = slot_data->wp_pin; 1606 1575 slot->detect_is_active_high = slot_data->detect_is_active_high; 1607 1576 slot->sdc_reg = sdc_reg; 1577 + slot->sdio_irq = sdio_irq; 1608 1578 1609 1579 mmc->ops = &atmci_ops; 1610 1580 mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); 1611 1581 mmc->f_max = host->bus_hz / 2; 1612 1582 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 1583 + if (sdio_irq) 1584 + mmc->caps |= MMC_CAP_SDIO_IRQ; 1613 1585 if (atmci_is_mci2()) 1614 1586 mmc->caps |= MMC_CAP_SD_HIGHSPEED; 1615 1587 if (slot_data->bus_width >= 4) ··· 1803 1769 ret = -ENODEV; 1804 1770 if (pdata->slot[0].bus_width) { 1805 1771 ret = atmci_init_slot(host, &pdata->slot[0], 1806 - 0, MCI_SDCSEL_SLOT_A); 1772 + 0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA); 1807 1773 if (!ret) 1808 1774 nr_slots++; 1809 1775 } 1810 1776 if (pdata->slot[1].bus_width) { 1811 1777 ret = atmci_init_slot(host, &pdata->slot[1], 1812 - 1, MCI_SDCSEL_SLOT_B); 1778 + 1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB); 1813 1779 if (!ret) 1814 1780 nr_slots++; 1815 1781 }