diff options
Diffstat (limited to 'drivers/tty/serial/8250.c')
-rw-r--r-- | drivers/tty/serial/8250.c | 132 |
1 files changed, 57 insertions, 75 deletions
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index 7f50999eebc..a87a56cb541 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; |