From patchwork Thu Aug 25 13:47:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic Desroches X-Patchwork-Id: 9299395 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 39EE660459 for ; Thu, 25 Aug 2016 13:49:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 29F4929334 for ; Thu, 25 Aug 2016 13:49:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1D55D29339; Thu, 25 Aug 2016 13:49:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3DF2729338 for ; Thu, 25 Aug 2016 13:49:31 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bcv0h-0006GG-0D; Thu, 25 Aug 2016 13:47:59 +0000 Received: from exsmtp03.microchip.com ([198.175.253.49] helo=email.microchip.com) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bcv0d-00067l-KI for linux-arm-kernel@lists.infradead.org; Thu, 25 Aug 2016 13:47:56 +0000 Received: from ibiza.corp.atmel.com (10.10.76.4) by chn-sv-exch03.mchp-main.com (10.10.76.49) with Microsoft SMTP Server id 14.3.181.6; Thu, 25 Aug 2016 06:47:30 -0700 From: Ludovic Desroches To: , Subject: [PATCH] tty/serial: atmel: add fractional baud rate support Date: Thu, 25 Aug 2016 15:47:56 +0200 Message-ID: <20160825134756.6261-1-ludovic.desroches@atmel.com> X-Mailer: git-send-email 2.9.0 MIME-Version: 1.0 X-Brightmail-Tracker: H4sIAAAAAAAAC+NgFnrNosTGxcLF5cOi+/nbvnCDnQ8fallMm/6O2eL/69OsFpO+3WC0uPdpG6MDSwBDFGtmXlJ+RQJrxvRLsgXPlSsunp7J2sD4QaaLkYtDSGA1o8SDj/dYuxg5OdgETCUeLehjBrFFBCwlJtw5zgxSxCywjlHi6r1nLCAJYQEXianfr4HZLAKqEh2P5oI18wrYS2w6vIARxJYQkJNoOH+fGSIuKHFy5hOwemYBCYmDL16AxYUENCReT9/K1MXIAVQfKNH7Nxui1Uli6ZUNLBC2ncTh6RfZIWx7ie6l2xlhaj78fgtla0tsf7WPFcLWkdh2sB+q11Ziz4yJTBC2u8SDR8uhbF+JWQ8boGqiJDbse80+gVFsFpJLZyG5dAEj0ypG6eSMPN3iMt3UiuQMA2O93OSMAt3cxMw8veT83E2MkIgw3MG46YHfIUZJDiYlUV7tFfvChfiS8lMqMxKLM+KLSnNSiw8xSnDwKInwugIjTIi3uCAxtzgzHSYlw8GhJMG7+BNQSrAoNT21Ii0zpyS1CCJ9ilFSSpy3CiQpANKXUZoHl7vEKColzOvzCijHU5BalJtZAhG/xSjM8ZBJiCUvPy9VCuhEBiDQYHzFKM7BqARUD3IDT2ZeCdwJr4CuYwK6ruX+bpDrShIRUlINjF3fLqd92Gx9RvE2kyeXUu9VMdGs1XccIp/OUzn+2T8yXdFNdUrug9Jn1nfL7v26u/Oy+IamX+xma1ItdvN6CIo589Qwt0b/utF9bCEHP9fpxLiOTz71/33OXrf/doS3+PWB28umZx+2vrj31pbmqzI22/t3ncjnYlfP//7+PlNvzjdul+hFiUosxRmJhlrMRcWJAPXIUCv+AgAA X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160825_064755_785358_57E6F9A2 X-CRM114-Status: GOOD ( 16.03 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-arm-kernel@lists.infradead.org, Ludovic Desroches , linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, jslaby@suse.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The USART device provides a fractional baud rate generator to get a more accurate baud rate. It can be used only when the USART is configured in 'normal mode' and this feature is not available on AT91RM9200 SoC. Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre --- drivers/tty/serial/atmel_serial.c | 41 +++++++++++++++++++++++++++++++-------- include/linux/atmel_serial.h | 1 + 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2eaa18d..1759239 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; @@ -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; @@ -2025,8 +2033,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 +2045,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 +2163,29 @@ 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)) + */ + if (atmel_port->has_frac_baudrate && + (mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) { + div = DIV_ROUND_CLOSEST(port->uartclk, baud); + cd = div / 16; + fp = DIV_ROUND_CLOSEST(div % 16, 2); + } 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); diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h index 5a4d664..f8e452a 100644 --- a/include/linux/atmel_serial.h +++ b/include/linux/atmel_serial.h @@ -118,6 +118,7 @@ #define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ #define ATMEL_US_CD GENMASK(15, 0) /* Clock Divider */ +#define ATMEL_US_FP_OFFSET 16 /* Fractional Part */ #define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register for USART */ #define ATMEL_UA_RTOR 0x28 /* Receiver Time-out Register for UART */