aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorJan Kundrát <jan.kundrat@cesnet.cz>2017-12-12 16:17:59 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-12-19 09:59:01 +0100
commit78be70c8243ae6bfe8ca642dd19b2b411d4b466f (patch)
tree3daac4dec73e9712c1cbf0db4807d161a699e148 /drivers/tty
parentserial: max310x: Use level-triggered interrupts (diff)
downloadlinux-dev-78be70c8243ae6bfe8ca642dd19b2b411d4b466f.tar.xz
linux-dev-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')
-rw-r--r--drivers/tty/serial/max310x.c20
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;