diff options
Diffstat (limited to 'drivers/tty/serial/atmel_serial.c')
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 58 |
1 files changed, 43 insertions, 15 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2eaa18ddef61..fd8aa1f4ba78 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -166,6 +166,7 @@ struct atmel_uart_port { u32 rts_low; bool ms_irq_enabled; u32 rtor; /* address of receiver timeout register if it exists */ + bool has_frac_baudrate; bool has_hw_timer; struct timer_list uart_timer; @@ -1634,8 +1635,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port, if (np) { /* DMA/PDC usage specification */ - if (of_get_property(np, "atmel,use-dma-rx", NULL)) { - if (of_get_property(np, "dmas", NULL)) { + if (of_property_read_bool(np, "atmel,use-dma-rx")) { + if (of_property_read_bool(np, "dmas")) { atmel_port->use_dma_rx = true; atmel_port->use_pdc_rx = false; } else { @@ -1647,8 +1648,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port, atmel_port->use_pdc_rx = false; } - if (of_get_property(np, "atmel,use-dma-tx", NULL)) { - if (of_get_property(np, "dmas", NULL)) { + if (of_property_read_bool(np, "atmel,use-dma-tx")) { + if (of_property_read_bool(np, "dmas")) { atmel_port->use_dma_tx = true; atmel_port->use_pdc_tx = false; } else { @@ -1745,6 +1746,11 @@ static void atmel_get_ip_name(struct uart_port *port) dbgu_uart = 0x44424755; /* DBGU */ new_uart = 0x55415254; /* UART */ + /* + * Only USART devices from at91sam9260 SOC implement fractional + * baudrate. + */ + atmel_port->has_frac_baudrate = false; atmel_port->has_hw_timer = false; if (name == new_uart) { @@ -1753,6 +1759,7 @@ static void atmel_get_ip_name(struct uart_port *port) atmel_port->rtor = ATMEL_UA_RTOR; } else if (name == usart) { dev_dbg(port->dev, "Usart\n"); + atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; atmel_port->rtor = ATMEL_US_RTOR; } else if (name == dbgu_uart) { @@ -1764,6 +1771,7 @@ static void atmel_get_ip_name(struct uart_port *port) case 0x302: case 0x10213: dev_dbg(port->dev, "This version is usart\n"); + atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; atmel_port->rtor = ATMEL_US_RTOR; break; @@ -1929,6 +1937,9 @@ static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* Disable modem control lines interrupts */ + atmel_disable_ms(port); + /* Disable interrupts at device level */ atmel_uart_writel(port, ATMEL_US_IDR, -1); @@ -1979,8 +1990,6 @@ static void atmel_shutdown(struct uart_port *port) */ free_irq(port->irq, port); - atmel_port->ms_irq_enabled = false; - atmel_flush_buffer(port); } @@ -2025,8 +2034,9 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - unsigned int old_mode, mode, imr, quot, baud; + unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0; /* save the current mode register */ mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); @@ -2036,12 +2046,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, ATMEL_US_PAR | ATMEL_US_USMODE); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - quot = uart_get_divisor(port, baud); - - if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ - quot /= 8; - mode |= ATMEL_US_USCLKS_MCK_DIV8; - } /* byte size */ switch (termios->c_cflag & CSIZE) { @@ -2160,7 +2164,31 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, atmel_uart_writel(port, ATMEL_US_CR, rts_state); } - /* set the baud rate */ + /* + * Set the baud rate: + * Fractional baudrate allows to setup output frequency more + * accurately. This feature is enabled only when using normal mode. + * baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8)) + * Currently, OVER is always set to 0 so we get + * baudrate = selected clock / (16 * (CD + FP / 8)) + * then + * 8 CD + FP = selected clock / (2 * baudrate) + */ + if (atmel_port->has_frac_baudrate && + (mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) { + div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2); + cd = div >> 3; + fp = div & ATMEL_US_FP_MASK; + } else { + cd = uart_get_divisor(port, baud); + } + + if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + cd /= 8; + mode |= ATMEL_US_USCLKS_MCK_DIV8; + } + quot = cd | fp << ATMEL_US_FP_OFFSET; + atmel_uart_writel(port, ATMEL_US_BRGR, quot); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -2292,7 +2320,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) } #endif -static struct uart_ops atmel_pops = { +static const struct uart_ops atmel_pops = { .tx_empty = atmel_tx_empty, .set_mctrl = atmel_set_mctrl, .get_mctrl = atmel_get_mctrl, |