MIPS: Alchemy: Threaded carddetect irqs for devboards
authorManuel Lauss <manuel.lauss@gmail.com>
Tue, 14 Feb 2017 12:03:28 +0000 (13:03 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Tue, 29 Aug 2017 13:21:53 +0000 (15:21 +0200)
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 <manuel.lauss@gmail.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/15287/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/alchemy/devboards/db1200.c
arch/mips/alchemy/devboards/db1300.c
drivers/pcmcia/db1xxx_ss.c

index 992442a03d8ba00d5ab7541b57074ebf3ec0a30d..c1bdd6e8191ea5c3f4ba7d05b36a2679c49fcae0 100644 (file)
@@ -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;
index a5504f57cb00f595e097c545cbd25ba4d89715a4..1468b6af96e2f0d65e29d24acd1d21bfec795876 100644 (file)
@@ -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;
index 944674ee34644fa2583f2193ad738a4b5cbe4912..19e17829f515ac5d317bc3dc124c9353e1e981ed 100644 (file)
@@ -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;