diff options
author | Jan Kundrát <jan.kundrat@cesnet.cz> | 2017-12-12 16:17:59 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-12-19 09:59:01 +0100 |
commit | 78be70c8243ae6bfe8ca642dd19b2b411d4b466f (patch) | |
tree | 3daac4dec73e9712c1cbf0db4807d161a699e148 /drivers/tty/serial/max310x.c | |
parent | serial: max310x: Use level-triggered interrupts (diff) | |
download | linux-78be70c8243ae6bfe8ca642dd19b2b411d4b466f.tar.xz linux-78be70c8243ae6bfe8ca642dd19b2b411d4b466f.zip |
serial: max310x: Support IRQ sharing with other devices
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>
Diffstat (limited to 'drivers/tty/serial/max310x.c')
-rw-r--r-- | drivers/tty/serial/max310x.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 828a2853bd4a..9e4e70f864ea 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -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; |