From 3efbf10e85c862e7256fc107d5eb4277f8075f04 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 29 Oct 2014 15:47:15 -0600 Subject: Add support for SAM3/4 basic TERMIOS and flow control. There are issues with IFLOW control: PDC or DMAC support is required --- nuttx/arch/arm/src/sam34/Kconfig | 10 +- nuttx/arch/arm/src/sam34/sam_serial.c | 226 ++++++++++++++++++++++++++++++++-- 2 files changed, 224 insertions(+), 12 deletions(-) diff --git a/nuttx/arch/arm/src/sam34/Kconfig b/nuttx/arch/arm/src/sam34/Kconfig index fa4b7bd99..464bec6b7 100644 --- a/nuttx/arch/arm/src/sam34/Kconfig +++ b/nuttx/arch/arm/src/sam34/Kconfig @@ -583,12 +583,14 @@ config SAM34_UART0 default y depends on ARCH_CHIP_SAM3U || ARCH_CHIP_SAM3X || ARCH_CHIP_SAM3A || ARCH_CHIP_SAM4CM || ARCH_CHIP_SAM4S || ARCH_CHIP_SAM4E select ARCH_HAVE_UART0 + select ARCH_HAVE_SERIAL_TERMIOS config SAM34_UART1 bool "UART 1" default n depends on ARCH_CHIP_SAM4CM || ARCH_CHIP_SAM4S || ARCH_CHIP_SAM4E select ARCH_HAVE_UART1 + select ARCH_HAVE_SERIAL_TERMIOS config SAM34_UDP bool "USB Device Full Speed (UDP)" @@ -615,23 +617,27 @@ config SAM34_USART0 bool "USART 0" default n select ARCH_HAVE_USART0 + select ARCH_HAVE_SERIAL_TERMIOS config SAM34_USART1 bool "USART 1" default n select ARCH_HAVE_USART1 + select ARCH_HAVE_SERIAL_TERMIOS config SAM34_USART2 bool "USART 2" default n - select ARCH_HAVE_USART2 depends on ARCH_CHIP_SAM3U || ARCH_CHIP_SAM3X || ARCH_CHIP_SAM3A || ARCH_CHIP_SAM4CM || ARCH_CHIP_SAM4L + select ARCH_HAVE_USART2 + select ARCH_HAVE_SERIAL_TERMIOS config SAM34_USART3 bool "USART 3" default n - select ARCH_HAVE_USART3 depends on ARCH_CHIP_SAM3U || ARCH_CHIP_SAM3X || ARCH_CHIP_SAM3A || ARCH_CHIP_SAM4CM || ARCH_CHIP_SAM4L + select ARCH_HAVE_USART3 + select ARCH_HAVE_SERIAL_TERMIOS config SAM34_WDT bool "Watchdog Timer (WDT)" diff --git a/nuttx/arch/arm/src/sam34/sam_serial.c b/nuttx/arch/arm/src/sam34/sam_serial.c index 6aec44070..b558ae7f9 100644 --- a/nuttx/arch/arm/src/sam34/sam_serial.c +++ b/nuttx/arch/arm/src/sam34/sam_serial.c @@ -48,6 +48,10 @@ #include #include +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + #include #include #include @@ -71,7 +75,7 @@ #endif /**************************************************************************** - * Definitions + * Pre-processor Definitions ****************************************************************************/ /* Some sanity checks *******************************************************/ @@ -106,6 +110,17 @@ # define HAVE_USART #endif +/* Hardware flow control requires using the PDC or DMAC channel for reception */ + +#ifdef CONFIG_SERIAL_IFLOWCONTROL +# warning PDC or DMAC support is required for RTS hardware flow control +# undef CONFIG_SERIAL_IFLOWCONTROL +# undef CONFIG_USART0_IFLOWCONTROL +# undef CONFIG_USART1_IFLOWCONTROL +# undef CONFIG_USART2_IFLOWCONTROL +# undef CONFIG_USART3_IFLOWCONTROL +#endif + /* Is there a serial console? It could be on UART0-1 or USART0-3 */ #if defined(CONFIG_UART0_SERIAL_CONSOLE) && defined(CONFIG_SAM34_UART0) @@ -339,13 +354,16 @@ struct up_dev_s { - uint32_t usartbase; /* Base address of USART registers */ - uint32_t baud; /* Configured baud */ - uint32_t sr; /* Saved status bits */ - uint8_t irq; /* IRQ associated with this USART */ - uint8_t parity; /* 0=none, 1=odd, 2=even */ - uint8_t bits; /* Number of bits (7 or 8) */ - bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + const uint32_t usartbase; /* Base address of USART registers */ + uint32_t baud; /* Configured baud */ + uint32_t sr; /* Saved status bits */ + uint8_t irq; /* IRQ associated with this USART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (5-9) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + bool flowc; /* input flow control (RTS) enabled */ +#endif }; /**************************************************************************** @@ -487,6 +505,9 @@ static struct up_dev_s g_usart0priv = .parity = CONFIG_USART0_PARITY, .bits = CONFIG_USART0_BITS, .stopbits2 = CONFIG_USART0_2STOP, +#if defined(CONFIG_USART0_OFLOWCONTROL) || defined(CONFIG_USART0_IFLOWCONTROL) + .flowc = true, +#endif }; static uart_dev_t g_usart0port = @@ -517,6 +538,9 @@ static struct up_dev_s g_usart1priv = .parity = CONFIG_USART1_PARITY, .bits = CONFIG_USART1_BITS, .stopbits2 = CONFIG_USART1_2STOP, +#if defined(CONFIG_USART1_OFLOWCONTROL) || defined(CONFIG_USART1_IFLOWCONTROL) + .flowc = true, +#endif }; static uart_dev_t g_usart1port = @@ -547,6 +571,9 @@ static struct up_dev_s g_usart2priv = .parity = CONFIG_USART2_PARITY, .bits = CONFIG_USART2_BITS, .stopbits2 = CONFIG_USART2_2STOP, +#if defined(CONFIG_USART2_OFLOWCONTROL) || defined(CONFIG_USART2_IFLOWCONTROL) + .flowc = true, +#endif }; static uart_dev_t g_usart2port = @@ -577,6 +604,9 @@ static struct up_dev_s g_usart3priv = .parity = CONFIG_USART3_PARITY, .bits = CONFIG_USART3_BITS, .stopbits2 = CONFIG_USART3_2STOP, +#if defined(CONFIG_USART3_OFLOWCONTROL) || defined(CONFIG_USART3_IFLOWCONTROL) + .flowc = true, +#endif }; static uart_dev_t g_usart3port = @@ -680,7 +710,28 @@ static int up_setup(struct uart_dev_s *dev) * as the timing source */ - regval = (UART_MR_MODE_NORMAL | SAM_MR_USCLKS); +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + /* "Setting the USART to operate with hardware handshaking is performed by + * writing the USART_MODE field in the Mode Register (US_MR) to the value + * 0x2. ... Using this mode requires using the PDC or DMAC channel for + * reception. The transmitter can handle hardware handshaking in any case." + */ + + if (priv->flowc) + { + /* Enable hardware flow control and MCK as the timing source */ + + regval = (UART_MR_MODE_HWHS | SAM_MR_USCLKS); + } + else +#endif + { + /* Set up the mode register. Start with normal UART mode and the MCK + * as the timing source + */ + + regval = (UART_MR_MODE_NORMAL | SAM_MR_USCLKS); + } /* OR in settings for the selected number of bits */ @@ -760,6 +811,7 @@ static int up_setup(struct uart_dev_s *dev) up_serialout(priv, SAM_UART_CR_OFFSET, (UART_CR_RXEN|UART_CR_TXEN)); #endif + return OK; } @@ -959,7 +1011,7 @@ static int up_interrupt(int irq, void *context) static int up_ioctl(struct file *filep, int cmd, unsigned long arg) { -#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT +#if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_SERIAL_TIOCSERGSTRUCT) struct inode *inode = filep->f_inode; struct uart_dev_s *dev = inode->i_private; #endif @@ -983,6 +1035,160 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) break; #endif +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios*)arg; + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Return baud */ + + cfsetispeed(termiosp, priv->baud); + + /* 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 */ + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + termiosp->c_cflag |= (priv->flowc) ? (CCTS_OFLOW | CRTS_IFLOW): 0; +#endif + /* 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; + + case 9: + termiosp->c_cflag |= CS8 /* CS9 */; + break; + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios*)arg; + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + uint32_t baud; + uint8_t parity; + uint8_t nbits; + bool stop2; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + bool flowc; +#endif + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Decode baud. */ + + ret = OK; + baud = cfgetispeed(termiosp); + + /* Decode number of bits */ + + switch (priv->bits) + { + case CS5: + nbits = 5; + break; + + case CS6: + nbits = 6; + break; + + case CS7: + nbits = 7; + break; + + case CS8: + nbits = 8; + break; +#if 0 + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } + + /* Decode parity */ + + if (termiosp->c_cflag & PARENB) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } + + /* Decode stop bits */ + + stop2 = (termiosp->c_cflag & CSTOPB) != 0; + + /* Decode flow control */ + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + flowc = (termiosp->c_cflag & (CCTS_OFLOW | CRTS_IFLOW)) != 0; +#endif + /* Verify that all settings are valid before committing */ + + if (ret == OK) + { + /* Commit */ + + priv->baud = baud; + priv->parity = parity; + priv->bits = nbits; + priv->stopbits2 = stop2; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + priv->flowc = flowc; +#endif + + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + up_setup(dev); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + default: ret = -ENOTTY; break; -- cgit v1.2.3