summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/8250.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/8250.c')
-rw-r--r--drivers/tty/serial/8250.c132
1 files changed, 57 insertions, 75 deletions
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 7f50999..a87a56c 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -309,6 +309,13 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_T_TRIG_01,
.flags = UART_CAP_FIFO | UART_CAP_RTOIE,
},
+ [PORT_XR17D15X] = {
+ .name = "XR17D15X",
+ .fifo_size = 64,
+ .tx_loadsz = 64,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
+ },
};
#if defined(CONFIG_MIPS_ALCHEMY)
@@ -461,42 +468,6 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset);
}
-/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
-static inline void dwapb_save_out_value(struct uart_port *p, int offset,
- int value)
-{
- struct uart_8250_port *up =
- container_of(p, struct uart_8250_port, port);
-
- if (offset == UART_LCR)
- up->lcr = value;
-}
-
-/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
-static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
-{
- if (offset == UART_TX || offset == UART_IER)
- p->serial_in(p, UART_IER);
-}
-
-static void dwapb_serial_out(struct uart_port *p, int offset, int value)
-{
- int save_offset = offset;
- offset = map_8250_out_reg(p, offset) << p->regshift;
- dwapb_save_out_value(p, save_offset, value);
- writeb(value, p->membase + offset);
- dwapb_check_clear_ier(p, save_offset);
-}
-
-static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
-{
- int save_offset = offset;
- offset = map_8250_out_reg(p, offset) << p->regshift;
- dwapb_save_out_value(p, save_offset, value);
- writel(value, p->membase + offset);
- dwapb_check_clear_ier(p, save_offset);
-}
-
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
@@ -509,6 +480,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
outb(value, p->iobase + offset);
}
+static int serial8250_default_handle_irq(struct uart_port *port);
+
static void set_io_from_upio(struct uart_port *p)
{
struct uart_8250_port *up =
@@ -540,16 +513,6 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = tsi_serial_out;
break;
- case UPIO_DWAPB:
- p->serial_in = mem_serial_in;
- p->serial_out = dwapb_serial_out;
- break;
-
- case UPIO_DWAPB32:
- p->serial_in = mem32_serial_in;
- p->serial_out = dwapb32_serial_out;
- break;
-
default:
p->serial_in = io_serial_in;
p->serial_out = io_serial_out;
@@ -557,6 +520,7 @@ static void set_io_from_upio(struct uart_port *p)
}
/* Remember loaded iotype */
up->cur_iotype = p->iotype;
+ p->handle_irq = serial8250_default_handle_irq;
}
static void
@@ -567,8 +531,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
case UPIO_MEM:
case UPIO_MEM32:
case UPIO_AU:
- case UPIO_DWAPB:
- case UPIO_DWAPB32:
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
break;
@@ -1120,6 +1082,14 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_outp(up, UART_IER, iersave);
/*
+ * Exar uarts have EFR in a weird location
+ */
+ if (up->port.flags & UPF_EXAR_EFR) {
+ up->port.type = PORT_XR17D15X;
+ up->capabilities |= UART_CAP_AFE | UART_CAP_EFR;
+ }
+
+ /*
* We distinguish between 16550A and U6 16550A by counting
* how many bytes are in the FIFO.
*/
@@ -1621,6 +1591,29 @@ static void serial8250_handle_port(struct uart_8250_port *up)
spin_unlock_irqrestore(&up->port.lock, flags);
}
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+{
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+
+ if (!(iir & UART_IIR_NO_INT)) {
+ serial8250_handle_port(up);
+ return 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_handle_irq);
+
+static int serial8250_default_handle_irq(struct uart_port *port)
+{
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+ unsigned int iir = serial_in(up, UART_IIR);
+
+ return serial8250_handle_irq(port, iir);
+}
+
/*
* This is the serial driver's interrupt routine.
*
@@ -1648,30 +1641,13 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
l = i->head;
do {
struct uart_8250_port *up;
- unsigned int iir;
+ struct uart_port *port;
up = list_entry(l, struct uart_8250_port, list);
+ port = &up->port;
- iir = serial_in(up, UART_IIR);
- if (!(iir & UART_IIR_NO_INT)) {
- serial8250_handle_port(up);
-
+ if (port->handle_irq(port)) {
handled = 1;
-
- end = NULL;
- } else if ((up->port.iotype == UPIO_DWAPB ||
- up->port.iotype == UPIO_DWAPB32) &&
- (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
- /* The DesignWare APB UART has an Busy Detect (0x07)
- * interrupt meaning an LCR write attempt occurred while the
- * UART was busy. The interrupt must be cleared by reading
- * the UART status register (USR) and the LCR re-written. */
- unsigned int status;
- status = *(volatile u32 *)up->port.private_data;
- serial_out(up, UART_LCR, up->lcr);
-
- handled = 1;
-
end = NULL;
} else if (end == NULL)
end = l;
@@ -2081,8 +2057,8 @@ static int serial8250_startup(struct uart_port *port)
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
(serial_inp(up, UART_LSR) == 0xff)) {
- printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
- serial_index(&up->port));
+ printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+ serial_index(&up->port));
return -ENODEV;
}
@@ -2458,7 +2434,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
efr |= UART_EFR_CTS;
serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_outp(up, UART_EFR, efr);
+ if (up->port.flags & UPF_EXAR_EFR)
+ serial_outp(up, UART_XR_EFR, efr);
+ else
+ serial_outp(up, UART_EFR, efr);
}
#ifdef CONFIG_ARCH_OMAP
@@ -2570,8 +2549,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM:
- case UPIO_DWAPB:
- case UPIO_DWAPB32:
if (!up->port.mapbase)
break;
@@ -2608,8 +2585,6 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM:
- case UPIO_DWAPB:
- case UPIO_DWAPB32:
if (!up->port.mapbase)
break;
@@ -3050,6 +3025,10 @@ int __init early_serial_setup(struct uart_port *port)
p->serial_in = port->serial_in;
if (port->serial_out)
p->serial_out = port->serial_out;
+ if (port->handle_irq)
+ p->handle_irq = port->handle_irq;
+ else
+ p->handle_irq = serial8250_default_handle_irq;
return 0;
}
@@ -3118,6 +3097,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.type = p->type;
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
+ port.handle_irq = p->handle_irq;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
@@ -3283,6 +3263,8 @@ int serial8250_register_port(struct uart_port *port)
uart->port.serial_in = port->serial_in;
if (port->serial_out)
uart->port.serial_out = port->serial_out;
+ if (port->handle_irq)
+ uart->port.handle_irq = port->handle_irq;
/* Possibly override set_termios call */
if (port->set_termios)
uart->port.set_termios = port->set_termios;
OpenPOWER on IntegriCloud