提交 88ff82ed 编写于 作者: A Anders Grahn 提交者: Linus Torvalds

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: NAnders Grahn <anders.grahn@hd-wireless.se>
Signed-off-by: NNicolas Ferre <nicolas.ferre@atmel.com>
Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 fdc50a94
...@@ -173,6 +173,7 @@ struct atmel_mci { ...@@ -173,6 +173,7 @@ struct atmel_mci {
* @mmc: The mmc_host representing this slot. * @mmc: The mmc_host representing this slot.
* @host: The MMC controller this slot is using. * @host: The MMC controller this slot is using.
* @sdc_reg: Value of SDCR to be written before using this slot. * @sdc_reg: Value of SDCR to be written before using this slot.
* @sdio_irq: SDIO irq mask for this slot.
* @mrq: mmc_request currently being processed or waiting to be * @mrq: mmc_request currently being processed or waiting to be
* processed, or NULL when the slot is idle. * processed, or NULL when the slot is idle.
* @queue_node: List node for placing this node in the @queue list of * @queue_node: List node for placing this node in the @queue list of
...@@ -191,6 +192,7 @@ struct atmel_mci_slot { ...@@ -191,6 +192,7 @@ struct atmel_mci_slot {
struct atmel_mci *host; struct atmel_mci *host;
u32 sdc_reg; u32 sdc_reg;
u32 sdio_irq;
struct mmc_request *mrq; struct mmc_request *mrq;
struct list_head queue_node; struct list_head queue_node;
...@@ -792,7 +794,7 @@ static void atmci_start_request(struct atmel_mci *host, ...@@ -792,7 +794,7 @@ static void atmci_start_request(struct atmel_mci *host,
mci_writel(host, SDCR, slot->sdc_reg); mci_writel(host, SDCR, slot->sdc_reg);
iflags = mci_readl(host, IMR); iflags = mci_readl(host, IMR);
if (iflags) if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB))
dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
iflags); iflags);
...@@ -1041,11 +1043,23 @@ static int atmci_get_cd(struct mmc_host *mmc) ...@@ -1041,11 +1043,23 @@ static int atmci_get_cd(struct mmc_host *mmc)
return present; return present;
} }
static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct atmel_mci_slot *slot = mmc_priv(mmc);
struct atmel_mci *host = slot->host;
if (enable)
mci_writel(host, IER, slot->sdio_irq);
else
mci_writel(host, IDR, slot->sdio_irq);
}
static const struct mmc_host_ops atmci_ops = { static const struct mmc_host_ops atmci_ops = {
.request = atmci_request, .request = atmci_request,
.set_ios = atmci_set_ios, .set_ios = atmci_set_ios,
.get_ro = atmci_get_ro, .get_ro = atmci_get_ro,
.get_cd = atmci_get_cd, .get_cd = atmci_get_cd,
.enable_sdio_irq = atmci_enable_sdio_irq,
}; };
/* Called with host->lock held */ /* Called with host->lock held */
...@@ -1497,6 +1511,19 @@ static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) ...@@ -1497,6 +1511,19 @@ static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
} }
static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
{
int i;
for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
struct atmel_mci_slot *slot = host->slot[i];
if (slot && (status & slot->sdio_irq)) {
mmc_signal_sdio_irq(slot->mmc);
}
}
}
static irqreturn_t atmci_interrupt(int irq, void *dev_id) static irqreturn_t atmci_interrupt(int irq, void *dev_id)
{ {
struct atmel_mci *host = dev_id; struct atmel_mci *host = dev_id;
...@@ -1536,6 +1563,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) ...@@ -1536,6 +1563,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
if (pending & MCI_CMDRDY) if (pending & MCI_CMDRDY)
atmci_cmd_interrupt(host, status); atmci_cmd_interrupt(host, status);
if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB))
atmci_sdio_interrupt(host, status);
} while (pass_count++ < 5); } while (pass_count++ < 5);
return pass_count ? IRQ_HANDLED : IRQ_NONE; return pass_count ? IRQ_HANDLED : IRQ_NONE;
...@@ -1558,7 +1589,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) ...@@ -1558,7 +1589,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
static int __init atmci_init_slot(struct atmel_mci *host, static int __init atmci_init_slot(struct atmel_mci *host,
struct mci_slot_pdata *slot_data, unsigned int id, struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg) u32 sdc_reg, u32 sdio_irq)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct atmel_mci_slot *slot; struct atmel_mci_slot *slot;
...@@ -1574,11 +1605,14 @@ static int __init atmci_init_slot(struct atmel_mci *host, ...@@ -1574,11 +1605,14 @@ static int __init atmci_init_slot(struct atmel_mci *host,
slot->wp_pin = slot_data->wp_pin; slot->wp_pin = slot_data->wp_pin;
slot->detect_is_active_high = slot_data->detect_is_active_high; slot->detect_is_active_high = slot_data->detect_is_active_high;
slot->sdc_reg = sdc_reg; slot->sdc_reg = sdc_reg;
slot->sdio_irq = sdio_irq;
mmc->ops = &atmci_ops; mmc->ops = &atmci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
mmc->f_max = host->bus_hz / 2; mmc->f_max = host->bus_hz / 2;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
if (sdio_irq)
mmc->caps |= MMC_CAP_SDIO_IRQ;
if (atmci_is_mci2()) if (atmci_is_mci2())
mmc->caps |= MMC_CAP_SD_HIGHSPEED; mmc->caps |= MMC_CAP_SD_HIGHSPEED;
if (slot_data->bus_width >= 4) if (slot_data->bus_width >= 4)
...@@ -1769,13 +1803,13 @@ static int __init atmci_probe(struct platform_device *pdev) ...@@ -1769,13 +1803,13 @@ static int __init atmci_probe(struct platform_device *pdev)
ret = -ENODEV; ret = -ENODEV;
if (pdata->slot[0].bus_width) { if (pdata->slot[0].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[0], ret = atmci_init_slot(host, &pdata->slot[0],
0, MCI_SDCSEL_SLOT_A); 0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA);
if (!ret) if (!ret)
nr_slots++; nr_slots++;
} }
if (pdata->slot[1].bus_width) { if (pdata->slot[1].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[1], ret = atmci_init_slot(host, &pdata->slot[1],
1, MCI_SDCSEL_SLOT_B); 1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB);
if (!ret) if (!ret)
nr_slots++; nr_slots++;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册