diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2011-06-19 13:17:51 +0000 |
---|---|---|
committer | Gabor Juhos <juhosg@openwrt.org> | 2011-06-19 13:17:51 +0000 |
commit | e6af77a1c8e6d0c1d57867ca7aeffcb17fc3ebc4 (patch) | |
tree | dbdb903efe3747ca632c5c90244fdbd2dd877e10 /target/linux/ar71xx | |
parent | 066e04d497ed757e35eb6b7eff206b5f676168cf (diff) | |
download | mtk-20170518-e6af77a1c8e6d0c1d57867ca7aeffcb17fc3ebc4.zip mtk-20170518-e6af77a1c8e6d0c1d57867ca7aeffcb17fc3ebc4.tar.gz mtk-20170518-e6af77a1c8e6d0c1d57867ca7aeffcb17fc3ebc4.tar.bz2 |
ar71xx: cleanup AR933X UART driver
SVN-Revision: 27222
Diffstat (limited to 'target/linux/ar71xx')
-rw-r--r-- | target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h | 13 | ||||
-rw-r--r-- | target/linux/ar71xx/files/drivers/serial/ar933x_uart.c | 622 |
2 files changed, 152 insertions, 483 deletions
diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h index edb13cd..5273055 100644 --- a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h +++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/ar933x_uart.h @@ -11,6 +11,9 @@ #ifndef __AR933X_UART_H #define __AR933X_UART_H +#define AR933X_UART_REGS_SIZE 20 +#define AR933X_UART_FIFO_SIZE 16 + #define AR933X_UART_DATA_REG 0x00 #define AR933X_UART_CS_REG 0x04 #define AR933X_UART_CLOCK_REG 0x08 @@ -23,9 +26,14 @@ #define AR933X_UART_CS_PARITY_S 0 #define AR933X_UART_CS_PARITY_M 0x3 -#define AR933X_UART_CS_PARITY_M 0x3 +#define AR933X_UART_CS_PARITY_NONE 0 +#define AR933X_UART_CS_PARITY_ODD 1 +#define AR933X_UART_CS_PARITY_EVEN 2 #define AR933X_UART_CS_IF_MODE_S 2 #define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_NONE 0 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 #define AR933X_UART_CS_FLOW_CTRL_S 4 #define AR933X_UART_CS_FLOW_CTRL_M 0x3 #define AR933X_UART_CS_DMA_EN BIT(6) @@ -41,7 +49,8 @@ #define AR933X_UART_CLOCK_STEP_M 0xffff #define AR933X_UART_CLOCK_SCALE_M 0xfff -#define AR933X_UART_CLCOK_SCALE_S 16 +#define AR933X_UART_CLOCK_SCALE_S 16 +#define AR933X_UART_CLOCK_STEP_M 0xffff #define AR933X_UART_INT_RX_VALID BIT(0) #define AR933X_UART_INT_TX_READY BIT(1) diff --git a/target/linux/ar71xx/files/drivers/serial/ar933x_uart.c b/target/linux/ar71xx/files/drivers/serial/ar933x_uart.c index 66925c9..ea12e40 100644 --- a/target/linux/ar71xx/files/drivers/serial/ar933x_uart.c +++ b/target/linux/ar71xx/files/drivers/serial/ar933x_uart.c @@ -1,27 +1,16 @@ /* - * linux/drivers/serial/hornet_serial.c + * Atheros AR933X SoC built-in UART driver * - * Driver for hornet serial ports + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> * * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * - * Copyright (C) 2010 Ryan Hsu. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * $Id$ - * - * A note about mapbase / membase - * - * mapbase is the physical address of the IO port. - * membase is an 'ioremapped' cookie. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. */ #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> @@ -30,77 +19,26 @@ #include <linux/platform_device.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/serial_reg.h> #include <linux/serial_core.h> #include <linux/serial.h> -#include <linux/serial_8250.h> -#include <linux/nmi.h> -#include <linux/mutex.h> #include <linux/slab.h> +#include <linux/io.h> +#include <linux/irq.h> #include <asm/mach-ar71xx/ar933x_uart.h> #include <asm/mach-ar71xx/ar933x_uart_platform.h> -#include <asm/io.h> -#include <asm/irq.h> - -#include "8250.h" -#define ar7240_reg_rmw_clear(_reg, _val) do {} while (0) - #define DRIVER_NAME "ar933x-uart" -#define AR933X_UART_REGS_SIZE 20 -#define AR933X_UART_FIFO_SIZE 16 - -/* - * uncomment below to enable WAR for EV81847. - */ -//#define AR933X_EV81847_WAR +#define AR933X_DUMMY_STATUS_RD 0x01 static struct uart_driver ar933x_uart_driver; -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - -/* - * We default to IRQ0 for the "no irq" hack. Some - * machine types want others as well - they're free - * to redefine this in their header file. - */ -#define is_real_interrupt(irq) ((irq) != 0) - -#include <asm/serial.h> - struct ar933x_uart_port { struct uart_port port; - struct timer_list timer; /* "no irq" timer */ - unsigned char acr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; + unsigned int ier; /* shadow Interrupt Enable Register */ }; -static inline int ar933x_ev81847_war(void) -{ -#if defined(AR933X_EV81847_WAR) - return 1; -#else - return 0; -#endif -} - static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, int offset) { @@ -142,19 +80,23 @@ static inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up, static inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up) { - ar933x_uart_rmw_set(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_TX_EMPTY); + up->ier |= AR933X_UART_INT_TX_EMPTY; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); } static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) { - if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; + up->ier &= ~AR933X_UART_INT_TX_EMPTY; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG,up->ier); +} - /* FIXME: why this uses RXVALIDINTEN? */ - ar933x_uart_rmw_clear(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_RX_VALID); - } +static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) +{ + unsigned int rdata; + + rdata = ch & AR933X_UART_DATA_TX_RX_MASK; + rdata |= AR933X_UART_DATA_TX_CSR; + ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); } static unsigned int ar933x_uart_tx_empty(struct uart_port *port) @@ -197,34 +139,22 @@ static void ar933x_uart_stop_rx(struct uart_port *port) { struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - - ar933x_uart_rmw_clear(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_RX_VALID); + up->ier &= ~AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); } static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) { struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; unsigned long flags; - unsigned long rdata; spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - - rdata = ar933x_uart_read(up, AR933X_UART_CS_REG); - if (up->lcr & UART_LCR_SBC) - rdata |= AR933X_UART_CS_TX_BREAK; + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); else - rdata &= ~AR933X_UART_CS_TX_BREAK; - - ar933x_uart_write(up, AR933X_UART_CS_REG, rdata); - + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -232,395 +162,170 @@ static void ar933x_uart_enable_ms(struct uart_port *port) { } -static inline unsigned int ar933x_uart_get_divisor(struct uart_port *port, - unsigned int baud) -{ - return (port->uartclk / (16 * baud)) - 1; -} - static void ar933x_uart_set_termios(struct uart_port *port, - struct ktermios *termios, + struct ktermios *new, struct ktermios *old) { struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; - unsigned char cval; + unsigned int cs; unsigned long flags; - unsigned int baud, quot; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } + unsigned int baud, scale; - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (termios->c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif + /* Only CS8 is supported */ + new->c_cflag &= ~CSIZE; + new->c_cflag |= CS8; - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - quot = ar933x_uart_get_divisor(port, baud); + /* Only one stop bit is supported */ + new->c_cflag &= ~CSTOPB; -#if 0 - if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { - if (baud < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + cs = 0; + if (new->c_cflag & PARENB) { + if (!(new->c_cflag & PARODD)) + cs |= AR933X_UART_CS_PARITY_EVEN; else - fcr = uart_config[up->port.type].fcr; + cs |= AR933X_UART_CS_PARITY_ODD; + } else { + cs |= AR933X_UART_CS_PARITY_NONE; } - /* - * MCR-based auto flow control. When AFE is enabled, RTS will be - * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. - */ - if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) { - up->mcr &= ~UART_MCR_AFE; - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; - } -#endif + /* Mark/space parity is not supported */ + new->c_cflag &= ~CMSPAR; + + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + scale = (port->uartclk / (16 * baud)) - 1; /* - * Ok, we're now changing the port state. Do it with + * Ok, we're now changing the port state. Do it with * interrupts disabled. */ spin_lock_irqsave(&up->port.lock, flags); - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); + /* Update the per-port timeout. */ + uart_update_timeout(port, new->c_cflag, baud); - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; + /* ignore all characters if CREAD is not set */ + if ((new->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; + ar933x_uart_write(up, AR933X_UART_CLOCK_REG, + scale << AR933X_UART_CLOCK_SCALE_S | 8192); + + /* setup configuration register */ + ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); + /* enable host interrupt */ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, AR933X_UART_CS_HOST_INT_EN); - /* Save LCR */ - up->lcr = cval; - - ar933x_uart_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); + + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); } -static void ar933x_uart_rx_chars(struct ar933x_uart_port *up, int *status) +static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) { struct tty_struct *tty = up->port.state->port.tty; - unsigned int lsr = *status; - unsigned char ch; int max_count = 256; - char flag; do { - ch = lsr & AR933X_UART_DATA_TX_RX_MASK; + unsigned int rdata; + unsigned char ch; - flag = TTY_NORMAL; - up->port.icount.rx++; + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) + break; - lsr = AR933X_UART_DATA_RX_CSR; - ar933x_uart_write(up, AR933X_UART_DATA_REG, lsr); - - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - /* - * For statistics only - */ - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) - up->port.icount.parity++; - else if (lsr & UART_LSR_FE) - up->port.icount.frame++; - if (lsr & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= up->port.read_status_mask; - - if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - flag = TTY_BREAK; - } else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } + /* remove the character from the FIFO */ + ar933x_uart_write(up, AR933X_UART_DATA_REG, + AR933X_UART_DATA_RX_CSR); - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; + up->port.icount.rx++; + ch = rdata & AR933X_UART_DATA_TX_RX_MASK; - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + if (uart_handle_sysrq_char(&up->port, ch)) + continue; -ignore_char: - lsr = ar933x_uart_read(up, AR933X_UART_DATA_REG); - } while ((lsr & AR933X_UART_DATA_RX_CSR) && (max_count-- > 0)); + if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } while (max_count-- > 0); - spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); - - *status = lsr; } static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) { struct circ_buf *xmit = &up->port.state->xmit; int count; - unsigned int rdata; - - rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); - if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) { - ar933x_uart_start_tx_interrupt(up); - return; - } - if (up->port.x_char) { - rdata = up->port.x_char & AR933X_UART_DATA_TX_RX_MASK; - rdata |= AR933X_UART_DATA_TX_CSR; - ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); - up->port.icount.tx++; - up->port.x_char = 0; - ar933x_uart_start_tx_interrupt(up); + if (uart_tx_stopped(&up->port)) return; - } - if (uart_tx_stopped(&up->port)) { - ar933x_uart_stop_tx(&up->port); - return; - } - - if (uart_circ_empty(xmit)) { - ar933x_uart_stop_tx_interrupt(up); - return; - } - - count = up->port.fifosize / 4; + count = up->port.fifosize; do { + unsigned int rdata; + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); - if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) { - ar933x_uart_start_tx_interrupt(up); - return; + if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) + break; + + if (up->port.x_char) { + ar933x_uart_putc(up, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + continue; } - rdata = xmit->buf[xmit->tail] & AR933X_UART_DATA_TX_RX_MASK; - rdata |= AR933X_UART_DATA_TX_CSR; - ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); + if (uart_circ_empty(xmit)) + break; + + ar933x_uart_putc(up, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; } while (--count > 0); - rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); - if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) { - ar933x_uart_start_tx_interrupt(up); - return; - } - - /* Re-enable TX Empty Interrupt to transmit pending chars */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - ar933x_uart_start_tx_interrupt(up); - } - DEBUG_INTR("THRE..."); - - if (uart_circ_empty(xmit)) - ar933x_uart_stop_tx_interrupt(up); - else + if (!uart_circ_empty(xmit)) ar933x_uart_start_tx_interrupt(up); } -/*! Hornet's interrupt status is not read clear, so that we have to... - * a. read out the interrupt status - * b. clear the interrupt mask to reset the interrupt status - * c. enable the interrupt to reactivate interrupt - * - * Disable and clear the interrupt status - */ -static inline void ar933x_uart_clear_int(struct ar933x_uart_port *up) -{ -#define BIT3 (0x1>>3) - - /* 1. clear MISC interrupt mask */ - //ar7240_reg_rmw_clear(AR7240_MISC_INT_MASK, BIT3); - - /* 2. clear uartcs hostinten mask, bit13 */ - ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, - AR933X_UART_CS_HOST_INT_EN); - - /* 3. clear rx uartint */ - ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID); - - /* 4. clear misc interrupt status */ - ar7240_reg_rmw_clear(AR7240_MISC_INT_STATUS, BIT3); - - /* 5. clear rx uartinten*/ - ar933x_uart_rmw_clear(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_RX_VALID); - - /* 6. enable rx int*/ - ar933x_uart_rmw_set(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_RX_VALID); - - /* 7. set uartcs hostinten mask */ - ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, - AR933X_UART_CS_HOST_INT_EN); - - /* 8. set misc int mask */ - //ar7240_reg_wr(AR7240_MISC_INT_MASK, BIT3); -} - -static inline void ar933x_uart_handle_port(struct ar933x_uart_port *up) +static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) { + struct ar933x_uart_port *up = dev_id; unsigned int status; - unsigned int int_status; - unsigned int en_status; - unsigned long flags; - status = ar933x_uart_read(up, AR933X_UART_DATA_REG); - int_status = ar933x_uart_read(up, AR933X_UART_INT_REG); - en_status = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + status = ar933x_uart_read(up, AR933X_UART_CS_REG); + if ((status & AR933X_UART_CS_HOST_INT) == 0) + return IRQ_NONE; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock(&up->port.lock); - if( (int_status & en_status) & AR933X_UART_INT_RX_VALID ) - ar933x_uart_rx_chars(up, &status); + status = ar933x_uart_read(up, AR933X_UART_INT_REG); + status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); - if (((int_status & en_status) & AR933X_UART_INT_TX_EMPTY)) { - /* clear TX empty interrupts */ + if (status & AR933X_UART_INT_RX_VALID) { ar933x_uart_write(up, AR933X_UART_INT_REG, - AR933X_UART_INT_TX_EMPTY); - - /* disable TX empty interrupts */ - ar933x_uart_rmw_clear(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_TX_EMPTY); - - if (!uart_circ_empty(&up->port.state->xmit)) - ar933x_uart_tx_chars(up); + AR933X_UART_INT_RX_VALID); + ar933x_uart_rx_chars(up); } - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) -{ - struct ar933x_uart_port *up; - unsigned int iir; - - up = (struct ar933x_uart_port *) dev_id; - - iir = ar933x_uart_read(up, AR933X_UART_CS_REG); - if ((iir & AR933X_UART_CS_HOST_INT) == 0) - return IRQ_NONE; - - DEBUG_INTR("ar933x_uart_interrupt(%d)...", irq); + if (status & AR933X_UART_INT_TX_EMPTY) { + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_TX_EMPTY); + ar933x_uart_stop_tx_interrupt(up); + ar933x_uart_tx_chars(up); + } - spin_lock(&up->port.lock); - ar933x_uart_handle_port(up); - ar933x_uart_clear_int(up); spin_unlock(&up->port.lock); - DEBUG_INTR("end.\n"); - return IRQ_HANDLED; } -static void ar933x_uart_timer(unsigned long data) -{ - struct uart_port *port = (void *)data; - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; - unsigned int iir; - - if (ar933x_ev81847_war()) { - struct circ_buf *xmit = &up->port.state->xmit; - unsigned long flags; - - if (!uart_circ_empty(xmit)) { - spin_lock_irqsave(&up->port.lock, flags); - ar933x_uart_tx_chars(up); - spin_unlock_irqrestore(&up->port.lock, flags); - } - } else { - iir = ar933x_uart_read(up, AR933X_UART_CS_REG); - if (iir & AR933X_UART_CS_HOST_INT) { - spin_lock(&up->port.lock); - ar933x_uart_handle_port(up); - spin_unlock(&up->port.lock); - } - } - - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); -} - static int ar933x_uart_startup(struct uart_port *port) { struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; @@ -632,39 +337,15 @@ static int ar933x_uart_startup(struct uart_port *port) if (ret) return ret; - up->mcr = 0; - - /* - * Clear the interrupt registers. - */ - ar933x_uart_read(up, AR933X_UART_CS_REG); - ar933x_uart_read(up, AR933X_UART_INT_REG); - - if (!is_real_interrupt(up->port.irq) || ar933x_ev81847_war()) { - setup_timer(&up->timer, ar933x_uart_timer, (unsigned long)port); - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - return 0; - } - spin_lock_irqsave(&up->port.lock, flags); - /* - * Enable host interrupts - */ + /* Enable HOST interrupts */ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, AR933X_UART_CS_HOST_INT_EN); - /* - * Enable RX interrupts - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - ar933x_uart_write(up, AR933X_UART_INT_EN_REG, - AR933X_UART_INT_RX_VALID); - - /* - * And clear the interrupt registers again for luck. - */ - ar933x_uart_read(up, AR933X_UART_INT_REG); + /* Enable RX interrupts */ + up->ier = AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); spin_unlock_irqrestore(&up->port.lock, flags); @@ -674,29 +355,15 @@ static int ar933x_uart_startup(struct uart_port *port) static void ar933x_uart_shutdown(struct uart_port *port) { struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; - unsigned long flags; - /* - * Disable all interrupts from this port - */ + /* Disable all interrupts */ up->ier = 0; - ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - ar933x_uart_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); - /* - * Disable break condition - */ + /* Disable break condition */ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, AR933X_UART_CS_TX_BREAK); - if (!is_real_interrupt(up->port.irq) || - ar933x_ev81847_war()) - del_timer_sync(&up->timer); - free_irq(up->port.irq, up); } @@ -718,20 +385,24 @@ static int ar933x_uart_request_port(struct uart_port *port) static void ar933x_uart_config_port(struct uart_port *port, int flags) { - struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; - - port->type = PORT_AR933X; - - /* Clear mask, so no surprise interrupts. */ - ar933x_uart_read(up, AR933X_UART_CS_REG); - /* Clear interrupts status register */ - ar933x_uart_read(up, AR933X_UART_INT_REG); + if (flags & UART_CONFIG_TYPE) + port->type = PORT_AR933X; } static int ar933x_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { - return -EINVAL; + if (ser->type != PORT_UNKNOWN && + ser->type != PORT_AR933X) + return -EINVAL; + + if (ser->irq < 0 || ser->irq >= NR_IRQS) + return -EINVAL; + + if (ser->baud_base < 28800) + return -EINVAL; + + return 0; } static struct uart_ops ar933x_uart_ops = { @@ -774,13 +445,9 @@ static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) static void ar933x_uart_console_putchar(struct uart_port *port, int ch) { struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; - unsigned int rdata; ar933x_uart_wait_xmitr(up); - - rdata = ch & AR933X_UART_DATA_TX_RX_MASK; - rdata |= AR933X_UART_DATA_TX_CSR; - ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); + ar933x_uart_putc(up, ch); } static void ar933x_uart_console_write(struct console *co, const char *s, @@ -788,22 +455,22 @@ static void ar933x_uart_console_write(struct console *co, const char *s, { struct ar933x_uart_port *up = ar933x_console_ports[co->index]; unsigned long flags; - unsigned int ier; + unsigned int int_en; int locked = 1; local_irq_save(flags); - if (up->port.sysrq) { + if (up->port.sysrq) locked = 0; - } else if (oops_in_progress) { + else if (oops_in_progress) locked = spin_trylock(&up->port.lock); - } else + else spin_lock(&up->port.lock); /* * First save the IER then disable the interrupts */ - ier = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); uart_console_write(&up->port, s, count, ar933x_uart_console_putchar); @@ -813,8 +480,8 @@ static void ar933x_uart_console_write(struct console *co, const char *s, * and restore the IER */ ar933x_uart_wait_xmitr(up); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en); - ar933x_uart_write(up, AR933X_UART_INT_EN_REG, ier); ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); if (locked) @@ -854,13 +521,6 @@ static struct console ar933x_uart_console = { .data = &ar933x_uart_driver, }; -static int __init ar933x_uart_console_init(void) -{ - register_console(&ar933x_uart_console); - return 0; -} -console_initcall(ar933x_uart_console_init); - static void ar933x_uart_add_console_port(struct ar933x_uart_port *up) { ar933x_console_ports[up->port.line] = up; @@ -1015,4 +675,4 @@ module_exit(ar933x_uart_exit); MODULE_DESCRIPTION("Atheros AR933X UART driver"); MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("platform:" DRIVER_NAME); |