serial: max310x: Support IRQ sharing with other devices
authorJan Kundrát <jan.kundrat@cesnet.cz>
Tue, 12 Dec 2017 15:17:59 +0000 (16:17 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 19 Dec 2017 08:59:01 +0000 (09:59 +0100)
According to my chip's datasheet [1], the IRQ output is an open
collector pin which is suitable for sharing with other chips. The chip
also has a register which indicates which UART performed a change and
the driver checks that register already, so we have everything what is
needed to effectively share the IRQ GPIO.

[1] https://datasheets.maximintegrated.com/en/ds/MAX14830.pdf

Signed-off-by: Jan Kundrát <jan.kundrat@cesnet.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/max310x.c

index 828a285..9e4e70f 100644 (file)
@@ -685,9 +685,10 @@ static void max310x_handle_tx(struct uart_port *port)
                uart_write_wakeup(port);
 }
 
-static void max310x_port_irq(struct max310x_port *s, int portno)
+static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
 {
        struct uart_port *port = &s->p[portno].port;
+       irqreturn_t res = IRQ_NONE;
 
        do {
                unsigned int ists, lsr, rxlen;
@@ -698,6 +699,8 @@ static void max310x_port_irq(struct max310x_port *s, int portno)
                if (!ists && !rxlen)
                        break;
 
+               res = IRQ_HANDLED;
+
                if (ists & MAX310X_IRQ_CTS_BIT) {
                        lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
                        uart_handle_cts_change(port,
@@ -711,11 +714,13 @@ static void max310x_port_irq(struct max310x_port *s, int portno)
                        mutex_unlock(&s->mutex);
                }
        } while (1);
+       return res;
 }
 
 static irqreturn_t max310x_ist(int irq, void *dev_id)
 {
        struct max310x_port *s = (struct max310x_port *)dev_id;
+       bool handled = false;
 
        if (s->devtype->nr > 1) {
                do {
@@ -726,12 +731,15 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
                        val = ((1 << s->devtype->nr) - 1) & ~val;
                        if (!val)
                                break;
-                       max310x_port_irq(s, fls(val) - 1);
+                       if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED)
+                               handled = true;
                } while (1);
-       } else
-               max310x_port_irq(s, 0);
+       } else {
+               if (max310x_port_irq(s, 0) == IRQ_HANDLED)
+                       handled = true;
+       }
 
-       return IRQ_HANDLED;
+       return IRQ_RETVAL(handled);
 }
 
 static void max310x_wq_proc(struct work_struct *ws)
@@ -1239,7 +1247,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
 
        /* Setup interrupt */
        ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
-                                       IRQF_ONESHOT, dev_name(dev), s);
+                                       IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), s);
        if (!ret)
                return 0;