From cc10815e2fb050c5a69472377d339e94bdc033c5 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Tue, 14 Feb 2017 13:03:28 +0100 Subject: [PATCH] MIPS: Alchemy: Threaded carddetect irqs for devboards This introduces threaded carddetect irqs for the db1200/db1300 boards. Main benefit is that the broken insertion/ejection interrupt pairs can now be better supported and debounced in software. Signed-off-by: Manuel Lauss Cc: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15287/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/devboards/db1200.c | 64 ++++++++++++++++------------ arch/mips/alchemy/devboards/db1300.c | 31 ++++++++------ drivers/pcmcia/db1xxx_ss.c | 33 ++++++++------ 3 files changed, 72 insertions(+), 56 deletions(-) diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c index 992442a03d8b..c1bdd6e8191e 100644 --- a/arch/mips/alchemy/devboards/db1200.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -344,28 +344,32 @@ static struct platform_device db1200_ide_dev = { /* SD carddetects: they're supposed to be edge-triggered, but ack * doesn't seem to work (CPLD Rev 2). Instead, the screaming one - * is disabled and its counterpart enabled. The 500ms timeout is - * because the carddetect isn't debounced in hardware. + * is disabled and its counterpart enabled. The 200ms timeout is + * because the carddetect usually triggers twice, after debounce. */ static irqreturn_t db1200_mmc_cd(int irq, void *ptr) { - void(*mmc_cd)(struct mmc_host *, unsigned long); + disable_irq_nosync(irq); + return IRQ_WAKE_THREAD; +} - if (irq == DB1200_SD0_INSERT_INT) { - disable_irq_nosync(DB1200_SD0_INSERT_INT); - enable_irq(DB1200_SD0_EJECT_INT); - } else { - disable_irq_nosync(DB1200_SD0_EJECT_INT); - enable_irq(DB1200_SD0_INSERT_INT); - } +static irqreturn_t db1200_mmc_cdfn(int irq, void *ptr) +{ + void (*mmc_cd)(struct mmc_host *, unsigned long); /* link against CONFIG_MMC=m */ mmc_cd = symbol_get(mmc_detect_change); if (mmc_cd) { - mmc_cd(ptr, msecs_to_jiffies(500)); + mmc_cd(ptr, msecs_to_jiffies(200)); symbol_put(mmc_detect_change); } + msleep(100); /* debounce */ + if (irq == DB1200_SD0_INSERT_INT) + enable_irq(DB1200_SD0_EJECT_INT); + else + enable_irq(DB1200_SD0_INSERT_INT); + return IRQ_HANDLED; } @@ -374,13 +378,13 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en) int ret; if (en) { - ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, - 0, "sd_insert", mmc_host); + ret = request_threaded_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, + db1200_mmc_cdfn, 0, "sd_insert", mmc_host); if (ret) goto out; - ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, - 0, "sd_eject", mmc_host); + ret = request_threaded_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, + db1200_mmc_cdfn, 0, "sd_eject", mmc_host); if (ret) { free_irq(DB1200_SD0_INSERT_INT, mmc_host); goto out; @@ -436,23 +440,27 @@ static struct led_classdev db1200_mmc_led = { static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr) { - void(*mmc_cd)(struct mmc_host *, unsigned long); + disable_irq_nosync(irq); + return IRQ_WAKE_THREAD; +} - if (irq == PB1200_SD1_INSERT_INT) { - disable_irq_nosync(PB1200_SD1_INSERT_INT); - enable_irq(PB1200_SD1_EJECT_INT); - } else { - disable_irq_nosync(PB1200_SD1_EJECT_INT); - enable_irq(PB1200_SD1_INSERT_INT); - } +static irqreturn_t pb1200_mmc1_cdfn(int irq, void *ptr) +{ + void (*mmc_cd)(struct mmc_host *, unsigned long); /* link against CONFIG_MMC=m */ mmc_cd = symbol_get(mmc_detect_change); if (mmc_cd) { - mmc_cd(ptr, msecs_to_jiffies(500)); + mmc_cd(ptr, msecs_to_jiffies(200)); symbol_put(mmc_detect_change); } + msleep(100); /* debounce */ + if (irq == PB1200_SD1_INSERT_INT) + enable_irq(PB1200_SD1_EJECT_INT); + else + enable_irq(PB1200_SD1_INSERT_INT); + return IRQ_HANDLED; } @@ -461,13 +469,13 @@ static int pb1200_mmc1_cd_setup(void *mmc_host, int en) int ret; if (en) { - ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0, - "sd1_insert", mmc_host); + ret = request_threaded_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, + pb1200_mmc1_cdfn, 0, "sd1_insert", mmc_host); if (ret) goto out; - ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0, - "sd1_eject", mmc_host); + ret = request_threaded_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, + pb1200_mmc1_cdfn, 0, "sd1_eject", mmc_host); if (ret) { free_irq(PB1200_SD1_INSERT_INT, mmc_host); goto out; diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index a5504f57cb00..1468b6af96e2 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -450,24 +450,27 @@ static struct platform_device db1300_ide_dev = { static irqreturn_t db1300_mmc_cd(int irq, void *ptr) { - void(*mmc_cd)(struct mmc_host *, unsigned long); + disable_irq_nosync(irq); + return IRQ_WAKE_THREAD; +} - /* disable the one currently screaming. No other way to shut it up */ - if (irq == DB1300_SD1_INSERT_INT) { - disable_irq_nosync(DB1300_SD1_INSERT_INT); - enable_irq(DB1300_SD1_EJECT_INT); - } else { - disable_irq_nosync(DB1300_SD1_EJECT_INT); - enable_irq(DB1300_SD1_INSERT_INT); - } +static irqreturn_t db1300_mmc_cdfn(int irq, void *ptr) +{ + void (*mmc_cd)(struct mmc_host *, unsigned long); /* link against CONFIG_MMC=m. We can only be called once MMC core has * initialized the controller, so symbol_get() should always succeed. */ mmc_cd = symbol_get(mmc_detect_change); - mmc_cd(ptr, msecs_to_jiffies(500)); + mmc_cd(ptr, msecs_to_jiffies(200)); symbol_put(mmc_detect_change); + msleep(100); /* debounce */ + if (irq == DB1300_SD1_INSERT_INT) + enable_irq(DB1300_SD1_EJECT_INT); + else + enable_irq(DB1300_SD1_INSERT_INT); + return IRQ_HANDLED; } @@ -487,13 +490,13 @@ static int db1300_mmc_cd_setup(void *mmc_host, int en) int ret; if (en) { - ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0, - "sd_insert", mmc_host); + ret = request_threaded_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, + db1300_mmc_cdfn, 0, "sd_insert", mmc_host); if (ret) goto out; - ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0, - "sd_eject", mmc_host); + ret = request_threaded_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, + db1300_mmc_cdfn, 0, "sd_eject", mmc_host); if (ret) { free_irq(DB1300_SD1_INSERT_INT, mmc_host); goto out; diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 944674ee3464..19e17829f515 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -131,22 +131,27 @@ static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data) return IRQ_HANDLED; } +/* Db/Pb1200 have separate per-socket insertion and ejection + * interrupts which stay asserted as long as the card is + * inserted/missing. The one which caused us to be called + * needs to be disabled and the other one enabled. + */ static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data) +{ + disable_irq_nosync(irq); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t db1200_pcmcia_cdirq_fn(int irq, void *data) { struct db1x_pcmcia_sock *sock = data; - /* Db/Pb1200 have separate per-socket insertion and ejection - * interrupts which stay asserted as long as the card is - * inserted/missing. The one which caused us to be called - * needs to be disabled and the other one enabled. - */ - if (irq == sock->insert_irq) { - disable_irq_nosync(sock->insert_irq); + /* Wait a bit for the signals to stop bouncing. */ + msleep(100); + if (irq == sock->insert_irq) enable_irq(sock->eject_irq); - } else { - disable_irq_nosync(sock->eject_irq); + else enable_irq(sock->insert_irq); - } pcmcia_parse_events(&sock->socket, SS_DETECT); @@ -172,13 +177,13 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) */ if ((sock->board_type == BOARD_TYPE_DB1200) || (sock->board_type == BOARD_TYPE_DB1300)) { - ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq, - 0, "pcmcia_insert", sock); + ret = request_threaded_irq(sock->insert_irq, db1200_pcmcia_cdirq, + db1200_pcmcia_cdirq_fn, 0, "pcmcia_insert", sock); if (ret) goto out1; - ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq, - 0, "pcmcia_eject", sock); + ret = request_threaded_irq(sock->eject_irq, db1200_pcmcia_cdirq, + db1200_pcmcia_cdirq_fn, 0, "pcmcia_eject", sock); if (ret) { free_irq(sock->insert_irq, sock); goto out1;