2018-04-12 17:31:09 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* arch/arm/src/imxrt/imxrt_serial.c
|
|
|
|
*
|
2020-12-03 15:11:22 +01:00
|
|
|
* 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
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
2020-12-03 15:11:22 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
2020-12-03 15:11:22 +01:00
|
|
|
* 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.
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
2021-05-18 08:59:14 +02:00
|
|
|
#include <assert.h>
|
2018-04-12 17:31:09 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <debug.h>
|
|
|
|
|
2018-07-26 15:08:17 +02:00
|
|
|
#ifdef CONFIG_SERIAL_TERMIOS
|
|
|
|
# include <termios.h>
|
|
|
|
#endif
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
#include <nuttx/irq.h>
|
|
|
|
#include <nuttx/arch.h>
|
2021-05-14 04:03:23 +02:00
|
|
|
#include <nuttx/spinlock.h>
|
2018-04-12 17:31:09 +02:00
|
|
|
#include <nuttx/init.h>
|
2018-04-17 17:17:44 +02:00
|
|
|
#include <nuttx/power/pm.h>
|
2019-01-27 20:25:58 +01:00
|
|
|
#include <nuttx/fs/ioctl.h>
|
2018-04-12 17:31:09 +02:00
|
|
|
#include <nuttx/serial/serial.h>
|
2018-04-17 17:17:44 +02:00
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
#include <arch/board/board.h>
|
|
|
|
|
|
|
|
#include "chip.h"
|
2020-05-01 03:20:29 +02:00
|
|
|
#include "arm_arch.h"
|
|
|
|
#include "arm_internal.h"
|
2018-04-12 17:31:09 +02:00
|
|
|
|
2019-05-25 02:54:55 +02:00
|
|
|
#include "hardware/imxrt_lpuart.h"
|
2019-01-17 00:44:39 +01:00
|
|
|
#include "imxrt_gpio.h"
|
2019-05-25 02:54:55 +02:00
|
|
|
#include "hardware/imxrt_pinmux.h"
|
2018-04-12 17:31:09 +02:00
|
|
|
#include "imxrt_config.h"
|
|
|
|
#include "imxrt_lowputc.h"
|
|
|
|
|
|
|
|
#ifdef USE_SERIALDRIVER
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Pre-processor Definitions
|
|
|
|
****************************************************************************/
|
|
|
|
|
2018-05-11 15:52:48 +02:00
|
|
|
/* 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.
|
2018-04-12 17:31:09 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* First pick the console and ttys0. This could be any of LPUART1-8 */
|
|
|
|
|
|
|
|
#if defined(CONFIG_LPUART1_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart1port /* LPUART1 is console */
|
|
|
|
# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */
|
|
|
|
# define UART1_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart2port /* LPUART2 is console */
|
|
|
|
# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */
|
|
|
|
# define UART2_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart3port /* LPUART3 is console */
|
|
|
|
# define TTYS0_DEV g_uart3port /* LPUART3 is ttyS0 */
|
|
|
|
# define UART3_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart4port /* LPUART4 is console */
|
|
|
|
# define TTYS0_DEV g_uart4port /* LPUART4 is ttyS0 */
|
|
|
|
# define UART4_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart5port /* LPUART5 is console */
|
2019-01-17 00:33:23 +01:00
|
|
|
# define TTYS0_DEV g_uart5port /* LPUART5 is ttyS0 */
|
2018-05-15 15:49:50 +02:00
|
|
|
# define UART5_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart6port /* LPUART6 is console */
|
2019-01-17 00:33:23 +01:00
|
|
|
# define TTYS0_DEV g_uart6port /* LPUART6 is ttyS0 */
|
2018-05-15 15:49:50 +02:00
|
|
|
# define UART6_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart7port /* LPUART7 is console */
|
2019-01-17 00:33:23 +01:00
|
|
|
# define TTYS0_DEV g_uart7port /* LPUART7 is ttyS0 */
|
2018-05-15 15:49:50 +02:00
|
|
|
# define UART7_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#elif defined(CONFIG_LPUART8_SERIAL_CONSOLE)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define CONSOLE_DEV g_uart8port /* LPUART8 is console */
|
2019-01-17 00:33:23 +01:00
|
|
|
# define TTYS0_DEV g_uart8port /* LPUART8 is ttyS0 */
|
2018-05-15 15:49:50 +02:00
|
|
|
# define UART8_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
#else
|
2018-05-15 15:49:50 +02:00
|
|
|
# undef CONSOLE_DEV /* No console */
|
2018-04-12 17:31:09 +02:00
|
|
|
# if defined(CONFIG_IMXRT_LPUART1)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */
|
|
|
|
# define UART1_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART2)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */
|
|
|
|
# define UART2_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART3)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart3port /* LPUART3 is ttyS0 */
|
|
|
|
# define UART3_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART4)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart4port /* LPUART4 is ttyS0 */
|
|
|
|
# define UART4_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART5)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart5port /* LPUART5 is ttyS0 */
|
|
|
|
# define UART5_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART6)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart6port /* LPUART6 is ttyS0 */
|
|
|
|
# define UART6_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART7)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart7port /* LPUART7 is ttyS0 */
|
|
|
|
# define UART7_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# elif defined(CONFIG_IMXRT_LPUART8)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define TTYS0_DEV g_uart8port /* LPUART8 is ttyS0 */
|
|
|
|
# define UART8_ASSIGNED 1
|
2018-04-12 17:31:09 +02:00
|
|
|
# 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.
|
|
|
|
*/
|
2020-01-29 14:33:19 +01:00
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
#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. */
|
|
|
|
|
2018-04-17 17:17:44 +02:00
|
|
|
/* Power management definitions */
|
|
|
|
|
2018-06-29 00:18:15 +02:00
|
|
|
#if defined(CONFIG_PM) && !defined(CONFIG_IMXRT_PM_SERIAL_ACTIVITY)
|
|
|
|
# define CONFIG_IMXRT_PM_SERIAL_ACTIVITY 10
|
2018-04-17 17:17:44 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_PM)
|
2018-05-15 15:49:50 +02:00
|
|
|
# define PM_IDLE_DOMAIN 0 /* Revisit */
|
2018-04-17 17:17:44 +02:00
|
|
|
#endif
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Private Types
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
struct imxrt_uart_s
|
|
|
|
{
|
2020-10-20 07:41:31 +02:00
|
|
|
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) */
|
2019-05-30 21:44:08 +02:00
|
|
|
#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)
|
2020-10-20 07:41:31 +02:00
|
|
|
uint8_t inviflow:1; /* Invert RTS sense */
|
2019-01-17 00:44:39 +01:00
|
|
|
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
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
const uint32_t tx_gpio; /* TX GPIO pin configuration */
|
|
|
|
#endif
|
2019-01-17 00:44:39 +01:00
|
|
|
|
2020-10-20 07:41:31 +02:00
|
|
|
uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */
|
2019-01-17 00:44:39 +01:00
|
|
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
2020-10-20 07:41:31 +02:00
|
|
|
uint8_t iflow:1; /* input flow control (RTS) enabled */
|
2019-01-17 00:44:39 +01:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_SERIAL_OFLOWCONTROL
|
2020-10-20 07:41:31 +02:00
|
|
|
uint8_t oflow:1; /* output flow control (CTS) enabled */
|
2019-01-17 00:44:39 +01:00
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#ifdef CONFIG_SERIAL_RS485CONTROL
|
2020-10-20 07:41:31 +02:00
|
|
|
uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static inline uint32_t imxrt_serialin(struct imxrt_uart_s *priv,
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t offset);
|
|
|
|
static inline void imxrt_serialout(struct imxrt_uart_s *priv,
|
|
|
|
uint32_t offset, uint32_t value);
|
2018-04-12 17:31:09 +02:00
|
|
|
static inline void imxrt_disableuartint(struct imxrt_uart_s *priv,
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t *ie);
|
2018-04-12 17:31:09 +02:00
|
|
|
static inline void imxrt_restoreuartint(struct imxrt_uart_s *priv,
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t ie);
|
2018-04-12 17:31:09 +02:00
|
|
|
|
|
|
|
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);
|
2020-11-13 07:37:56 +01:00
|
|
|
static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status);
|
2018-04-12 17:31:09 +02:00
|
|
|
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);
|
|
|
|
|
2018-04-17 17:17:44 +02:00
|
|
|
#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
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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 =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART1_BASE,
|
|
|
|
.baud = CONFIG_LPUART1_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART1,
|
|
|
|
.parity = CONFIG_LPUART1_PARITY,
|
|
|
|
.bits = CONFIG_LPUART1_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART1_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART1_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART1_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
|
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart1port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART1_RXBUFSIZE,
|
|
|
|
.buffer = g_uart1rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART1_TXBUFSIZE,
|
|
|
|
.buffer = g_uart1txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart1priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This describes the state of the IMXRT lpuart2 port. */
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART2
|
|
|
|
static struct imxrt_uart_s g_uart2priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART2_BASE,
|
|
|
|
.baud = CONFIG_LPUART2_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART2,
|
|
|
|
.parity = CONFIG_LPUART2_PARITY,
|
|
|
|
.bits = CONFIG_LPUART2_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART2_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART2_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART2_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart2port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART2_RXBUFSIZE,
|
|
|
|
.buffer = g_uart2rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART2_TXBUFSIZE,
|
|
|
|
.buffer = g_uart2txbuffer,
|
2020-01-29 14:33:19 +01:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart2priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART3
|
|
|
|
static struct imxrt_uart_s g_uart3priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART3_BASE,
|
|
|
|
.baud = CONFIG_LPUART3_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART3,
|
|
|
|
.parity = CONFIG_LPUART3_PARITY,
|
|
|
|
.bits = CONFIG_LPUART3_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART3_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART3_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART3_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart3port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART3_RXBUFSIZE,
|
|
|
|
.buffer = g_uart3rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART3_TXBUFSIZE,
|
|
|
|
.buffer = g_uart3txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart3priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART4
|
|
|
|
static struct imxrt_uart_s g_uart4priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART4_BASE,
|
|
|
|
.baud = CONFIG_LPUART4_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART4,
|
|
|
|
.parity = CONFIG_LPUART4_PARITY,
|
|
|
|
.bits = CONFIG_LPUART4_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART4_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART4_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART4_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart4port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART4_RXBUFSIZE,
|
|
|
|
.buffer = g_uart4rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART4_TXBUFSIZE,
|
|
|
|
.buffer = g_uart4txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart4priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART5
|
|
|
|
static struct imxrt_uart_s g_uart5priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART5_BASE,
|
|
|
|
.baud = CONFIG_LPUART5_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART5,
|
|
|
|
.parity = CONFIG_LPUART5_PARITY,
|
|
|
|
.bits = CONFIG_LPUART5_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART5_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART5_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART5_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart5port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART5_RXBUFSIZE,
|
|
|
|
.buffer = g_uart5rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART5_TXBUFSIZE,
|
|
|
|
.buffer = g_uart5txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart5priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART6
|
|
|
|
static struct imxrt_uart_s g_uart6priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART6_BASE,
|
|
|
|
.baud = CONFIG_LPUART6_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART6,
|
|
|
|
.parity = CONFIG_LPUART6_PARITY,
|
|
|
|
.bits = CONFIG_LPUART6_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART6_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART6_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART6_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart6port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART6_RXBUFSIZE,
|
|
|
|
.buffer = g_uart6rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART6_TXBUFSIZE,
|
|
|
|
.buffer = g_uart6txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart6priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART7
|
|
|
|
static struct imxrt_uart_s g_uart7priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART7_BASE,
|
|
|
|
.baud = CONFIG_LPUART7_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART7,
|
|
|
|
.parity = CONFIG_LPUART7_PARITY,
|
|
|
|
.bits = CONFIG_LPUART7_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART7_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART7_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART7_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart7port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART7_RXBUFSIZE,
|
|
|
|
.buffer = g_uart7rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART7_TXBUFSIZE,
|
|
|
|
.buffer = g_uart7txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart7priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMXRT_LPUART8
|
|
|
|
static struct imxrt_uart_s g_uart8priv =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.uartbase = IMXRT_LPUART8_BASE,
|
|
|
|
.baud = CONFIG_LPUART8_BAUD,
|
|
|
|
.irq = IMXRT_IRQ_LPUART8,
|
|
|
|
.parity = CONFIG_LPUART8_PARITY,
|
|
|
|
.bits = CONFIG_LPUART8_BITS,
|
|
|
|
.stopbits2 = CONFIG_LPUART8_2STOP,
|
2019-01-17 00:44:39 +01:00
|
|
|
#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,
|
2019-05-30 21:44:08 +02:00
|
|
|
#endif
|
|
|
|
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) \
|
|
|
|
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL)))
|
2019-01-17 00:44:39 +01:00
|
|
|
.rts_gpio = GPIO_LPUART8_RTS,
|
|
|
|
#endif
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
.tx_gpio = GPIO_LPUART8_TX,
|
|
|
|
#endif
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct uart_dev_s g_uart8port =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.recv =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART8_RXBUFSIZE,
|
|
|
|
.buffer = g_uart8rxbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.xmit =
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.size = CONFIG_LPUART8_TXBUFSIZE,
|
|
|
|
.buffer = g_uart8txbuffer,
|
2018-04-12 17:31:09 +02:00
|
|
|
},
|
2018-05-15 15:49:50 +02:00
|
|
|
.ops = &g_uart_ops,
|
|
|
|
.priv = &g_uart8priv,
|
2018-04-12 17:31:09 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2018-04-17 17:17:44 +02:00
|
|
|
#ifdef CONFIG_PM
|
|
|
|
static struct pm_callback_s g_serial_pmcb =
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
.notify = up_pm_notify,
|
|
|
|
.prepare = up_pm_prepare,
|
2018-04-17 17:17:44 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-10-20 07:41:31 +02:00
|
|
|
static inline void imxrt_serialout(struct imxrt_uart_s *priv,
|
|
|
|
uint32_t offset, uint32_t value)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
|
|
|
putreg32(value, priv->uartbase + offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: imxrt_disableuartint
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static inline void imxrt_disableuartint(struct imxrt_uart_s *priv,
|
|
|
|
uint32_t *ie)
|
|
|
|
{
|
|
|
|
irqstate_t flags;
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t regval;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2018-04-12 17:31:09 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET);
|
|
|
|
|
|
|
|
/* Return the current Rx and Tx interrupt state */
|
|
|
|
|
|
|
|
if (ie != NULL)
|
|
|
|
{
|
|
|
|
*ie = regval & LPUART_ALL_INTS;
|
|
|
|
}
|
|
|
|
|
2018-04-17 15:15:15 +02:00
|
|
|
regval &= ~LPUART_ALL_INTS;
|
2018-04-12 17:31:09 +02:00
|
|
|
imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval);
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: imxrt_restoreuartint
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static inline void imxrt_restoreuartint(struct imxrt_uart_s *priv,
|
|
|
|
uint32_t ie)
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
irqstate_t flags;
|
|
|
|
uint32_t regval;
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/* Enable/disable any interrupts that are currently disabled but should be
|
|
|
|
* enabled/disabled.
|
|
|
|
*/
|
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2018-05-15 15:49:50 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET);
|
|
|
|
regval &= ~LPUART_ALL_INTS;
|
|
|
|
regval |= ie;
|
2018-04-12 17:31:09 +02:00
|
|
|
imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval);
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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
|
2020-01-29 14:33:19 +01:00
|
|
|
int ret;
|
2019-05-30 21:44:08 +02:00
|
|
|
struct uart_config_s config =
|
|
|
|
{
|
|
|
|
0
|
|
|
|
};
|
2018-04-12 17:31:09 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2019-05-30 21:44:08 +02:00
|
|
|
#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
|
2018-04-12 17:31:09 +02:00
|
|
|
|
|
|
|
ret = imxrt_lpuart_configure(priv->uartbase, &config);
|
|
|
|
|
2020-10-20 07:41:31 +02:00
|
|
|
priv->ie = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET) & \
|
|
|
|
LPUART_ALL_INTS;
|
2018-04-12 17:31:09 +02:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
#else
|
2020-10-20 07:41:31 +02:00
|
|
|
priv->ie = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET) & \
|
|
|
|
LPUART_ALL_INTS;
|
2018-04-12 17:31:09 +02:00
|
|
|
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:
|
2018-05-11 15:52:48 +02:00
|
|
|
* 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.
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
2018-05-11 15:52:48 +02:00
|
|
|
* 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.
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
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
|
2018-05-11 15:52:48 +02:00
|
|
|
* closed normally just before the shutdown method is called. The
|
|
|
|
* exception is the serial console which is never shutdown.
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
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:
|
2019-11-04 18:16:46 +01:00
|
|
|
* This is the common UART interrupt handler. It should call
|
2018-04-12 17:31:09 +02:00
|
|
|
* 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;
|
2018-05-11 15:52:48 +02:00
|
|
|
bool handled;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
|
|
|
DEBUGASSERT(dev != NULL && dev->priv != NULL);
|
|
|
|
priv = (struct imxrt_uart_s *)dev->priv;
|
|
|
|
|
2018-06-29 00:18:15 +02:00
|
|
|
#if defined(CONFIG_PM) && CONFIG_IMXRT_PM_SERIAL_ACTIVITY > 0
|
2018-04-17 17:17:44 +02:00
|
|
|
/* Report serial activity to the power management logic */
|
|
|
|
|
2018-06-29 00:18:15 +02:00
|
|
|
pm_activity(PM_IDLE_DOMAIN, CONFIG_IMXRT_PM_SERIAL_ACTIVITY);
|
2018-04-17 17:17:44 +02:00
|
|
|
#endif
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/* Loop until there are no characters to be transferred or,
|
|
|
|
* until we have been looping for a long time.
|
|
|
|
*/
|
|
|
|
|
2018-05-11 15:52:48 +02:00
|
|
|
handled = true;
|
|
|
|
for (passes = 0; passes < 256 && handled; passes++)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-11 15:52:48 +02:00
|
|
|
handled = false;
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/* Get the current UART status and check for loop
|
|
|
|
* termination conditions
|
|
|
|
*/
|
|
|
|
|
2018-05-11 15:52:48 +02:00
|
|
|
usr = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET);
|
2019-11-04 18:16:46 +01:00
|
|
|
usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR |
|
2018-05-11 15:52:48 +02:00
|
|
|
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);
|
|
|
|
}
|
2018-04-12 17:31:09 +02:00
|
|
|
|
2018-05-11 15:52:48 +02:00
|
|
|
if ((usr & LPUART_STAT_FE) != 0)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-05-11 15:52:48 +02:00
|
|
|
imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, LPUART_STAT_FE);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle incoming, receive bytes */
|
|
|
|
|
2018-05-11 15:52:48 +02:00
|
|
|
if ((usr & LPUART_STAT_RDRF) != 0 &&
|
|
|
|
(priv->ie & LPUART_CTRL_RIE) != 0)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
|
|
|
uart_recvchars(dev);
|
2018-05-11 15:52:48 +02:00
|
|
|
handled = true;
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle outgoing, transmit bytes */
|
|
|
|
|
2019-11-04 18:16:46 +01:00
|
|
|
if ((usr & LPUART_STAT_TDRE) != 0 &&
|
|
|
|
(priv->ie & LPUART_CTRL_TIE) != 0)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
|
|
|
uart_xmitchars(dev);
|
2018-05-11 15:52:48 +02:00
|
|
|
handled = true;
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
}
|
2018-05-11 15:52:48 +02:00
|
|
|
|
|
|
|
return OK;
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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)
|
|
|
|
{
|
2019-01-17 00:44:39 +01:00
|
|
|
#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS)
|
2018-04-12 17:31:09 +02:00
|
|
|
struct inode *inode = filep->f_inode;
|
|
|
|
struct uart_dev_s *dev = inode->i_private;
|
2020-01-29 14:33:19 +01:00
|
|
|
irqstate_t flags;
|
2018-04-12 17:31:09 +02:00
|
|
|
#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
|
|
|
|
|
2018-07-26 15:08:17 +02:00
|
|
|
#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 */
|
|
|
|
|
2019-01-17 00:44:39 +01:00
|
|
|
#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);
|
2018-07-26 15:08:17 +02:00
|
|
|
#endif
|
2020-10-19 17:39:49 +02:00
|
|
|
/* Return baud */
|
|
|
|
|
|
|
|
cfsetispeed(termiosp, priv->baud);
|
|
|
|
|
2018-07-26 15:08:17 +02:00
|
|
|
/* 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;
|
|
|
|
|
2020-01-29 14:33:19 +01:00
|
|
|
#if defined(CS9)
|
2018-07-26 15:08:17 +02:00
|
|
|
case 9:
|
2020-01-29 14:33:19 +01:00
|
|
|
termiosp->c_cflag |= CS9;
|
2018-07-26 15:08:17 +02:00
|
|
|
break;
|
2020-01-29 14:33:19 +01:00
|
|
|
#endif
|
2018-07-26 15:08:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2019-01-17 00:44:39 +01:00
|
|
|
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
|
|
|
|
)
|
2018-07-26 15:08:17 +02:00
|
|
|
{
|
|
|
|
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;
|
2020-01-29 14:33:19 +01:00
|
|
|
|
|
|
|
#if defined(CS9)
|
2018-07-26 15:08:17 +02:00
|
|
|
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;
|
2019-01-17 00:44:39 +01:00
|
|
|
#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;
|
2018-07-26 15:08:17 +02:00
|
|
|
#endif
|
|
|
|
/* effect the changes immediately - note that we do not
|
|
|
|
* implement TCSADRAIN / TCSAFLUSH
|
|
|
|
*/
|
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2018-07-26 15:08:17 +02:00
|
|
|
imxrt_disableuartint(priv, &ie);
|
|
|
|
ret = imxrt_setup(dev);
|
|
|
|
|
|
|
|
/* Restore the interrupt state */
|
|
|
|
|
|
|
|
imxrt_restoreuartint(priv, ie);
|
|
|
|
priv->ie = ie;
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2018-07-26 15:08:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_SERIAL_TERMIOS */
|
|
|
|
|
2020-12-03 15:11:22 +01:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_SINGLEWIRE
|
|
|
|
case TIOCSSINGLEWIRE:
|
|
|
|
{
|
|
|
|
uint32_t regval;
|
|
|
|
irqstate_t flags;
|
|
|
|
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv;
|
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2020-12-03 15:11:22 +01:00
|
|
|
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);
|
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2020-12-03 15:11:22 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2019-07-03 22:22:09 +02:00
|
|
|
#ifdef CONFIG_IMXRT_LPUART_INVERT
|
|
|
|
case TIOCSINVERT:
|
|
|
|
{
|
|
|
|
uint32_t ctrl;
|
|
|
|
uint32_t stat;
|
|
|
|
uint32_t regval;
|
|
|
|
irqstate_t flags;
|
2019-07-04 17:15:04 +02:00
|
|
|
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv;
|
2019-07-03 22:22:09 +02:00
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2019-07-03 22:22:09 +02:00
|
|
|
ctrl = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET);
|
|
|
|
stat = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET);
|
|
|
|
regval = ctrl;
|
|
|
|
|
2020-10-20 07:41:31 +02:00
|
|
|
/* {R|T}XINV bit field can only be written when the receiver
|
|
|
|
* is disabled (RE=0).
|
|
|
|
*/
|
2019-07-03 22:22:09 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2019-07-03 22:22:09 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
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'.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-11-13 07:37:56 +01:00
|
|
|
static int imxrt_receive(struct uart_dev_s *dev, unsigned int *status)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
|
|
|
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv;
|
|
|
|
uint32_t rxd;
|
|
|
|
|
2018-05-11 15:52:48 +02:00
|
|
|
rxd = imxrt_serialin(priv, IMXRT_LPUART_DATA_OFFSET);
|
2018-04-12 17:31:09 +02:00
|
|
|
*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;
|
2018-05-15 15:49:50 +02:00
|
|
|
irqstate_t flags;
|
|
|
|
uint32_t regval;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
2018-04-17 15:15:15 +02:00
|
|
|
/* Enable interrupts for data available at Rx */
|
2018-04-12 17:31:09 +02:00
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2018-04-12 17:31:09 +02:00
|
|
|
if (enable)
|
|
|
|
{
|
|
|
|
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
|
2018-05-11 15:52:48 +02:00
|
|
|
priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE;
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-15 15:49:50 +02:00
|
|
|
priv->ie &= ~(LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-15 15:49:50 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET);
|
|
|
|
regval &= ~LPUART_ALL_INTS;
|
|
|
|
regval |= priv->ie;
|
2018-04-12 17:31:09 +02:00
|
|
|
imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval);
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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;
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t regval;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
|
|
|
/* Return true is data is ready in the Rx FIFO */
|
|
|
|
|
2018-05-15 15:49:50 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET);
|
|
|
|
return ((regval & LPUART_STAT_RDRF) != 0);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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;
|
2018-05-15 15:49:50 +02:00
|
|
|
irqstate_t flags;
|
|
|
|
uint32_t regval;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
2018-04-17 15:15:15 +02:00
|
|
|
/* Enable interrupt for TX complete */
|
2018-04-12 17:31:09 +02:00
|
|
|
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
flags = spin_lock_irqsave(NULL);
|
2018-04-12 17:31:09 +02:00
|
|
|
if (enable)
|
|
|
|
{
|
|
|
|
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
|
2019-11-04 18:16:46 +01:00
|
|
|
priv->ie |= LPUART_CTRL_TIE;
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-11-04 18:16:46 +01:00
|
|
|
priv->ie &= ~LPUART_CTRL_TIE;
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-15 15:49:50 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET);
|
|
|
|
regval &= ~LPUART_ALL_INTS;
|
|
|
|
regval |= priv->ie;
|
2018-04-12 17:31:09 +02:00
|
|
|
imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval);
|
arch, boards, drivers, include, sched, wireless: Change spinlock APIs.
Summary:
- This commit changes spinlock APIs (spin_lock_irqsave/spin_unlock_irqrestore)
- In the previous implementation, the global spinlock (i.e. g_irq_spin) was used.
- This commit allows to use caller specific spinlock but also supports to use
g_irq_spin for backword compatibility (In this case, NULL must be specified)
Impact:
- None
Testing:
- Tested with the following configurations
- spresnse:wifi, spresense:wifi_smp
- esp32-devkitc:smp (QEMU), sabre6-quad:smp (QEMU)
- maxi-bit:smp (QEMU), sim:smp
- stm32f4discovery:wifi
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
2021-02-08 01:21:26 +01:00
|
|
|
spin_unlock_irqrestore(NULL, flags);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: imxrt_txready
|
|
|
|
*
|
|
|
|
* Description:
|
rch/arm/src/imxrt/imxrt_serial.c: o, just to complete the documentation of this...it looks like two issues, which confused me greatly;
1) Operational issue
TC (Transmission complete) and TDRE (TX Buffer Empty) were transposed in imxrt_serial.c. The end result was that for unoptimised code everything worked fine, but optimised code got itself into a real mess and continually fired interrupts. The patch attached fixes this. This one would have been found much more quickly if this particular board had supported SWO :-/
2) Startup issue
There are a number of chip errata that apply to the 1052 first revision (A-suffix) that don't apply to the second (B-suffix). Those got me for a while and it's important to use an EVK_B_ dev board if you're suffering stability problems with this particular chip. However, even with that resolved with either optimised or unoptimised code when there is no SNVS (Battery Backup) power and the power is switched on the CPU appears to boot but gets stuck with timer interrupts not being generated. The CPU is running and it will execute linear code. I have determined this by putting an 'imxrt_lowputc('A'+irq)' into up_doirq. For the non-running case the output looks like this;
LLLL
this implies 4 0x0b interrupts have been generated, and nothing else. If I hit keys on the keyboard I get 'e' in the flow. 0x0b is the SVC instruction and is the mechanism by which NuttX handles task switching. 'e' is 0x24, which corresponds to the LPUART1 interrupt. Other than these, the system does not respond further but is happily in the idle loop. In this circumstance if you hit SW2 on the EVKB board though the logjam 'unjams' and normal service is established, output now looks like;
LLLLPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPLPP ...etc.
Where 'P' is 0x0f (the SYSTICK interrupt)....this is what _should_ be happening so; SYSTICK starts up after SW2 has been pressed.
From this point on everything works correctly and you can reboot the CPU, put new code into it or do whatever you wish, **provided power is not cycled off**. If power is cycled off then return to the top and go through the process again.
When there is SNVS power to the CPU then power can be switched on and off as you wish, and the CPU will boot correctly. This has been determined by putting 3V onto J6.
I think we are probably doing something naughty with the way we are starting the clocks to the timers. There are certainly some restrictions on imxrt clock manipulation which we have studiously avoided. I am investigating further and have some potential patches but even if I find the root cause it should not be included in 8.2 as the change could be disruptive.
2019-11-12 16:05:25 +01:00
|
|
|
* Return true if the transmit register is available to be written to
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static bool imxrt_txready(struct uart_dev_s *dev)
|
|
|
|
{
|
|
|
|
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv;
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t regval;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
2018-05-15 15:49:50 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET);
|
rch/arm/src/imxrt/imxrt_serial.c: o, just to complete the documentation of this...it looks like two issues, which confused me greatly;
1) Operational issue
TC (Transmission complete) and TDRE (TX Buffer Empty) were transposed in imxrt_serial.c. The end result was that for unoptimised code everything worked fine, but optimised code got itself into a real mess and continually fired interrupts. The patch attached fixes this. This one would have been found much more quickly if this particular board had supported SWO :-/
2) Startup issue
There are a number of chip errata that apply to the 1052 first revision (A-suffix) that don't apply to the second (B-suffix). Those got me for a while and it's important to use an EVK_B_ dev board if you're suffering stability problems with this particular chip. However, even with that resolved with either optimised or unoptimised code when there is no SNVS (Battery Backup) power and the power is switched on the CPU appears to boot but gets stuck with timer interrupts not being generated. The CPU is running and it will execute linear code. I have determined this by putting an 'imxrt_lowputc('A'+irq)' into up_doirq. For the non-running case the output looks like this;
LLLL
this implies 4 0x0b interrupts have been generated, and nothing else. If I hit keys on the keyboard I get 'e' in the flow. 0x0b is the SVC instruction and is the mechanism by which NuttX handles task switching. 'e' is 0x24, which corresponds to the LPUART1 interrupt. Other than these, the system does not respond further but is happily in the idle loop. In this circumstance if you hit SW2 on the EVKB board though the logjam 'unjams' and normal service is established, output now looks like;
LLLLPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPLPP ...etc.
Where 'P' is 0x0f (the SYSTICK interrupt)....this is what _should_ be happening so; SYSTICK starts up after SW2 has been pressed.
From this point on everything works correctly and you can reboot the CPU, put new code into it or do whatever you wish, **provided power is not cycled off**. If power is cycled off then return to the top and go through the process again.
When there is SNVS power to the CPU then power can be switched on and off as you wish, and the CPU will boot correctly. This has been determined by putting 3V onto J6.
I think we are probably doing something naughty with the way we are starting the clocks to the timers. There are certainly some restrictions on imxrt clock manipulation which we have studiously avoided. I am investigating further and have some potential patches but even if I find the root cause it should not be included in 8.2 as the change could be disruptive.
2019-11-12 16:05:25 +01:00
|
|
|
return ((regval & LPUART_STAT_TDRE) != 0);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: imxrt_txempty
|
|
|
|
*
|
|
|
|
* Description:
|
rch/arm/src/imxrt/imxrt_serial.c: o, just to complete the documentation of this...it looks like two issues, which confused me greatly;
1) Operational issue
TC (Transmission complete) and TDRE (TX Buffer Empty) were transposed in imxrt_serial.c. The end result was that for unoptimised code everything worked fine, but optimised code got itself into a real mess and continually fired interrupts. The patch attached fixes this. This one would have been found much more quickly if this particular board had supported SWO :-/
2) Startup issue
There are a number of chip errata that apply to the 1052 first revision (A-suffix) that don't apply to the second (B-suffix). Those got me for a while and it's important to use an EVK_B_ dev board if you're suffering stability problems with this particular chip. However, even with that resolved with either optimised or unoptimised code when there is no SNVS (Battery Backup) power and the power is switched on the CPU appears to boot but gets stuck with timer interrupts not being generated. The CPU is running and it will execute linear code. I have determined this by putting an 'imxrt_lowputc('A'+irq)' into up_doirq. For the non-running case the output looks like this;
LLLL
this implies 4 0x0b interrupts have been generated, and nothing else. If I hit keys on the keyboard I get 'e' in the flow. 0x0b is the SVC instruction and is the mechanism by which NuttX handles task switching. 'e' is 0x24, which corresponds to the LPUART1 interrupt. Other than these, the system does not respond further but is happily in the idle loop. In this circumstance if you hit SW2 on the EVKB board though the logjam 'unjams' and normal service is established, output now looks like;
LLLLPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPLPP ...etc.
Where 'P' is 0x0f (the SYSTICK interrupt)....this is what _should_ be happening so; SYSTICK starts up after SW2 has been pressed.
From this point on everything works correctly and you can reboot the CPU, put new code into it or do whatever you wish, **provided power is not cycled off**. If power is cycled off then return to the top and go through the process again.
When there is SNVS power to the CPU then power can be switched on and off as you wish, and the CPU will boot correctly. This has been determined by putting 3V onto J6.
I think we are probably doing something naughty with the way we are starting the clocks to the timers. There are certainly some restrictions on imxrt clock manipulation which we have studiously avoided. I am investigating further and have some potential patches but even if I find the root cause it should not be included in 8.2 as the change could be disruptive.
2019-11-12 16:05:25 +01:00
|
|
|
* Return true if the transmission has completed and been sent to line.
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static bool imxrt_txempty(struct uart_dev_s *dev)
|
|
|
|
{
|
|
|
|
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv;
|
2018-05-15 15:49:50 +02:00
|
|
|
uint32_t regval;
|
2018-04-12 17:31:09 +02:00
|
|
|
|
2018-05-15 15:49:50 +02:00
|
|
|
regval = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET);
|
rch/arm/src/imxrt/imxrt_serial.c: o, just to complete the documentation of this...it looks like two issues, which confused me greatly;
1) Operational issue
TC (Transmission complete) and TDRE (TX Buffer Empty) were transposed in imxrt_serial.c. The end result was that for unoptimised code everything worked fine, but optimised code got itself into a real mess and continually fired interrupts. The patch attached fixes this. This one would have been found much more quickly if this particular board had supported SWO :-/
2) Startup issue
There are a number of chip errata that apply to the 1052 first revision (A-suffix) that don't apply to the second (B-suffix). Those got me for a while and it's important to use an EVK_B_ dev board if you're suffering stability problems with this particular chip. However, even with that resolved with either optimised or unoptimised code when there is no SNVS (Battery Backup) power and the power is switched on the CPU appears to boot but gets stuck with timer interrupts not being generated. The CPU is running and it will execute linear code. I have determined this by putting an 'imxrt_lowputc('A'+irq)' into up_doirq. For the non-running case the output looks like this;
LLLL
this implies 4 0x0b interrupts have been generated, and nothing else. If I hit keys on the keyboard I get 'e' in the flow. 0x0b is the SVC instruction and is the mechanism by which NuttX handles task switching. 'e' is 0x24, which corresponds to the LPUART1 interrupt. Other than these, the system does not respond further but is happily in the idle loop. In this circumstance if you hit SW2 on the EVKB board though the logjam 'unjams' and normal service is established, output now looks like;
LLLLPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPLPP ...etc.
Where 'P' is 0x0f (the SYSTICK interrupt)....this is what _should_ be happening so; SYSTICK starts up after SW2 has been pressed.
From this point on everything works correctly and you can reboot the CPU, put new code into it or do whatever you wish, **provided power is not cycled off**. If power is cycled off then return to the top and go through the process again.
When there is SNVS power to the CPU then power can be switched on and off as you wish, and the CPU will boot correctly. This has been determined by putting 3V onto J6.
I think we are probably doing something naughty with the way we are starting the clocks to the timers. There are certainly some restrictions on imxrt clock manipulation which we have studiously avoided. I am investigating further and have some potential patches but even if I find the root cause it should not be included in 8.2 as the change could be disruptive.
2019-11-12 16:05:25 +01:00
|
|
|
return ((regval & LPUART_STAT_TC) != 0);
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 17:17:44 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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:
|
2020-01-29 14:33:19 +01:00
|
|
|
|
2018-04-17 17:17:44 +02:00
|
|
|
/* Should not get here */
|
2019-05-30 21:44:08 +02:00
|
|
|
|
2018-04-17 17:17:44 +02:00
|
|
|
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
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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
|
2020-05-01 16:50:23 +02:00
|
|
|
* before arm_serialinit.
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2019-08-13 22:59:59 +02:00
|
|
|
void imxrt_earlyserialinit(void)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
|
|
|
/* 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
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2020-05-01 16:50:23 +02:00
|
|
|
* Name: arm_serialinit
|
2018-04-12 17:31:09 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Register serial console and serial ports. This assumes
|
|
|
|
* that imxrt_earlyserialinit was called previously.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-05-01 16:50:23 +02:00
|
|
|
void arm_serialinit(void)
|
2018-04-12 17:31:09 +02:00
|
|
|
{
|
2018-04-17 17:17:44 +02:00
|
|
|
#ifdef CONFIG_PM
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Register to receive power management callbacks */
|
|
|
|
|
|
|
|
ret = pm_register(&g_serial_pmcb);
|
|
|
|
DEBUGASSERT(ret == OK);
|
|
|
|
UNUSED(ret);
|
|
|
|
#endif
|
|
|
|
|
2018-04-12 17:31:09 +02:00
|
|
|
#ifdef CONSOLE_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/console", &CONSOLE_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Register all UARTs */
|
|
|
|
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS0", &TTYS0_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#ifdef TTYS1_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS1", &TTYS1_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TTYS2_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS2", &TTYS2_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TTYS3_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS3", &TTYS3_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TTYS4_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS4", &TTYS4_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TTYS5_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS5", &TTYS5_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TTYS6_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS6", &TTYS6_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TTYS7_DEV
|
2020-01-02 17:49:34 +01:00
|
|
|
uart_register("/dev/ttyS7", &TTYS7_DEV);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: up_putc
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Provide priority, low-level access to support OS debug writes
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int up_putc(int ch)
|
|
|
|
{
|
2019-05-01 00:08:46 +02:00
|
|
|
#ifdef CONSOLE_DEV
|
|
|
|
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)CONSOLE_DEV.priv;
|
2018-04-12 17:31:09 +02:00
|
|
|
uint32_t ie;
|
|
|
|
|
|
|
|
imxrt_disableuartint(priv, &ie);
|
|
|
|
|
|
|
|
/* Check for LF */
|
|
|
|
|
|
|
|
if (ch == '\n')
|
|
|
|
{
|
|
|
|
/* Add CR */
|
|
|
|
|
2019-05-01 00:08:46 +02:00
|
|
|
imxrt_lowputc('\r');
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
2019-05-01 00:08:46 +02:00
|
|
|
imxrt_lowputc(ch);
|
|
|
|
imxrt_restoreuartint(priv, ie);
|
2018-04-12 17:31:09 +02:00
|
|
|
#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 */
|
|
|
|
|
2020-05-01 16:50:23 +02:00
|
|
|
arm_lowputc('\r');
|
2018-04-12 17:31:09 +02:00
|
|
|
}
|
|
|
|
|
2020-05-01 16:50:23 +02:00
|
|
|
arm_lowputc(ch);
|
2018-04-12 17:31:09 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* USE_SERIALDRIVER */
|