summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/stm32-usart.c
diff options
context:
space:
mode:
authorErwan Le Ray <erwan.leray@st.com>2019-05-21 17:45:41 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-05-24 09:58:28 +0200
commitc8a9d043947b4acb19a65f7fac2bd0893e581cd5 (patch)
treed68ac84946862b6595755cfe306502fd653292e5 /drivers/tty/serial/stm32-usart.c
parent9c12d739d69b80847e99d24692ff20de993bf172 (diff)
serial: stm32: fix word length configuration
STM32 supports either: - 8 and 9 bits word length (including parity bit) for stm32f4 compatible devices - 7, 8 and 9 bits word length (including parity bit) for stm32f7 and stm32h7 compatible devices. As a consequence STM32 supports the following termios configurations: - CS7 with parity bit, and CS8 (with or without parity bit) for stm32f4 compatible devices. - CS6 with parity bit, CS7 and CS8 (with or without parity bit) for stm32f7 and stm32h7 compatible devices. This patch is fixing word length by configuring correctly the SoC with supported configurations. Fixes: ada8618ff3bf ("serial: stm32: adding support for stm32f7") Signed-off-by: Erwan Le Ray <erwan.leray@st.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/stm32-usart.c')
-rw-r--r--drivers/tty/serial/stm32-usart.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index e8d7a7bb4339..e8321850938a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -599,6 +599,36 @@ static void stm32_shutdown(struct uart_port *port)
free_irq(port->irq, port);
}
+unsigned int stm32_get_databits(struct ktermios *termios)
+{
+ unsigned int bits;
+
+ tcflag_t cflag = termios->c_cflag;
+
+ switch (cflag & CSIZE) {
+ /*
+ * CSIZE settings are not necessarily supported in hardware.
+ * CSIZE unsupported configurations are handled here to set word length
+ * to 8 bits word as default configuration and to print debug message.
+ */
+ case CS5:
+ bits = 5;
+ break;
+ case CS6:
+ bits = 6;
+ break;
+ case CS7:
+ bits = 7;
+ break;
+ /* default including CS8 */
+ default:
+ bits = 8;
+ break;
+ }
+
+ return bits;
+}
+
static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
@@ -606,7 +636,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
struct serial_rs485 *rs485conf = &port->rs485;
- unsigned int baud;
+ unsigned int baud, bits;
u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag;
u32 cr1, cr2, cr3;
@@ -632,16 +662,28 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if (cflag & CSTOPB)
cr2 |= USART_CR2_STOP_2B;
+ bits = stm32_get_databits(termios);
+
if (cflag & PARENB) {
+ bits++;
cr1 |= USART_CR1_PCE;
- if ((cflag & CSIZE) == CS8) {
- if (cfg->has_7bits_data)
- cr1 |= USART_CR1_M0;
- else
- cr1 |= USART_CR1_M;
- }
}
+ /*
+ * Word length configuration:
+ * CS8 + parity, 9 bits word aka [M1:M0] = 0b01
+ * CS7 or (CS6 + parity), 7 bits word aka [M1:M0] = 0b10
+ * CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00
+ * M0 and M1 already cleared by cr1 initialization.
+ */
+ if (bits == 9)
+ cr1 |= USART_CR1_M0;
+ else if ((bits == 7) && cfg->has_7bits_data)
+ cr1 |= USART_CR1_M1;
+ else if (bits != 8)
+ dev_dbg(port->dev, "Unsupported data bits config: %u bits\n"
+ , bits);
+
if (cflag & PARODD)
cr1 |= USART_CR1_PS;