summaryrefslogtreecommitdiff
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorPradeep Goudagunta <pgoudagunta@nvidia.com>2013-07-31 14:46:44 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:39:00 -0700
commite867b9851e24c841b6964b75b48d0c191719b5cf (patch)
tree61d8f1bd6c3322d06e365f2471371559712c09b7 /drivers/tty/serial
parentacb36c8ff92c8c400afe1f8919a164186807b271 (diff)
tty: serial8250: Add interrupt handler for tegra
Tegra UART IIR sometimes not consistent with its IRQ signal which will generate continous spurious interrupts, inorder to recover from this, generate legal modem interrupt and handle it. So add a seperate interrupt handler for tegra. Bug 1229695 Bug 1339412 Change-Id: I1e8145fea015ece24150d3ef8a640695576b5826 Signed-off-by: Pradeep Goudagunta <pgoudagunta@nvidia.com> Reviewed-on: http://git-master/r/256273 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Alexander Van Brunt <avanbrunt@nvidia.com> Tested-by: Alexander Van Brunt <avanbrunt@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/8250/8250_core.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 5c8ad3e2f145..a1a1a08e4dfc 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -436,6 +436,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
}
static int serial8250_default_handle_irq(struct uart_port *port);
+static int serial8250_tegra_handle_irq(struct uart_port *port);
static int exar_handle_irq(struct uart_port *port);
static void set_io_from_upio(struct uart_port *p)
@@ -1577,6 +1578,68 @@ static int serial8250_default_handle_irq(struct uart_port *port)
}
/*
+ * Tegra UART IIR sometimes not consistent with its IRQ signal
+ * which will generate continous spurious interrupts, inorder to
+ * recover from this, generate legal modem interrupt and
+ * handle it.
+ */
+#define NOINTR_COUNTER 1000
+static int serial8250_tegra_handle_irq(struct uart_port *port)
+{
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+ static int tegra_nointr_count;
+ unsigned int iir = serial_port_in(port, UART_IIR);
+ unsigned char status;
+ unsigned long flags;
+
+ if ((iir & UART_IIR_NO_INT)) {
+ tegra_nointr_count++;
+ if (tegra_nointr_count > NOINTR_COUNTER) {
+ up->mcr = serial_port_in(port, UART_MCR)
+ | UART_MCR_LOOP;
+ serial_port_out(port, UART_MCR, up->mcr);
+ up->ier = serial_port_in(port, UART_IER)
+ | UART_IER_MSI;
+ serial_port_out(port, UART_IER, up->ier);
+ up->mcr |= UART_MCR_RTS;
+ serial_port_out(port, UART_MCR, up->mcr);
+ }
+ return 0;
+ } else {
+ tegra_nointr_count = 0;
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ status = serial_port_in(port, UART_LSR);
+
+ DEBUG_INTR("status = %x...", status);
+
+ if ((iir & 0xf) == UART_IIR_MSI) {
+ if (up->mcr & UART_MCR_LOOP) {
+ serial_port_out(port, UART_TX, 0xff);
+ up->mcr &= ~UART_MCR_LOOP;
+ serial_port_out(port, UART_MCR, up->mcr);
+ up->ier &= ~UART_IER_MSI;
+ serial_port_out(port, UART_IER, up->ier);
+ up->mcr &= ~UART_MCR_RTS;
+ serial_port_out(port, UART_MCR, up->mcr);
+ }
+ serial8250_modem_status(up);
+ }
+
+ if (status & (UART_LSR_DR | UART_LSR_BI))
+ status = serial8250_rx_chars(up, status);
+
+ if (status & UART_LSR_THRE)
+ serial8250_tx_chars(up);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ return 1;
+}
+
+/*
* These Exar UARTs have an extra interrupt indicator that could
* fire for a few unimplemented interrupts. One of which is a
* wakeup event when coming out of sleep. Put this here just
@@ -1646,6 +1709,10 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
} else if (end == NULL)
end = l;
+ /* Tegra NO_INTR should be returned as handled */
+ if (port->type == PORT_TEGRA)
+ handled = 1;
+
l = l->next;
if (l == i->head && pass_counter++ > PASS_LIMIT) {
@@ -2738,8 +2805,10 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
up->bugs |= UART_BUG_NOMSR;
- if (port->type == PORT_TEGRA)
+ if (port->type == PORT_TEGRA) {
up->bugs |= UART_BUG_NOMSR;
+ port->handle_irq = serial8250_tegra_handle_irq;
+ }
if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);