From 88c6524d7c52dc9850d53ab85caf937933017aa7 Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Tue, 25 May 2021 20:13:34 +0900 Subject: [PATCH] arch: imx6: Add termios support to imx6 Summary: - This commit adds termios support to imx6 Impact: - None Testing: - Tested with QEMU Signed-off-by: Masayuki Ishikawa --- arch/arm/src/imx6/Kconfig | 5 + arch/arm/src/imx6/imx_serial.c | 187 ++++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 3 deletions(-) diff --git a/arch/arm/src/imx6/Kconfig b/arch/arm/src/imx6/Kconfig index b71c49da38..91c78e77d7 100644 --- a/arch/arm/src/imx6/Kconfig +++ b/arch/arm/src/imx6/Kconfig @@ -89,26 +89,31 @@ config IMX6_UART1 bool "UART1" default n select UART1_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS config IMX6_UART2 bool "UART2" default n select UART2_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS config IMX6_UART3 bool "UART3" default n select UART3_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS config IMX6_UART4 bool "UART4" default n select UART4_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS config IMX6_UART5 bool "UART5" default n select UART5_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS config IMX6_SPI1 bool "SPI1" diff --git a/arch/arm/src/imx6/imx_serial.c b/arch/arm/src/imx6/imx_serial.c index 84f2f141f2..b6248ac6a6 100644 --- a/arch/arm/src/imx6/imx_serial.c +++ b/arch/arm/src/imx6/imx_serial.c @@ -32,8 +32,13 @@ #include #include +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + #include #include +#include #include #include #include @@ -187,13 +192,18 @@ struct imx_uart_s { uint32_t uartbase; /* Base address of UART registers */ uint32_t baud; /* Configured baud */ + uint32_t ie; /* Saved enabled interrupts */ uint32_t ucr1; /* Saved UCR1 value */ uint8_t irq; /* IRQ associated with this UART */ uint8_t parity; /* 0=none, 1=odd, 2=even */ uint8_t bits; /* Number of bits (7 or 8) */ uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */ - uint8_t hwfc:1; /* 1: Hardware flow control */ - uint8_t reserved:6; +#ifdef CONFIG_SERIAL_IFLOWCONTROL + uint8_t iflow:1; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + uint8_t oflow:1; /* output flow control (CTS) enabled */ +#endif }; /**************************************************************************** @@ -688,9 +698,10 @@ static int imx_interrupt(int irq, void *context, FAR void *arg) static int imx_ioctl(struct file *filep, int cmd, unsigned long arg) { -#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT +#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) struct inode *inode = filep->f_inode; struct uart_dev_s *dev = inode->i_private; + irqstate_t flags; #endif int ret = OK; @@ -712,6 +723,176 @@ static int imx_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Return parity */ + + termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0); + + /* Return stop bits */ + + termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; + + /* Return flow control */ + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + termiosp->c_cflag |= ((priv->oflow) ? CCTS_OFLOW : 0); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + termiosp->c_cflag |= ((priv->iflow) ? CRTS_IFLOW : 0); +#endif + /* Return baud */ + + cfsetispeed(termiosp, priv->baud); + + /* Return number of bits */ + + switch (priv->bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + + case 6: + termiosp->c_cflag |= CS6; + break; + + case 7: + termiosp->c_cflag |= CS7; + break; + + default: + case 8: + termiosp->c_cflag |= CS8; + break; + +#if defined(CS9) + case 9: + termiosp->c_cflag |= CS9; + break; +#endif + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv; + uint32_t baud; + uint32_t ie; + uint8_t parity; + uint8_t nbits; + bool stop2; + + if ((!termiosp) +#ifdef CONFIG_SERIAL_OFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#endif + ) + { + ret = -EINVAL; + break; + } + + /* Decode baud. */ + + ret = OK; + baud = cfgetispeed(termiosp); + + /* Decode number of bits */ + + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + nbits = 5; + break; + + case CS6: + nbits = 6; + break; + + case CS7: + nbits = 7; + break; + + case CS8: + nbits = 8; + break; + +#if defined(CS9) + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } + + /* Decode parity */ + + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } + + /* Decode stop bits */ + + stop2 = (termiosp->c_cflag & CSTOPB) != 0; + + /* Verify that all settings are valid before committing */ + + if (ret == OK) + { + /* Commit */ + + priv->baud = baud; + priv->parity = parity; + priv->bits = nbits; + priv->stopbits2 = stop2; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + flags = spin_lock_irqsave(NULL); + imx_disableuartint(priv, &ie); + ret = imx_setup(dev); + + /* Restore the interrupt state */ + + imx_restoreuartint(priv, ie); + priv->ie = ie; + spin_unlock_irqrestore(NULL, flags); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ default: