From b92edeecee42b509087bdc8760eb3722f5ac174e Mon Sep 17 00:00:00 2001 From: wgzAIIT <820906721@qq.com> Date: Wed, 23 Mar 2022 14:30:05 +0800 Subject: [PATCH] add Ubiquitous/Nuttx/app_match_nuttx/nuttx/arch/arm/src/imxrt/imxrt_serial.c add imxrt_serial.c to app_match_nuttx/nuttx/arch/arm/src/imxrt --- .../nuttx/arch/arm/src/imxrt/imxrt_serial.c | 1833 +++++++++++++++++ 1 file changed, 1833 insertions(+) create mode 100644 Ubiquitous/Nuttx/app_match_nuttx/nuttx/arch/arm/src/imxrt/imxrt_serial.c diff --git a/Ubiquitous/Nuttx/app_match_nuttx/nuttx/arch/arm/src/imxrt/imxrt_serial.c b/Ubiquitous/Nuttx/app_match_nuttx/nuttx/arch/arm/src/imxrt/imxrt_serial.c new file mode 100644 index 000000000..2b9fc124d --- /dev/null +++ b/Ubiquitous/Nuttx/app_match_nuttx/nuttx/arch/arm/src/imxrt/imxrt_serial.c @@ -0,0 +1,1833 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_serial.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "chip.h" +#include "arm_arch.h" +#include "arm_internal.h" + +#include "hardware/imxrt_lpuart.h" +#include "imxrt_gpio.h" +#include "hardware/imxrt_pinmux.h" +#include "imxrt_config.h" +#include "imxrt_lowputc.h" + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Which LPUART with be tty0/console and which tty1-7? The console will + * always be ttyS0. If there is no console then will use the lowest + * numbered UART. + */ + +/* First pick the console and ttys0. This could be any of LPUART1-8 */ + +#if defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* LPUART1 is console */ +# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart2port /* LPUART2 is console */ +# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */ +# define UART2_ASSIGNED 1 +#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart3port /* LPUART3 is console */ +# define TTYS0_DEV g_uart3port /* LPUART3 is ttyS0 */ +# define UART3_ASSIGNED 1 +#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart4port /* LPUART4 is console */ +# define TTYS0_DEV g_uart4port /* LPUART4 is ttyS0 */ +# define UART4_ASSIGNED 1 +#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart5port /* LPUART5 is console */ +# define TTYS0_DEV g_uart5port /* LPUART5 is ttyS0 */ +# define UART5_ASSIGNED 1 +#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart6port /* LPUART6 is console */ +# define TTYS0_DEV g_uart6port /* LPUART6 is ttyS0 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart7port /* LPUART7 is console */ +# define TTYS0_DEV g_uart7port /* LPUART7 is ttyS0 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_LPUART8_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart8port /* LPUART8 is console */ +# define TTYS0_DEV g_uart8port /* LPUART8 is ttyS0 */ +# define UART8_ASSIGNED 1 +#else +# undef CONSOLE_DEV /* No console */ +# if defined(CONFIG_IMXRT_LPUART1) +# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */ +# define UART1_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART2) +# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */ +# define UART2_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART3) +# define TTYS0_DEV g_uart3port /* LPUART3 is ttyS0 */ +# define UART3_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART4) +# define TTYS0_DEV g_uart4port /* LPUART4 is ttyS0 */ +# define UART4_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART5) +# define TTYS0_DEV g_uart5port /* LPUART5 is ttyS0 */ +# define UART5_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART6) +# define TTYS0_DEV g_uart6port /* LPUART6 is ttyS0 */ +# define UART6_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART7) +# define TTYS0_DEV g_uart7port /* LPUART7 is ttyS0 */ +# define UART7_ASSIGNED 1 +# elif defined(CONFIG_IMXRT_LPUART8) +# define TTYS0_DEV g_uart8port /* LPUART8 is ttyS0 */ +# define UART8_ASSIGNED 1 +# endif +#endif + +/* Pick ttys1. This could be any of UART1-8 excluding the console UART. + * One of UART1-8 could be the console; one of UART1-8 has already been + * assigned to ttys0. + */ + +#if defined(CONFIG_IMXRT_LPUART1) && !defined(UART1_ASSIGNED) +# define TTYS1_DEV g_uart1port /* LPUART1 is ttyS1 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART2) && !defined(UART2_ASSIGNED) +# define TTYS1_DEV g_uart2port /* LPUART2 is ttyS1 */ +# define UART2_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART3) && !defined(UART3_ASSIGNED) +# define TTYS1_DEV g_uart3port /* LPUART3 is ttyS1 */ +# define UART3_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) +# define TTYS1_DEV g_uart4port /* LPUART4 is ttyS1 */ +# define UART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) +# define TTYS1_DEV g_uart5port /* LPUART5 is ttyS1 */ +# define UART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) +# define TTYS1_DEV g_uart6port /* LPUART6 is ttyS1 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS1_DEV g_uart7port /* LPUART7 is ttyS1 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS1_DEV g_uart8port /* LPUART8 is ttyS1 */ +# define UART8_ASSIGNED 1 +#endif + +/* Pick ttys2. This could be one of UART2-8. It can't be UART1 because that + * was either assigned as ttyS0 or ttys1. One of UART 1-8 could be the + * console. One of UART2-8 has already been assigned to ttys0 or ttyS1. + */ + +#if defined(CONFIG_IMXRT_LPUART2) && !defined(UART2_ASSIGNED) +# define TTYS2_DEV g_uart2port /* LPUART2 is ttyS2 */ +# define UART2_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART3) && !defined(UART3_ASSIGNED) +# define TTYS2_DEV g_uart3port /* LPUART3 is ttyS2 */ +# define UART3_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) +# define TTYS2_DEV g_uart4port /* LPUART4 is ttyS2 */ +# define UART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) +# define TTYS2_DEV g_uart5port /* LPUART5 is ttyS2 */ +# define UART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) +# define TTYS2_DEV g_uart6port /* LPUART6 is ttyS2 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS2_DEV g_uart7port /* LPUART7 is ttyS2 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS2_DEV g_uart8port /* LPUART8 is ttyS2 */ +# define UART8_ASSIGNED 1 +#endif + +/* Pick ttys3. This could be one of UART3-8. It can't be UART1-2 because + * those have already been assigned to ttsyS0, 1, or 2. One of + * UART3-8 could also be the console. One of UART3-8 has already + * been assigned to ttys0, 1, or 3. + */ + +#if defined(CONFIG_IMXRT_LPUART3) && !defined(UART3_ASSIGNED) +# define TTYS3_DEV g_uart3port /* LPUART3 is ttyS3 */ +# define UART3_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) +# define TTYS3_DEV g_uart4port /* LPUART4 is ttyS3 */ +# define UART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) +# define TTYS3_DEV g_uart5port /* LPUART5 is ttyS3 */ +# define UART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) +# define TTYS3_DEV g_uart6port /* LPUART6 is ttyS3 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS3_DEV g_uart7port /* LPUART7 is ttyS3 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS3_DEV g_uart8port /* LPUART8 is ttyS3 */ +# define UART8_ASSIGNED 1 +#endif + +/* Pick ttys4. This could be one of UART4-8. It can't be UART1-3 because + * those have already been assigned to ttsyS0, 1, 2 or 3. One of + * UART 4-8 could be the console. One of UART4-8 has already been + * assigned to ttys0, 1, 3, or 4. + */ + +#if defined(CONFIG_IMXRT_LPUART4) && !defined(UART4_ASSIGNED) +# define TTYS4_DEV g_uart4port /* LPUART4 is ttyS4 */ +# define UART4_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) +# define TTYS4_DEV g_uart5port /* LPUART5 is ttyS4 */ +# define UART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) +# define TTYS4_DEV g_uart6port /* LPUART6 is ttyS4 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS4_DEV g_uart7port /* LPUART7 is ttyS4 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS4_DEV g_uart8port /* LPUART8 is ttyS4 */ +# define UART8_ASSIGNED 1 +#endif + +/* Pick ttys5. This could be one of UART5-8. It can't be UART1-4 because + * those have already been assigned to ttsyS0, 1, 2, 3 or 4. One of + * UART 5-8 could be the console. One of UART5-8 has already been + * assigned to ttys0, 1, 2, 3, or 4. + */ + +#if defined(CONFIG_IMXRT_LPUART5) && !defined(UART5_ASSIGNED) +# define TTYS5_DEV g_uart5port /* LPUART5 is ttyS5 */ +# define UART5_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) +# define TTYS5_DEV g_uart6port /* LPUART6 is ttyS5 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS5_DEV g_uart7port /* LPUART7 is ttyS5 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS5_DEV g_uart8port /* LPUART8 is ttyS5 */ +# define UART8_ASSIGNED 1 +#endif + +/* Pick ttys6. This could be one of UART6-8. It can't be UART1-5 because + * those have already been assigned to ttsyS0, 1, 2, 3, 4 or 5. One of + * UART 6-8 could be the console. One of UART6-8 has already been + * assigned to ttys0, 1, 2, 3, 4 or 5. + */ + +#if defined(CONFIG_IMXRT_LPUART6) && !defined(UART6_ASSIGNED) +# define TTYS6_DEV g_uart6port /* LPUART6 is ttyS5 */ +# define UART6_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS6_DEV g_uart7port /* LPUART7 is ttyS5 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS6_DEV g_uart8port /* LPUART8 is ttyS5 */ +# define UART8_ASSIGNED 1 +#endif + +/* Pick ttys7. This could be one of UART7-8. It can't be UART1-6 because + * those have already been assigned to ttsyS0, 1, 2, 3, 4, 5 or 6. One of + * UART 7-8 could be the console. One of UART7-8 has already been + * assigned to ttys0, 1, 2, 3, 4, 5 or 6. + */ + +#if defined(CONFIG_IMXRT_LPUART7) && !defined(UART7_ASSIGNED) +# define TTYS7_DEV g_uart7port /* LPUART7 is ttyS5 */ +# define UART7_ASSIGNED 1 +#elif defined(CONFIG_IMXRT_LPUART8) && !defined(UART8_ASSIGNED) +# define TTYS7_DEV g_uart8port /* LPUART8 is ttyS5 */ +# define UART8_ASSIGNED 1 +#endif + +/* UART, if available, should have been assigned to ttyS0-7. */ + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_IMXRT_PM_SERIAL_ACTIVITY) +# define CONFIG_IMXRT_PM_SERIAL_ACTIVITY 10 +#endif + +#if defined(CONFIG_PM) +# define PM_IDLE_DOMAIN 0 /* Revisit */ +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imxrt_uart_s +{ + uint32_t uartbase; /* Base address of UART registers */ + uint32_t baud; /* Configured baud */ + uint32_t ie; /* Saved enabled interrupts */ + 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) */ +#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + uint8_t inviflow:1; /* Invert RTS sense */ + const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */ +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + const uint32_t tx_gpio; /* TX GPIO pin configuration */ +#endif + + uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */ +#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 +#ifdef CONFIG_SERIAL_RS485CONTROL + uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t imxrt_serialin(struct imxrt_uart_s *priv, + uint32_t offset); +static inline void imxrt_serialout(struct imxrt_uart_s *priv, + uint32_t offset, uint32_t value); +static inline void imxrt_disableuartint(struct imxrt_uart_s *priv, + uint32_t *ie); +static inline void imxrt_restoreuartint(struct imxrt_uart_s *priv, + uint32_t ie); + +static int imxrt_setup(struct uart_dev_s *dev); +static void imxrt_shutdown(struct uart_dev_s *dev); +static int imxrt_attach(struct uart_dev_s *dev); +static void imxrt_detach(struct uart_dev_s *dev); +static int imxrt_interrupt(int irq, void *context, FAR void *arg); +static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg); +static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status); +static void imxrt_rxint(struct uart_dev_s *dev, bool enable); +static bool imxrt_rxavailable(struct uart_dev_s *dev); +static void imxrt_send(struct uart_dev_s *dev, int ch); +static void imxrt_txint(struct uart_dev_s *dev, bool enable); +static bool imxrt_txready(struct uart_dev_s *dev); +static bool imxrt_txempty(struct uart_dev_s *dev); + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int dowmin, + enum pm_state_e pmstate); +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Serial driver UART operations */ + +static const struct uart_ops_s g_uart_ops = +{ + .setup = imxrt_setup, + .shutdown = imxrt_shutdown, + .attach = imxrt_attach, + .detach = imxrt_detach, + .ioctl = imxrt_ioctl, + .receive = imxrt_receive, + .rxint = imxrt_rxint, + .rxavailable = imxrt_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = imxrt_send, + .txint = imxrt_txint, + .txready = imxrt_txready, + .txempty = imxrt_txempty, +}; + +/* I/O buffers */ + +#ifdef CONFIG_IMXRT_LPUART1 +static char g_uart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_LPUART1_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART2 +static char g_uart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE]; +static char g_uart2txbuffer[CONFIG_LPUART2_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART3 +static char g_uart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE]; +static char g_uart3txbuffer[CONFIG_LPUART3_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART4 +static char g_uart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE]; +static char g_uart4txbuffer[CONFIG_LPUART4_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART5 +static char g_uart5rxbuffer[CONFIG_LPUART5_RXBUFSIZE]; +static char g_uart5txbuffer[CONFIG_LPUART5_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART6 +static char g_uart6rxbuffer[CONFIG_LPUART6_RXBUFSIZE]; +static char g_uart6txbuffer[CONFIG_LPUART6_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART7 +static char g_uart7rxbuffer[CONFIG_LPUART7_RXBUFSIZE]; +static char g_uart7txbuffer[CONFIG_LPUART7_TXBUFSIZE]; +#endif + +#ifdef CONFIG_IMXRT_LPUART8 +static char g_uart8rxbuffer[CONFIG_LPUART8_RXBUFSIZE]; +static char g_uart8txbuffer[CONFIG_LPUART8_TXBUFSIZE]; +#endif + +/* This describes the state of the IMXRT lpuart1 port. */ + +#ifdef CONFIG_IMXRT_LPUART1 +static struct imxrt_uart_s g_uart1priv = +{ + .uartbase = IMXRT_LPUART1_BASE, + .baud = CONFIG_LPUART1_BAUD, + .irq = IMXRT_IRQ_LPUART1, + .parity = CONFIG_LPUART1_PARITY, + .bits = CONFIG_LPUART1_BITS, + .stopbits2 = CONFIG_LPUART1_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART1_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART1_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART1_TX, +#endif + +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART1_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart1port = +{ + .recv = + { + .size = CONFIG_LPUART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +/* This describes the state of the IMXRT lpuart2 port. */ + +#ifdef CONFIG_IMXRT_LPUART2 +static struct imxrt_uart_s g_uart2priv = +{ + .uartbase = IMXRT_LPUART2_BASE, + .baud = CONFIG_LPUART2_BAUD, + .irq = IMXRT_IRQ_LPUART2, + .parity = CONFIG_LPUART2_PARITY, + .bits = CONFIG_LPUART2_BITS, + .stopbits2 = CONFIG_LPUART2_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART2_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART2_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART2_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART2_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART2_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart2port = +{ + .recv = + { + .size = CONFIG_LPUART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +#ifdef CONFIG_IMXRT_LPUART3 +static struct imxrt_uart_s g_uart3priv = +{ + .uartbase = IMXRT_LPUART3_BASE, + .baud = CONFIG_LPUART3_BAUD, + .irq = IMXRT_IRQ_LPUART3, + .parity = CONFIG_LPUART3_PARITY, + .bits = CONFIG_LPUART3_BITS, + .stopbits2 = CONFIG_LPUART3_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART3_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART3_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART3_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART3_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART3_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart3port = +{ + .recv = + { + .size = CONFIG_LPUART3_RXBUFSIZE, + .buffer = g_uart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART3_TXBUFSIZE, + .buffer = g_uart3txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart3priv, +}; +#endif + +#ifdef CONFIG_IMXRT_LPUART4 +static struct imxrt_uart_s g_uart4priv = +{ + .uartbase = IMXRT_LPUART4_BASE, + .baud = CONFIG_LPUART4_BAUD, + .irq = IMXRT_IRQ_LPUART4, + .parity = CONFIG_LPUART4_PARITY, + .bits = CONFIG_LPUART4_BITS, + .stopbits2 = CONFIG_LPUART4_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART4_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART4_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART4_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART4_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART4_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart4port = +{ + .recv = + { + .size = CONFIG_LPUART4_RXBUFSIZE, + .buffer = g_uart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART4_TXBUFSIZE, + .buffer = g_uart4txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart4priv, +}; +#endif + +#ifdef CONFIG_IMXRT_LPUART5 +static struct imxrt_uart_s g_uart5priv = +{ + .uartbase = IMXRT_LPUART5_BASE, + .baud = CONFIG_LPUART5_BAUD, + .irq = IMXRT_IRQ_LPUART5, + .parity = CONFIG_LPUART5_PARITY, + .bits = CONFIG_LPUART5_BITS, + .stopbits2 = CONFIG_LPUART5_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART5_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART5_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART5_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART5_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART5_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart5port = +{ + .recv = + { + .size = CONFIG_LPUART5_RXBUFSIZE, + .buffer = g_uart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART5_TXBUFSIZE, + .buffer = g_uart5txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart5priv, +}; +#endif + +#ifdef CONFIG_IMXRT_LPUART6 +static struct imxrt_uart_s g_uart6priv = +{ + .uartbase = IMXRT_LPUART6_BASE, + .baud = CONFIG_LPUART6_BAUD, + .irq = IMXRT_IRQ_LPUART6, + .parity = CONFIG_LPUART6_PARITY, + .bits = CONFIG_LPUART6_BITS, + .stopbits2 = CONFIG_LPUART6_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART6_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART6_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART6_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART6_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART6_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart6port = +{ + .recv = + { + .size = CONFIG_LPUART6_RXBUFSIZE, + .buffer = g_uart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART6_TXBUFSIZE, + .buffer = g_uart6txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart6priv, +}; +#endif + +#ifdef CONFIG_IMXRT_LPUART7 +static struct imxrt_uart_s g_uart7priv = +{ + .uartbase = IMXRT_LPUART7_BASE, + .baud = CONFIG_LPUART7_BAUD, + .irq = IMXRT_IRQ_LPUART7, + .parity = CONFIG_LPUART7_PARITY, + .bits = CONFIG_LPUART7_BITS, + .stopbits2 = CONFIG_LPUART7_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART7_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART7_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART7_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART7_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART7_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart7port = +{ + .recv = + { + .size = CONFIG_LPUART7_RXBUFSIZE, + .buffer = g_uart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART7_TXBUFSIZE, + .buffer = g_uart7txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart7priv, +}; +#endif + +#ifdef CONFIG_IMXRT_LPUART8 +static struct imxrt_uart_s g_uart8priv = +{ + .uartbase = IMXRT_LPUART8_BASE, + .baud = CONFIG_LPUART8_BAUD, + .irq = IMXRT_IRQ_LPUART8, + .parity = CONFIG_LPUART8_PARITY, + .bits = CONFIG_LPUART8_BITS, + .stopbits2 = CONFIG_LPUART8_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART8_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART8_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART8_RTS, +#endif +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + .tx_gpio = GPIO_LPUART8_TX, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART8_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart8port = +{ + .recv = + { + .size = CONFIG_LPUART8_RXBUFSIZE, + .buffer = g_uart8rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART8_TXBUFSIZE, + .buffer = g_uart8txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart8priv, +}; +#endif + +#ifdef CONFIG_PM +static struct pm_callback_s g_serial_pmcb = +{ + .notify = up_pm_notify, + .prepare = up_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_serialin + ****************************************************************************/ + +static inline uint32_t imxrt_serialin(struct imxrt_uart_s *priv, + uint32_t offset) +{ + return getreg32(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: imxrt_serialout + ****************************************************************************/ + +static inline void imxrt_serialout(struct imxrt_uart_s *priv, + uint32_t offset, uint32_t value) +{ + putreg32(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: imxrt_disableuartint + ****************************************************************************/ + +static inline void imxrt_disableuartint(struct imxrt_uart_s *priv, + uint32_t *ie) +{ + irqstate_t flags; + uint32_t regval; + + flags = spin_lock_irqsave(NULL); + regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + + /* Return the current Rx and Tx interrupt state */ + + if (ie != NULL) + { + *ie = regval & LPUART_ALL_INTS; + } + + regval &= ~LPUART_ALL_INTS; + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imxrt_restoreuartint + ****************************************************************************/ + +static inline void imxrt_restoreuartint(struct imxrt_uart_s *priv, + uint32_t ie) +{ + irqstate_t flags; + uint32_t regval; + + /* Enable/disable any interrupts that are currently disabled but should be + * enabled/disabled. + */ + + flags = spin_lock_irqsave(NULL); + regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= ie; + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imxrt_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This + * method is called the first time that the serial port is + * opened. + * + ****************************************************************************/ + +static int imxrt_setup(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; +#ifndef CONFIG_SUPPRESS_LPUART_CONFIG + int ret; + struct uart_config_s config = + { + 0 + }; + + /* Configure the UART */ + + config.baud = priv->baud; /* Configured baud */ + config.parity = priv->parity; /* 0=none, 1=odd, 2=even */ + config.bits = priv->bits; /* Number of bits (5-9) */ + config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + config.usects = priv->iflow; /* Flow control on inbound side */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + config.userts = priv->oflow; /* Flow control on outbound side */ +#endif +#ifdef CONFIG_SERIAL_RS485CONTROL + config.users485 = priv->rs485mode; /* Switch into RS485 mode */ +#endif +#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + config.invrts = priv->inviflow; /* Inversion of outbound flow control */ +#endif + + ret = imxrt_lpuart_configure(priv->uartbase, &config); + + priv->ie = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET) & \ + LPUART_ALL_INTS; + return ret; + +#else + priv->ie = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET) & \ + LPUART_ALL_INTS; + return OK; +#endif +} + +/**************************************************************************** + * Name: imxrt_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void imxrt_shutdown(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + + /* Disable the UART */ + + imxrt_serialout(priv, IMXRT_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST); +} + +/**************************************************************************** + * Name: imxrt_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method + * is called when the serial port is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate + * in a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supports multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int imxrt_attach(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, imxrt_interrupt, dev); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the UART + */ + + up_enable_irq(priv->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: imxrt_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void imxrt_detach(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: imxrt_interrupt (and front-ends) + * + * Description: + * This is the common UART interrupt handler. It should call + * uart_transmitchars or uart_receivechar to perform the appropriate data + * transfers. + * + ****************************************************************************/ + +static int imxrt_interrupt(int irq, void *context, FAR void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct imxrt_uart_s *priv; + uint32_t usr; + int passes = 0; + bool handled; + + DEBUGASSERT(dev != NULL && dev->priv != NULL); + priv = (struct imxrt_uart_s *)dev->priv; + +#if defined(CONFIG_PM) && CONFIG_IMXRT_PM_SERIAL_ACTIVITY > 0 + /* Report serial activity to the power management logic */ + + pm_activity(PM_IDLE_DOMAIN, CONFIG_IMXRT_PM_SERIAL_ACTIVITY); +#endif + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + handled = true; + for (passes = 0; passes < 256 && handled; passes++) + { + handled = false; + + /* Get the current UART status and check for loop + * termination conditions + */ + + usr = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR | + LPUART_STAT_FE); + + /* Clear serial overrun and framing errors */ + + if ((usr & LPUART_STAT_OR) != 0) + { + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_OR); + } + + if ((usr & LPUART_STAT_FE) != 0) + { + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_FE); + } + + /* Handle incoming, receive bytes */ + + if ((usr & LPUART_STAT_RDRF) != 0 && + (priv->ie & LPUART_CTRL_RIE) != 0) + { + uart_recvchars(dev); + handled = true; + } + + /* Handle outgoing, transmit bytes */ + + if ((usr & LPUART_STAT_TDRE) != 0 && + (priv->ie & LPUART_CTRL_TIE) != 0) + { + uart_xmitchars(dev); + handled = true; + } + } + + return OK; +} + +/**************************************************************************** + * Name: imxrt_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#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; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct imxrt_uart_s *user = (struct imxrt_uart_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct imxrt_uart_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imxrt_uart_s *priv = (struct imxrt_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 imxrt_uart_s *priv = (struct imxrt_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); + imxrt_disableuartint(priv, &ie); + ret = imxrt_setup(dev); + + /* Restore the interrupt state */ + + imxrt_restoreuartint(priv, ie); + priv->ie = ie; + spin_unlock_irqrestore(NULL, flags); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + +#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE + case TIOCSSINGLEWIRE: + { + uint32_t regval; + irqstate_t flags; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + + flags = spin_lock_irqsave(NULL); + regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + + if ((arg & SER_SINGLEWIRE_ENABLED) != 0) + { + uint32_t gpio_val = IOMUX_OPENDRAIN; + gpio_val |= (arg & SER_SINGLEWIRE_PULL_MASK) == + SER_SINGLEWIRE_PULLUP ? + IOMUX_PULL_UP_47K : IOMUX_PULL_NONE; + gpio_val |= (arg & SER_SINGLEWIRE_PULL_MASK) == + SER_SINGLEWIRE_PULLDOWN ? + IOMUX_PULL_DOWN_100K : IOMUX_PULL_NONE; + imxrt_config_gpio((priv->tx_gpio & + ~(IOMUX_PULL_MASK | IOMUX_OPENDRAIN)) | gpio_val); + regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC; + } + else + { + imxrt_config_gpio((priv->tx_gpio & ~(IOMUX_PULL_MASK | + IOMUX_OPENDRAIN)) | + IOMUX_PULL_NONE); + regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC); + } + + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + + spin_unlock_irqrestore(NULL, flags); + } + break; +#endif + +#ifdef CONFIG_IMXRT_LPUART_INVERT + case TIOCSINVERT: + { + uint32_t ctrl; + uint32_t stat; + uint32_t regval; + irqstate_t flags; + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + + flags = spin_lock_irqsave(NULL); + ctrl = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + stat = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + regval = ctrl; + + /* {R|T}XINV bit field can only be written when the receiver + * is disabled (RE=0). + */ + + regval &= ~LPUART_CTRL_RE; + + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + + /* Enable/disable signal inversion. */ + + if (arg & SER_INVERT_ENABLED_RX) + { + stat |= LPUART_STAT_RXINV; + } + else + { + stat &= ~LPUART_STAT_RXINV; + } + + if (arg & SER_INVERT_ENABLED_TX) + { + ctrl |= LPUART_CTRL_TXINV; + } + else + { + ctrl &= ~LPUART_CTRL_TXINV; + } + + imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, stat); + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, ctrl); + + spin_unlock_irqrestore(NULL, flags); + } + break; +#endif + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: imxrt_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + uint32_t rxd; + + rxd = imxrt_serialin(priv, IMXRT_LPUART_DATA_OFFSET); + *status = rxd >> LPUART_DATA_STATUS_SHIFT; + return (rxd & LPUART_DATA_MASK) >> LPUART_DATA_SHIFT; +} + +/**************************************************************************** + * Name: imxrt_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void imxrt_rxint(struct uart_dev_s *dev, bool enable) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupts for data available at Rx */ + + flags = spin_lock_irqsave(NULL); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE; +#endif + } + else + { + priv->ie &= ~(LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE); + } + + regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imxrt_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +static bool imxrt_rxavailable(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + uint32_t regval; + + /* Return true is data is ready in the Rx FIFO */ + + regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_RDRF) != 0); +} + +/**************************************************************************** + * Name: imxrt_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void imxrt_send(struct uart_dev_s *dev, int ch) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + imxrt_serialout(priv, IMXRT_LPUART_DATA_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: imxrt_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void imxrt_txint(struct uart_dev_s *dev, bool enable) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupt for TX complete */ + + flags = spin_lock_irqsave(NULL); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_TIE; +#endif + } + else + { + priv->ie &= ~LPUART_CTRL_TIE; + } + + regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imxrt_txready + * + * Description: + * Return true if the transmit register is available to be written to + * + ****************************************************************************/ + +static bool imxrt_txready(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + uint32_t regval; + + regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TDRE) != 0); +} + +/**************************************************************************** + * Name: imxrt_txempty + * + * Description: + * Return true if the transmission has completed and been sent to line. + * + ****************************************************************************/ + +static bool imxrt_txempty(struct uart_dev_s *dev) +{ + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv; + uint32_t regval; + + regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TC) != 0); +} + +/**************************************************************************** + * Name: up_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Logic for PM_NORMAL goes here */ + } + break; + + case(PM_IDLE): + { + /* Logic for PM_IDLE goes here */ + } + break; + + case(PM_STANDBY): + { + /* Logic for PM_STANDBY goes here */ + } + break; + + case(PM_SLEEP): + { + /* Logic for PM_SLEEP goes here */ + } + break; + + default: + + /* Should not get here */ + + break; + } +} +#endif + +/**************************************************************************** + * Name: up_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* Logic to prepare for a reduced power state goes here. */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_earlyserialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before arm_serialinit. + * + ****************************************************************************/ + +void imxrt_earlyserialinit(void) +{ + /* NOTE: This function assumes that low level hardware configuration + * -- including all clocking and pin configuration -- was performed by the + * function imxrt_lowsetup() earlier in the boot sequence. + */ + + /* Enable the console UART. The other UARTs will be initialized if and + * when they are first opened. + */ + +#ifdef CONSOLE_DEV + CONSOLE_DEV.isconsole = true; + imxrt_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: arm_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that imxrt_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm_serialinit(void) +{ +#ifdef CONFIG_PM + int ret; + + /* Register to receive power management callbacks */ + + ret = pm_register(&g_serial_pmcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + +#ifdef CONSOLE_DEV + uart_register("/dev/console", &CONSOLE_DEV); +#endif + + /* Register all UARTs */ + + uart_register("/dev/ttyS0", &TTYS0_DEV); +#ifdef TTYS1_DEV + uart_register("/dev/ttyS1", &TTYS1_DEV); +#endif +#ifdef TTYS2_DEV + uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +#ifdef TTYS3_DEV + uart_register("/dev/ttyS3", &TTYS3_DEV); +#endif +#ifdef TTYS4_DEV + uart_register("/dev/ttyS4", &TTYS4_DEV); +#endif +#ifdef TTYS5_DEV + uart_register("/dev/ttyS5", &TTYS5_DEV); +#endif +#ifdef TTYS6_DEV + uart_register("/dev/ttyS6", &TTYS6_DEV); +#endif +#ifdef TTYS7_DEV + uart_register("/dev/ttyS7", &TTYS7_DEV); +#endif +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef CONSOLE_DEV + struct imxrt_uart_s *priv = (struct imxrt_uart_s *)CONSOLE_DEV.priv; + uint32_t ie; + + imxrt_disableuartint(priv, &ie); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + imxrt_lowputc('\r'); + } + + imxrt_lowputc(ch); + imxrt_restoreuartint(priv, ie); +#endif + + return ch; +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#if CONSOLE_LPUART > 0 + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm_lowputc('\r'); + } + + arm_lowputc(ch); +#endif + + return ch; +} + +#endif /* USE_SERIALDRIVER */