diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h new file mode 100644 index 0000000000..b8ac2e9454 --- /dev/null +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h @@ -0,0 +1,354 @@ +/******************************************************************************************** + * arch/arm/src/s32k1xx/hardware/imxrt_lpuart.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ********************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_LPUART_H +#define __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_LPUART_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include +#include "hardware/s32k1xx_memorymap.h" + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ + +/* Register offsets *************************************************************************/ + +#define S32K1XX_LPUART_VERID_OFFSET 0x0000 /* Version ID Register */ +#define S32K1XX_LPUART_PARAM_OFFSET 0x0004 /* Parameter Register */ +#define S32K1XX_LPUART_GLOBAL_OFFSET 0x0008 /* LPUART Global Register */ +#define S32K1XX_LPUART_PINCFG_OFFSET 0x000c /* LPUART Pin Configuration Register */ +#define S32K1XX_LPUART_BAUD_OFFSET 0x0010 /* LPUART Baud Rate Register */ +#define S32K1XX_LPUART_STAT_OFFSET 0x0014 /* LPUART Status Register */ +#define S32K1XX_LPUART_CTRL_OFFSET 0x0018 /* LPUART Control Register */ +#define S32K1XX_LPUART_DATA_OFFSET 0x001c /* LPUART Data Register */ +#define S32K1XX_LPUART_MATCH_OFFSET 0x0020 /* LPUART Match Address Register */ +#define S32K1XX_LPUART_MODIR_OFFSET 0x0024 /* LPUART Modem IrDA Register */ +#define S32K1XX_LPUART_FIFO_OFFSET 0x0028 /* LPUART FIFO Register */ +#define S32K1XX_LPUART_WATER_OFFSET 0x002c /* LPUART Watermark Register */ + +/* Register addresses ***********************************************************************/ + +#define S32K1XX_LPUART0_VERID (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_VERID_OFFSET) +#define S32K1XX_LPUART0_PARAM (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_PARAM_OFFSET) +#define S32K1XX_LPUART0_GLOBAL (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_GLOBAL_OFFSET) +#define S32K1XX_LPUART0_PINCFG (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_PINCFG_OFFSET) +#define S32K1XX_LPUART0_BAUD (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_BAUD_OFFSET) +#define S32K1XX_LPUART0_STAT (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_STAT_OFFSET) +#define S32K1XX_LPUART0_CTRL (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_CTRL_OFFSET) +#define S32K1XX_LPUART0_DATA (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_DATA_OFFSET) +#define S32K1XX_LPUART0_MATCH (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_MATCH_OFFSET) +#define S32K1XX_LPUART0_MODIR (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_MODIR_OFFSET) +#define S32K1XX_LPUART0_FIFO (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_FIFO_OFFSET) +#define S32K1XX_LPUART0_WATER (S32K1XX_LPUART0_BASE + S32K1XX_LPUART_WATER_OFFSET) + +#define S32K1XX_LPUART1_VERID (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_VERID_OFFSET) +#define S32K1XX_LPUART1_PARAM (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_PARAM_OFFSET) +#define S32K1XX_LPUART1_GLOBAL (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_GLOBAL_OFFSET) +#define S32K1XX_LPUART1_PINCFG (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_PINCFG_OFFSET) +#define S32K1XX_LPUART1_BAUD (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_BAUD_OFFSET) +#define S32K1XX_LPUART1_STAT (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_STAT_OFFSET) +#define S32K1XX_LPUART1_CTRL (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_CTRL_OFFSET) +#define S32K1XX_LPUART1_DATA (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_DATA_OFFSET) +#define S32K1XX_LPUART1_MATCH (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_MATCH_OFFSET) +#define S32K1XX_LPUART1_MODIR (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_MODIR_OFFSET) +#define S32K1XX_LPUART1_FIFO (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_FIFO_OFFSET) +#define S32K1XX_LPUART1_WATER (S32K1XX_LPUART1_BASE + S32K1XX_LPUART_WATER_OFFSET) + +#define S32K1XX_LPUART2_VERID (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_VERID_OFFSET) +#define S32K1XX_LPUART2_PARAM (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_PARAM_OFFSET) +#define S32K1XX_LPUART2_GLOBAL (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_GLOBAL_OFFSET) +#define S32K1XX_LPUART2_PINCFG (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_PINCFG_OFFSET) +#define S32K1XX_LPUART2_BAUD (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_BAUD_OFFSET) +#define S32K1XX_LPUART2_STAT (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_STAT_OFFSET) +#define S32K1XX_LPUART2_CTRL (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_CTRL_OFFSET) +#define S32K1XX_LPUART2_DATA (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_DATA_OFFSET) +#define S32K1XX_LPUART2_MATCH (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_MATCH_OFFSET) +#define S32K1XX_LPUART2_MODIR (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_MODIR_OFFSET) +#define S32K1XX_LPUART2_FIFO (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_FIFO_OFFSET) +#define S32K1XX_LPUART2_WATER (S32K1XX_LPUART2_BASE + S32K1XX_LPUART_WATER_OFFSET) + +/* Register bit definitions *****************************************************************/ + +/* Version ID Register */ + +#define LPUART_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number */ +#define LPUART_VERID_FEATURE_MASK (0xffff << LPUART_VERID_FEATURE_SHIFT) +# define LPUART_VERID_FEATURE_STD (1 << LPUART_VERID_FEATURE_SHIFT) /* Standard feature set */ +# define LPUART_VERID_FEATURE_MODEM (3 << LPUART_VERID_FEATURE_SHIFT) /* MODEM/IrDA support */ +#define LPUART_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number */ +#define LPUART_VERID_MINOR_MASK (0xff << LPUART_VERID_MINOR_SHIFT) +#define LPUART_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number */ +#define LPUART_VERID_MAJOR_MASK (0xff << LPUART_VERID_MAJOR_SHIFT) + +/* Parameter Register */ + +#define LPUART_PARAM_TXFIFO_SHIFT (0) /* Bits 0-7: Transmit FIFO Size */ +#define LPUART_PARAM_TXFIFO_MASK (0xff << LPUART_PARAM_TXFIFO_SHIFT) +#define LPUART_PARAM_RXFIFO_SHIFT (8) /* Bits 8-15: Transmit FIFO Size */ +#define LPUART_PARAM_RXFIFO_MASK (0xff << LPUART_PARAM_RXFIFO_SHIFT) + /* Bits 16-31: Reserved */ + +/* LPUART Global Register */ + + /* Bit 0: Reserved */ +#define LPUART_GLOBAL_RST (1 << 1) /* Bit 1: Software Reset */ + /* Bits 2-31: Reserved */ + +/* LPUART Pin Configuration Register */ + +#define LPUART_PINCFG_TRGSEL_SHIFT (0) /* Bits 0-1: Trigger Select */ +#define LPUART_PINCFG_TRGSEL_MASK (3 << LPUART_PINCFG_TRGSEL_SHIFT) +# define LPUART_PINCFG_TRGSEL_DISABLE (0 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger disabled */ +# define LPUART_PINCFG_TRGSEL_RXD (1 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of RXD pin */ +# define LPUART_PINCFG_TRGSEL_CTSB (2 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of CTS_B pin */ +# define LPUART_PINCFG_TRGSEL_TXDMOD (3 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used to modulate the TXD output */ + /* Bits 2-31: Reserved */ + +/* LPUART Baud Rate Register */ + +#define LPUART_BAUD_SBR_SHIFT (0) /* Bits 0-12: Baud Rate Modulo Divisor. */ +#define LPUART_BAUD_SBR_MASK (0x1fff << LPUART_BAUD_SBR_SHIFT) +# define LPUART_BAUD_SBR(n) ((uint32_t)(n) << LPUART_BAUD_SBR_SHIFT) +#define LPUART_BAUD_SBNS (1 << 13) /* Bit 13: Stop Bit Number Select */ +#define LPUART_BAUD_RXEDGIE (1 << 14) /* Bit 14: RX Input Active Edge Interrupt Enable */ +#define LPUART_BAUD_LBKDIE (1 << 15) /* Bit 15: LIN Break Detect Interrupt Enable */ +#define LPUART_BAUD_RESYNCDIS (1 << 16) /* Bit 16: Resynchronization Disable */ +#define LPUART_BAUD_BOTHEDGE (1 << 17) /* Bit 17: Both Edge Sampling */ +#define LPUART_BAUD_MATCFG_SHIFT (18) /* Bits 18-19: Match Configuration */ +#define LPUART_BAUD_MATCFG_MASK (3 << LPUART_BAUD_MATCFG_SHIFT) +# define LPUART_BAUD_MATCFG_ADDR (0 << LPUART_BAUD_MATCFG_SHIFT) /* Address Match Wakeup */ +# define LPUART_BAUD_MATCFG_IDLE (1 << LPUART_BAUD_MATCFG_SHIFT) /* Idle Match Wakeup */ +# define LPUART_BAUD_MATCFG_ONOFF (2 << LPUART_BAUD_MATCFG_SHIFT) /* Match On and Match Off */ +# define LPUART_BAUD_MATCFG_RWUENAB (3 << LPUART_BAUD_MATCFG_SHIFT) /* Enables RWU on Data Match and Match + * On/Off for transmitter CTS input */ + /* Bit 20: Reserved */ +#define LPUART_BAUD_RDMAE (1 << 21) /* Bit 21: Receiver Full DMA Enable */ + /* Bit 22: Reserved */ +#define LPUART_BAUD_TDMAE (1 << 23) /* Bit 23: Transmitter DMA Enable */ +#define LPUART_BAUD_OSR_SHIFT (24) /* Bits 24-28: Oversampling Ratio */ +#define LPUART_BAUD_OSR_MASK (15 << LPUART_BAUD_OSR_SHIFT) +# define LPUART_BAUD_OSR(n) ((uint32_t)((n) - 1) << LPUART_BAUD_OSR_SHIFT) /* n=4..32 */ +#define LPUART_BAUD_M10 (1 << 29) /* Bit 20: 10-bit Mode select */ +#define LPUART_BAUD_MAEN2 (1 << 30) /* Bit 30: Match Address Mode Enable 2 */ +#define LPUART_BAUD_MAEN1 (1 << 31) /* Bit 31: Match Address Mode Enable 1 */ + +/* LPUART Status Register */ + + /* Bits 0-13: Reserved */ +#define LPUART_STAT_MA2F (1 << 14) /* Bit 14: Match 2 Flag */ +#define LPUART_STAT_MA1F (1 << 15) /* Bit 15: Match 1 Flag */ +#define LPUART_STAT_PF (1 << 16) /* Bit 16: Parity Error Flag */ +#define LPUART_STAT_FE (1 << 17) /* Bit 17: Framing Error Flag */ +#define LPUART_STAT_NF (1 << 18) /* Bit 18: Noise Flag */ +#define LPUART_STAT_OR (1 << 19) /* Bit 19: Receiver Overrun Flag */ +#define LPUART_STAT_IDLE (1 << 20) /* Bit 20: Idle Line Flag */ +#define LPUART_STAT_RDRF (1 << 21) /* Bit 21: Receive Data Register Full Flag */ +#define LPUART_STAT_TC (1 << 22) /* Bit 22: Transmission Complete Flag */ +#define LPUART_STAT_TDRE (1 << 23) /* Bit 23: Transmit Data Register Empty Flag */ +#define LPUART_STAT_RAF (1 << 24) /* Bit 24: Receiver Active Flag */ +#define LPUART_STAT_LBKDE (1 << 25) /* Bit 25: LIN Break Detection Enable */ +#define LPUART_STAT_BRK13 (1 << 26) /* Bit 26: Break Character Generation Length */ +#define LPUART_STAT_RWUID (1 << 27) /* Bit 27: Receive Wake Up Idle Detect */ +#define LPUART_STAT_RXINV (1 << 28) /* Bit 28: Receive Data Inversion */ +#define LPUART_STAT_MSBF (1 << 29) /* Bit 29: MSB First */ +#define LPUART_STAT_RXEDGIF (1 << 30) /* Bit 30: RXD Pin Active Edge Interrupt Flag */ +#define LPUART_STAT_LBKDIF (1 << 31) /* Bit 31: LIN Break Detect Interrupt Flag */ + +/* LPUART Control Register */ + +#define LPUART_CTRL_PT (1 << 0) /* Bit 0: Parity Type */ +# define LPUART_CTRL_PT_EVEN (0 << 0) /* Even parity */ +# define LPUART_CTRL_PT_ODD (1 << 0) /* Odd parity */ +#define LPUART_CTRL_PE (1 << 1) /* Bit 1: Parity Enable */ +#define LPUART_CTRL_ILT (1 << 2) /* Bit 2: Idle Line Type Select */ +#define LPUART_CTRL_WAKE (1 << 3) /* Bit 3: Receiver Wakeup Method Select */ +#define LPUART_CTRL_M (1 << 4) /* Bit 4: 9-Bit or 8-Bit Mode Select */ +#define LPUART_CTRL_RSRC (1 << 5) /* Bit 5: Receiver Source Select */ +#define LPUART_CTRL_DOZEEN (1 << 6) /* Bit 6: Doze Enable */ +#define LPUART_CTRL_LOOPS (1 << 7) /* Bit 7: Loop Mode Select */ +#define LPUART_CTRL_IDLECFG_SHIFT (8) /* Bits 8-10: Idle Configuration */ +#define LPUART_CTRL_IDLECFG_MASK (7 << LPUART_CTRL_IDLECFG_SHIFT) +# define LPUART_CTRL_IDLECFG_1 (0 << LPUART_CTRL_IDLECFG_SHIFT) /* 1 idle character */ +# define LPUART_CTRL_IDLECFG_2 (1 << LPUART_CTRL_IDLECFG_SHIFT) /* 2 idle characters */ +# define LPUART_CTRL_IDLECFG_4 (2 << LPUART_CTRL_IDLECFG_SHIFT) /* 4 idle characters */ +# define LPUART_CTRL_IDLECFG_8 (3 << LPUART_CTRL_IDLECFG_SHIFT) /* 8 idle characters */ +# define LPUART_CTRL_IDLECFG_16 (4 << LPUART_CTRL_IDLECFG_SHIFT) /* 6 idle characters */ +# define LPUART_CTRL_IDLECFG_32 (5 << LPUART_CTRL_IDLECFG_SHIFT) /* 32 idle characters */ +# define LPUART_CTRL_IDLECFG_64 (6 << LPUART_CTRL_IDLECFG_SHIFT) /* 64 idle characters */ +# define LPUART_CTRL_IDLECFG_128 (7 << LPUART_CTRL_IDLECFG_SHIFT) /* 128 idle characters */ +#define LPUART_CTRL_M7 (1 << 11) /* Bit 11: 7-Bit Mode Select */ + /* Bits 12-13: Reserved */ +#define LPUART_CTRL_MA2IE (1 << 14) /* Bit 14: Match 2 Interrupt Enable */ +#define LPUART_CTRL_MA1IE (1 << 15) /* Bit 15: Match 1 Interrupt Enable */ +#define LPUART_CTRL_SBK (1 << 16) /* Bit 16: Send Break */ +#define LPUART_CTRL_RWU (1 << 17) /* Bit 17: Receiver Wakeup Control */ +#define LPUART_CTRL_RE (1 << 18) /* Bit 18: Receiver Enable */ +#define LPUART_CTRL_TE (1 << 19) /* Bit 19: Transmitter Enable */ +#define LPUART_CTRL_ILIE (1 << 20) /* Bit 20: Idle Line Interrupt Enable */ +#define LPUART_CTRL_RIE (1 << 21) /* Bit 21: Receiver Interrupt Enable */ +#define LPUART_CTRL_TCIE (1 << 22) /* Bit 22: Transmission Complete Interrupt Enable */ +#define LPUART_CTRL_TIE (1 << 23) /* Bit 23: Transmit Interrupt Enable */ +#define LPUART_CTRL_PEIE (1 << 24) /* Bit 24: Parity Error Interrupt Enable */ +#define LPUART_CTRL_FEIE (1 << 25) /* Bit 25: Framing Error Interrupt Enable */ +#define LPUART_CTRL_NEIE (1 << 26) /* Bit 26: Noise Error Interrupt Enable */ +#define LPUART_CTRL_ORIE (1 << 27) /* Bit 27: Overrun Interrupt Enable */ +#define LPUART_CTRL_TXINV (1 << 28) /* Bit 28: Transmit Data Inversion */ +#define LPUART_CTRL_TXDIR (1 << 29) /* Bit 29: TXD Pin Direction in Single-Wire Mode */ +#define LPUART_CTRL_R9T8 (1 << 30) /* Bit 30: Receive Bit 9 / Transmit Bit 8 */ +#define LPUART_CTRL_R8T9 (1 << 31) /* Bit 31: Receive Bit 8 / Transmit Bit 9 */ + +#define LPUART_ALL_INTS (LPUART_CTRL_ORIE | LPUART_CTRL_NEIE | LPUART_CTRL_FEIE | \ + LPUART_CTRL_PEIE | LPUART_CTRL_TIE | LPUART_CTRL_TCIE | \ + LPUART_CTRL_RIE | LPUART_CTRL_ILIE | LPUART_CTRL_MA1IE | \ + LPUART_CTRL_MA2IE) + +/* LPUART Data Register */ + +#define LPUART_DATA_SHIFT (0) /* Bits 0-9: Data bits 0-9 */ +#define LPUART_DATA_MASK (0x3ff << LPUART_DATA_SHIFT) + /* Bit 10: Reserved */ +#define LPUART_DATA_STATUS_SHIFT (11) /* Bit 11: Idle Line status */ +#define LPUART_DATA_IDLINE (1 << 11) /* Bit 11: Idle Line */ +#define LPUART_DATA_RXEMPT (1 << 12) /* Bit 12: Receive Buffer Empty */ +#define LPUART_DATA_FRETSC (1 << 13) /* Bit 13: Frame Error / Transmit Special Character */ +#define LPUART_DATA_PARITYE (1 << 14) /* Bit 14: Parity Error */ +#define LPUART_DATA_NOISY (1 << 15) /* Bit 15: Noisy */ + /* Bits 16-31: Reserved */ + +/* LPUART Match Address Register */ + +#define LPUART_MATCH_MA1_SHIFT (0) /* Bits 0-9: Match Address 1 */ +#define LPUART_MATCH_MA1_MASK (0x3ff << LPUART_MATCH_MA1_SHIFT) +# define LPUART_MATCH_MA1(n) ((uint32_t)(n) << LPUART_MATCH_MA1_SHIFT) + /* Bits 10-15: Reserved */ +#define LPUART_MATCH_MA2_SHIFT (16) /* Bits 16-25: Match Address 2 */ +#define LPUART_MATCH_MA2_MASK (0x3ff << LPUART_MATCH_MA2_SHIFT) +# define LPUART_MATCH_MA2(n) ((uint32_t)(n) << LPUART_MATCH_MA2_SHIFT) + /* Bits 26-31: Reserved */ + +/* LPUART Modem IrDA Register */ + +#define LPUART_MODIR_TXCTSE (1 << 0) /* Bit nn: Transmitter clear-to-send enable */ +#define LPUART_MODIR_TXRTSE (1 << 1) /* Bit nn: Transmitter request-to-send enable */ +#define LPUART_MODIR_TXRTSPOL (1 << 2) /* Bit nn: Transmitter request-to-send polarity */ +#define LPUART_MODIR_RXRTSE (1 << 3) /* Bit nn: Receiver request-to-send enable */ +#define LPUART_MODIR_TXCTSC (1 << 4) /* Bit nn: Transmit CTS Configuration */ +# define LPUART_MODIR_TXCTSC_START (0 << 4) /* CTS sampled at start of character */ +# define LPUART_MODIR_TXCTSC_IDLE (1 << 4) /* CTS sampled when transmitter idle */ +#define LPUART_MODIR_TXCTSSRC (1 << 5) /* Bit nn: Transmit CTS Source */ +# define LPUART_MODIR_TXCTSSRC_CTSB (0 << 5) /* Bit nn: CTS input is CTS_B pin */ +# define LPUART_MODIR_TXCTSSRC_RXMAT (1 << 5) /* Bit nn: Transmit CTS Source */ + /* Bits 6-7: Reserved */ +#define LPUART_MODIR_RTSWATER (8) /* Bits 8-9: Receive RTS Configuration */ +#define LPUART_MODIR_RTSWATER_MASK (3 << LPUART_MODIR_RTSWATER_SHIFT) +# define LPUART_MODIR_RTSWATER(n) ((uint32_t)(n) << LPUART_MODIR_RTSWATER_SHIFT) + /* Bits 10-15: Reserved */ +#define LPUART_MODIR_TNP_SHIFT (16) /* Bits 16-17: Transmitter narrow pulse */ +#define LPUART_MODIR_TNP_MASK (3 << LPUART_MODIR_TNP_SHIFT) +# define LPUART_MODIR_TNP(n) ((uint32_t)((n) - 1) << LPUART_MODIR_TNP_SHIFT) /* n/OSR */ +#define LPUART_MODIR_IREN (1 << 18) /* Bit nn: Infrared enable */ + /* Bits 19-31: Reserved */ + +/* LPUART FIFO Register */ + +#define LPUART_FIFO_RXFIFOSIZE_SHIFT (0) /* Bits 0-2: Receive FIFO. Buffer Depth */ +#define LPUART_FIFO_RXFIFOSIZE_MASK (7 << LPUART_FIFO_RXFIFOSIZE_SHIFT) +# define LPUART_FIFO_RXFIFOSIZE_1 (0 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 1 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_4 (1 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 4 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_8 (2 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 8 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_16 (3 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 16 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_32 (4 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 32 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_64 (5 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 64 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_128 (6 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 128 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_256 (7 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 256 datawords */ +#define LPUART_FIFO_RXFE (1 << 3) /* Bit 3: Receive FIFO Enable */ +#define LPUART_FIFO_TXFIFOSIZE_SHIFT (4) /* Bits 4-6: Transmit FIFO. Buffer Depth */ +#define LPUART_FIFO_TXFIFOSIZE_MASK (7 << LPUART_FIFO_TXFIFOSIZE_SHIFT) +# define LPUART_FIFO_TXFIFOSIZE_1 (0 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 1 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_4 (1 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 4 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_8 (2 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 8 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_16 (3 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 16 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_32 (4 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 32 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_64 (5 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 64 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_128 (6 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 128 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_256 (7 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 256 datawords */ + +#define LPUART_FIFO_TXFE (1 << 7) /* Bit 7: Transmit FIFO Enable */ +#define LPUART_FIFO_RXUFE (1 << 8) /* Bit 8: Receive FIFO Underflow Interrupt Enable */ +#define LPUART_FIFO_TXOFE (1 << 9) /* Bit 9: Transmit FIFO Overflow Interrupt Enable */ +#define LPUART_FIFO_RXIDEN_SHIFT (10) /* Bits 10-12: Receiver Idle Empty Enable */ +#define LPUART_FIFO_RXIDEN_MASK (7 << LPUART_FIFO_RXIDEN_SHIFT) +# define LPUART_FIFO_RXIDEN_DISABLE (0 << LPUART_FIFO_RXIDEN_SHIFT) /* Disable RDRF assertion when receiver is idle */ +# define LPUART_FIFO_RXIDEN_1 (1 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 1 word */ +# define LPUART_FIFO_RXIDEN_2 (2 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 2 words */ +# define LPUART_FIFO_RXIDEN_4 (3 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 4 words */ +# define LPUART_FIFO_RXIDEN_8 (4 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 8 words */ +# define LPUART_FIFO_RXIDEN_16 (5 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 16 words */ +# define LPUART_FIFO_RXIDEN_32 (6 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 32 words */ +# define LPUART_FIFO_RXIDEN_64 (7 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 64 words */ + +#define LPUART_FIFO_RXFLUSH (1 << 14) /* Bit 14: Receive FIFO/Buffer Flush */ +#define LPUART_FIFO_TXFLUSH (1 << 15) /* Bit 15: Transmit FIFO/Buffer Flush */ +#define LPUART_FIFO_RXUF (1 << 16) /* Bit 16: Receiver Buffer Underflow Flag */ +#define LPUART_FIFO_TXOF (1 << 17) /* Bit 17: Transmitter Buffer Overflow Flag */ + /* Bits 18-21: Reserved */ +#define LPUART_FIFO_RXEMPT (1 << 22) /* Bit 22: Receive Buffer/FIFO Empty */ +#define LPUART_FIFO_TXEMPT (1 << 23) /* Bit 23: Transmit Buffer/FIFO Empty */ + /* Bits 24-31: Reserved */ + +/* LPUART Watermark Register */ + +#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-1: Transmit Watermark */ +#define LPUART_WATER_TXWATER_MASK (3 << LPUART_WATER_TXWATER_SHIFT) +# define LPUART_WATER_TXWATER(n) ((uint32_t)(n) << LPUART_WATER_TXWATER_SHIFT) + /* Bits 2-7: Reserved */ +#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-10:Transmit Counter */ +#define LPUART_WATER_TXCOUNT_MASK (7 << LPUART_WATER_TXCOUNT_SHIFT) +# define LPUART_WATER_TXCOUNT(n) ((uint32_t)(n) << LPUART_WATER_TXCOUNT_SHIFT) + /* Bits 11-15: Reserved */ +#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-17: Receive Watermark */ +#define LPUART_WATER_RXWATER_MASK (3 << LPUART_WATER_RXWATER_SHIFT) +# define LPUART_WATER_RXWATER(n) ((uint32_t)(n) << LPUART_WATER_RXWATER_SHIFT) + /* Bits 18-23: Reserved */ +#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-26: Receive Counter */ +#define LPUART_WATER_RXCOUNT_MASK (7 << LPUART_WATER_RXCOUNT_SHIFT) +# define LPUART_WATER_RXCOUNT(n) ((uint32_t)(n) << LPUART_WATER_RXCOUNT_SHIFT) + /* Bits 27-31: Reserved */ + +#endif /* __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_LPUART_H */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_config.h b/arch/arm/src/s32k1xx/s32k1xx_config.h new file mode 100644 index 0000000000..dee9dd3993 --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_config.h @@ -0,0 +1,127 @@ +/************************************************************************************ + * arch/arm/src/s32k1xx/s32k1xx_config.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_S32K1XX_S32K1XX_CONFIG_H +#define __ARCH_ARM_SRC_S32K1XX_S32K1XX_CONFIG_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Configuration *********************************************************************/ + +#undef HAVE_LPUART0 +#undef HAVE_LPUART1 +#undef HAVE_LPUART2 + +#ifdef CONFIG_S32K1XX_LPUART0 +# define HAVE_LPUART0 1 +#endif +#ifdef CONFIG_S32K1XX_LPUART1 +# define HAVE_LPUART1 1 +#endif +#ifdef CONFIG_S32K1XX_LPUART2 +# define HAVE_LPUART2 1 +#endif + +/* Check if we have a LPUART device */ + +#undef CONFIG_S32K1XX_HAVE_LPUART +#undef HAVE_LPUART_DEVICE + +#if defined(HAVE_LPUART0) || defined(HAVE_LPUART1) || defined(HAVE_LPUART2) +# define HAVE_LPUART_DEVICE 1 +#endif + +/* Is there a serial console? There should be at most one defined. It could be on + * any LPUARTn, n=0,1,2,3 + */ + +#undef HAVE_LPUART_CONSOLE + +#if defined(CONFIG_LPUART0_SERIAL_CONSOLE) && defined(HAVE_LPUART0) +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_LPUART2_SERIAL_CONSOLE +# define HAVE_LPUART_CONSOLE 1 +#elif defined(CONFIG_LPUART1_SERIAL_CONSOLE) && defined(HAVE_LPUART1) +# undef CONFIG_LPUART0_SERIAL_CONSOLE +# undef CONFIG_LPUART2_SERIAL_CONSOLE +# define HAVE_LPUART_CONSOLE 1 +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) && defined(HAVE_LPUART2) +# undef CONFIG_LPUART0_SERIAL_CONSOLE +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# define HAVE_LPUART_CONSOLE 1 +#else +# ifdef CONFIG_DEV_CONSOLE +# warning "No valid CONFIG_[LP]LPUART[n]_SERIAL_CONSOLE Setting" +# endif +# undef CONFIG_LPUART0_SERIAL_CONSOLE +# undef CONFIG_LPUART1_SERIAL_CONSOLE +# undef CONFIG_LPUART2_SERIAL_CONSOLE +#endif + +/* Check LPUART flow control (Not yet supported) */ + +# undef CONFIG_LPUART0_FLOWCONTROL +# undef CONFIG_LPUART1_FLOWCONTROL +# undef CONFIG_LPUART2_FLOWCONTROL + +/* Ethernet controller configuration */ + +#ifndef CONFIG_S32K1XX_ENET_NRXBUFFERS +# define CONFIG_S32K1XX_ENET_NRXBUFFERS 6 +#endif + +#ifndef CONFIG_S32K1XX_ENET_NTXBUFFERS +# define CONFIG_S32K1XX_ENET_NTXBUFFERS 2 +#endif + +#ifndef CONFIG_S32K1XX_ENET_NETHIFS +# define CONFIG_S32K1XX_ENET_NETHIFS 1 +#endif + +#define S32K1XX_ENET_HAS_DBSWAP 1 + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_S32K1XX_S32K1XX_CONFIG_H */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_lowputc.c b/arch/arm/src/s32k1xx/s32k1xx_lowputc.c new file mode 100644 index 0000000000..67d410b916 --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_lowputc.c @@ -0,0 +1,476 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_lowputc.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "up_arch.h" + +#include "hardware/s32k1xx_pinmux.h" +#include "hardware/s32k1xx_lpuart.h" +#include "s32k1xx_config.h" +#include "s32k1xx_periphclks.h" +#include "s32k1xx_gpio.h" +#include "s32k1xx_lowputc.h" + +#include "up_internal.h" + +#include /* Include last: has dependencies */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifdef HAVE_LPUART_CONSOLE +# if defined(CONFIG_LPUART0_SERIAL_CONSOLE) +# define S32K1XX_CONSOLE_BASE S32K1XX_LPUART0_BASE +# define S32K1XX_CONSOLE_BAUD CONFIG_LPUART0_BAUD +# define S32K1XX_CONSOLE_BITS CONFIG_LPUART0_BITS +# define S32K1XX_CONSOLE_PARITY CONFIG_LPUART0_PARITY +# define S32K1XX_CONSOLE_2STOP CONFIG_LPUART0_2STOP +# elif defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define S32K1XX_CONSOLE_BASE S32K1XX_LPUART1_BASE +# define S32K1XX_CONSOLE_BAUD CONFIG_LPUART1_BAUD +# define S32K1XX_CONSOLE_BITS CONFIG_LPUART1_BITS +# define S32K1XX_CONSOLE_PARITY CONFIG_LPUART1_PARITY +# define S32K1XX_CONSOLE_2STOP CONFIG_LPUART1_2STOP +# elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define S32K1XX_CONSOLE_BASE S32K1XX_LPUART2_BASE +# define S32K1XX_CONSOLE_BAUD CONFIG_LPUART2_BAUD +# define S32K1XX_CONSOLE_BITS CONFIG_LPUART2_BITS +# define S32K1XX_CONSOLE_PARITY CONFIG_LPUART2_PARITY +# define S32K1XX_CONSOLE_2STOP CONFIG_LPUART2_2STOP +#endif + +/* Clocking *****************************************************************/ + +/* The UART module receives two clocks, a peripheral_clock (ipg_clk) and the + * module_clock (ipg_perclk). The peripheral_clock is used as write clock + * of the TxFIFO, read clock of the RxFIFO and synchronization of the modem + * control input pins. It must always be running when UART is enabled. + * + * The default lpuart1 ipg_clk is 66MHz (max 66.5MHz). ipg_clk is shared + * among many modules and should not be controlled by the UART logic. + * + * The module_clock is for all the state machines, writing RxFIFO, reading + * TxFIFO, etc. It must always be running when UART is sending or receiving + * characters. This clock is used in order to allow frequency scaling on + * peripheral_clock without changing configuration of baud rate. + * + * The default ipg_perclk is 80MHz (max 80MHz). ipg_perclk is gated by + * CCGR5[CG12], lpuart1_clk_enable. The clock generation sequence is: + * + * pll3_sw_clk (480M) -> CCGR5[CG12] -> 3 bit divider cg podf=6 -> + * PLL3_80M (80Mhz) -> CDCDR1: lpuart1_clk_podf -> + * 6 bit divider default=1 -> LPUART0_CLK_ROOT + * + * REVISIT: This logic assumes that all dividers are at the default value + * and that the value of the ipg_perclk is 80MHz. + */ + +#define IPG_PERCLK_FREQUENCY 80000000 + +/* The BRM sub-block receives ref_clk (module_clock clock after divider). + * From this clock, and with integer and non-integer division, BRM generates + * a 16x baud rate clock. + */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef HAVE_LPUART_CONSOLE +static const struct uart_config_s g_console_config = +{ + .baud = S32K1XX_CONSOLE_BAUD, /* Configured baud */ + .parity = S32K1XX_CONSOLE_PARITY, /* 0=none, 1=odd, 2=even */ + .bits = S32K1XX_CONSOLE_BITS, /* Number of bits (5-9) */ + .stopbits2 = S32K1XX_CONSOLE_2STOP, /* true: Configure with 2 stop bits instead of 1 */ +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +void s32k1xx_lpuart_clock_enable (uint32_t base) +{ + if (base == S32K1XX_LPUART0_BASE) + { + s32k1xx_clockall_lpuart1(); + } + else if (base == S32K1XX_LPUART1_BASE) + { + s32k1xx_clockall_lpuart2(); + } + else if (base == S32K1XX_LPUART2_BASE) + { + s32k1xx_clockall_lpuart3(); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization including setup of the console UART. This UART done + * early so that the serial console is available for debugging very early + * in the boot sequence. + * + ****************************************************************************/ + +void s32k1xx_lowsetup(void) +{ +#ifndef CONFIG_SUPPRESS_LPUART_CONFIG +#ifdef HAVE_LPUART_DEVICE + +#ifdef CONFIG_S32K1XX_LPUART0 + + /* Configure LPUART0 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + (void)s32k1xx_config_gpio(GPIO_LPUART0_RX); + (void)s32k1xx_config_gpio(GPIO_LPUART0_TX); +#ifdef CONFIG_LPUART0_OFLOWCONTROL + (void)s32k1xx_config_gpio(GPIO_LPUART0_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART0_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL))) + (void)s32k1xx_config_gpio(GPIO_LPUART0_RTS); +#endif +#endif + +#ifdef CONFIG_S32K1XX_LPUART1 + + /* Configure LPUART1 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + (void)s32k1xx_config_gpio(GPIO_LPUART1_RX); + (void)s32k1xx_config_gpio(GPIO_LPUART1_TX); +#ifdef CONFIG_LPUART1_OFLOWCONTROL + (void)s32k1xx_config_gpio(GPIO_LPUART1_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + (void)s32k1xx_config_gpio(GPIO_LPUART1_RTS); +#endif +#endif + +#ifdef CONFIG_S32K1XX_LPUART2 + + /* Configure LPUART2 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + (void)s32k1xx_config_gpio(GPIO_LPUART2_RX); + (void)s32k1xx_config_gpio(GPIO_LPUART2_TX); +#ifdef CONFIG_LPUART2_OFLOWCONTROL + (void)s32k1xx_config_gpio(GPIO_LPUART2_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) + (void)s32k1xx_config_gpio(GPIO_LPUART2_RTS); +#endif +#endif + +#ifdef HAVE_LPUART_CONSOLE + /* Configure the serial console for initial, non-interrupt driver mode */ + + (void)s32k1xx_lpuart_configure(S32K1XX_CONSOLE_BASE, &g_console_config); +#endif +#endif /* HAVE_LPUART_DEVICE */ +#endif /* CONFIG_SUPPRESS_LPUART_CONFIG */ +} + +/**************************************************************************** + * Name: s32k1xx_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ + +#ifdef HAVE_LPUART_DEVICE +int s32k1xx_lpuart_configure(uint32_t base, + FAR const struct uart_config_s *config) +{ + uint32_t src_freq = 0; + uint32_t pll3_div = 0; + uint32_t uart_div = 0; + uint32_t lpuart_freq = 0; + uint16_t sbr; + uint16_t temp_sbr; + uint32_t osr; + uint32_t temp_osr; + uint32_t temp_diff; + uint32_t calculated_baud; + uint32_t baud_diff; + uint32_t regval; + + if ((getreg32(S32K1XX_CCM_CSCDR1) & CCM_CSCDR1_UART_CLK_SEL) != 0) + { + src_freq = BOARD_XTAL_FREQUENCY; + } + else + { + if ((getreg32(S32K1XX_CCM_ANALOG_PLL_USB1) & + CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0) + { + pll3_div = 22; + } + else + { + pll3_div = 20; + } + + src_freq = (BOARD_XTAL_FREQUENCY * pll3_div) / 6; + } + + uart_div = (getreg32(S32K1XX_CCM_CSCDR1) & CCM_CSCDR1_UART_CLK_PODF_MASK) + 1; + lpuart_freq = src_freq / uart_div; + + /* This LPUART instantiation uses a slightly different baud rate + * calculation. The idea is to use the best OSR (over-sampling rate) + * possible. + * + * NOTE: OSR is typically hard-set to 16 in other LPUART instantiations + * loop to find the best OSR value possible, one that generates minimum + * baud_diff iterate through the rest of the supported values of OSR + */ + + baud_diff = config->baud; + osr = 0; + sbr = 0; + + for (temp_osr = 4; temp_osr <= 32; temp_osr++) + { + /* Calculate the temporary sbr value */ + + temp_sbr = (lpuart_freq / (config->baud * temp_osr)); + + /* Set temp_sbr to 1 if the sourceClockInHz can not satisfy the + * desired baud rate. + */ + + if (temp_sbr == 0) + { + temp_sbr = 1; + } + + /* Calculate the baud rate based on the temporary OSR and SBR values */ + + calculated_baud = (lpuart_freq / (temp_osr * temp_sbr)); + temp_diff = calculated_baud - config->baud; + + /* Select the better value between srb and (sbr + 1) */ + + if (temp_diff > (config->baud - (lpuart_freq / (temp_osr * (temp_sbr + 1))))) + { + temp_diff = config->baud - (lpuart_freq / (temp_osr * (temp_sbr + 1))); + temp_sbr++; + } + + if (temp_diff <= baud_diff) + { + baud_diff = temp_diff; + osr = temp_osr; + sbr = temp_sbr; + } + } + + if (baud_diff > ((config->baud / 100) * 3)) + { + /* Unacceptable baud rate difference of more than 3% */ + + return ERROR; + } + + /* Enable lpuart clock */ + + s32k1xx_lpuart_clock_enable(base); + + /* Reset all internal logic and registers, except the Global Register */ + + regval = getreg32(base + S32K1XX_LPUART_GLOBAL_OFFSET); + regval |= LPUART_GLOBAL_RST; + putreg32(regval, base + S32K1XX_LPUART_GLOBAL_OFFSET); + + regval &= ~LPUART_GLOBAL_RST; + putreg32(regval, base + S32K1XX_LPUART_GLOBAL_OFFSET); + + /* Construct MODIR register */ + + regval = 0; + + if (config->userts) + { + regval |= LPUART_MODIR_RXRTSE; + } + else if (config->users485) + { + /* Both TX and RX side can't control RTS, so this gives + * the RX side precidence. This should have been filtered + * in layers above anyway, but it's just a precaution. + */ + + regval |= LPUART_MODIR_TXRTSE; + } + + if (config->usects) + { + regval |= LPUART_MODIR_TXCTSE; + } + + if (config->invrts) + { + regval |= LPUART_MODIR_TXRTSPOL; + } + + putreg32(regval, base + S32K1XX_LPUART_MODIR_OFFSET); + + regval = 0; + + if ((osr > 3) && (osr < 8)) + { + regval |= LPUART_BAUD_BOTHEDGE; + } + + if (config->stopbits2) + { + regval |= LPUART_BAUD_SBNS; + } + + regval |= LPUART_BAUD_OSR(osr) | LPUART_BAUD_SBR(sbr); + putreg32(regval, base + S32K1XX_LPUART_BAUD_OFFSET); + + regval = 0; + if (config->parity == 1) + { + regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_ODD; + } + else if (config->parity == 2) + { + regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_EVEN; + } + + if (config->bits == 8) + { + regval &= ~LPUART_CTRL_M; + } + else if (config->bits == 9) + { + regval |= LPUART_CTRL_M; + } + else + { + /* Here should be added support of other bit modes. */ + +#warning missing logic + return ERROR; + } + + regval |= LPUART_CTRL_RE | LPUART_CTRL_TE; + putreg32(regval, base + S32K1XX_LPUART_CTRL_OFFSET); + + return OK; +} +#endif /* HAVE_LPUART_DEVICE */ + +/**************************************************************************** + * Name: s32k1xx_lowputc + * + * Description: + * Output a byte with as few system dependencies as possible. This will + * even work BEFORE the console is initialized if we are booting from U- + * Boot (and the same UART is used for the console, of course.) + * + ****************************************************************************/ + +#if defined(HAVE_LPUART_DEVICE) && defined(CONFIG_DEBUG_FEATURES) +void s32k1xx_lowputc(int ch) +{ + while ((getreg32(S32K1XX_CONSOLE_BASE + S32K1XX_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } + + /* If the character to output is a newline, then pre-pend a carriage return */ + + if (ch == '\n') + { + /* Send the carriage return by writing it into the UART_TXD register. */ + + putreg32((uint32_t)'\r', S32K1XX_CONSOLE_BASE + S32K1XX_LPUART_DATA_OFFSET); + + /* Wait for the transmit register to be emptied. When the TXFE bit is + * non-zero, the TX Buffer FIFO is empty. + */ + + while ((getreg32(S32K1XX_CONSOLE_BASE + S32K1XX_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } + } + + /* Send the character by writing it into the UART_TXD register. */ + + putreg32((uint32_t)ch, S32K1XX_CONSOLE_BASE + S32K1XX_LPUART_DATA_OFFSET); + + /* Wait for the transmit register to be emptied. When the TXFE bit is + * non-zero, the TX Buffer FIFO is empty. + */ + + while ((getreg32(S32K1XX_CONSOLE_BASE + S32K1XX_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } +} +#endif diff --git a/arch/arm/src/s32k1xx/s32k1xx_lowputc.h b/arch/arm/src/s32k1xx/s32k1xx_lowputc.h new file mode 100644 index 0000000000..94f834ec56 --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_lowputc.h @@ -0,0 +1,119 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_lowputc.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_S32K1XX_LOWPUTC_H +#define __ARCH_ARM_SRC_S32K1XX_LOWPUTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "s32k1xx_config.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef HAVE_LPUART_DEVICE +/* This structure describes the configuration of an UART */ + +struct uart_config_s +{ + uint32_t baud; /* Configured baud */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (5-9) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + bool userts; /* True: Assert RTS when there are data to be sent */ + bool invrts; /* True: Invert sense of RTS pin (true=active high) */ + bool usects; /* True: Condition transmission on CTS asserted */ + bool users485; /* True: Assert RTS while transmission progresses */ +}; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization including setup of the console UART. This UART done + * early so that the serial console is available for debugging very early + * in the boot sequence. + * + ****************************************************************************/ + +void s32k1xx_lowsetup(void); + +/**************************************************************************** + * Name: s32k1xx_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ + +#ifdef HAVE_LPUART_DEVICE +int s32k1xx_lpuart_configure(uint32_t base, + FAR const struct uart_config_s *config); +#endif + +/**************************************************************************** + * Name: s32k1xx_lowputc + * + * Description: + * Output a byte with as few system dependencies as possible. This will + * even work BEFORE the console is initialized if we are booting from U- + * Boot (and the same UART is used for the console, of course.) + * + ****************************************************************************/ + +#if defined(HAVE_LPUART_DEVICE) && defined(CONFIG_DEBUG_FEATURES) +void s32k1xx_lowputc(int ch); +#else +# define s32k1xx_lowputc(ch) +#endif + +#endif /* __ARCH_ARM_SRC_S32K1XX_LOWPUTC_H */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_serial.c b/arch/arm/src/s32k1xx/s32k1xx_serial.c new file mode 100644 index 0000000000..d9881f90fb --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_serial.c @@ -0,0 +1,1333 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_serial.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "chip.h" +#include "up_arch.h" +#include "up_internal.h" + +#include "hardware/s32k1xx_lpuart.h" +#include "s32k1xx_gpio.h" +#include "hardware/s32k1xx_pinmux.h" +#include "s32k1xx_config.h" +#include "s32k1xx_lowputc.h" + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Which LPUART with be tty0/console and which tty1-7? The console will + * always be ttyS0. If there is no console then will use the lowest + * numbered LPUART. + */ + +/* First pick the console and ttys0. This could be any of LPUART0-2 */ + +#if defined(CONFIG_LPUART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart0port /* LPUART0 is console */ +# define TTYS0_DEV g_uart0port /* LPUART0 is ttyS0 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* LPUART1 is console */ +# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */ +# define UART2_ASSIGNED 1 +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart2port /* LPUART2 is console */ +# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */ +# define UART3_ASSIGNED 1 +#else +# undef CONSOLE_DEV /* No console */ +# if defined(CONFIG_S32K1XX_LPUART0) +# define TTYS0_DEV g_uart0port /* LPUART0 is ttyS0 */ +# define UART1_ASSIGNED 1 +# elif defined(CONFIG_S32K1XX_LPUART1) +# define TTYS0_DEV g_uart1port /* LPUART1 is ttyS0 */ +# define UART2_ASSIGNED 1 +# elif defined(CONFIG_S32K1XX_LPUART2) +# define TTYS0_DEV g_uart2port /* LPUART2 is ttyS0 */ +# define UART3_ASSIGNED 1 +# endif +#endif + +/* Pick ttys1. This could be any of LPUART0-2 excluding the console UART. + * One of LPUART0-8 could be the console; one of UART0-2 has already been + * assigned to ttys0. + */ + +#if defined(CONFIG_S32K1XX_LPUART0) && !defined(UART1_ASSIGNED) +# define TTYS1_DEV g_uart0port /* LPUART0 is ttyS1 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART1) && !defined(UART2_ASSIGNED) +# define TTYS1_DEV g_uart1port /* LPUART1 is ttyS1 */ +# define UART2_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(UART3_ASSIGNED) +# define TTYS1_DEV g_uart2port /* LPUART2 is ttyS1 */ +# define UART3_ASSIGNED 1 +#endif + +/* Pick ttys2. This could be one of LPUART0-2. It can't be LPUART0 because + * that was either assigned as ttyS0 or ttys1. One of LPUART0-2 could be the + * console. One of UART1-2 has already been assigned to ttys0 or ttyS1. + */ + +#if defined(CONFIG_S32K1XX_LPUART1) && !defined(UART2_ASSIGNED) +# define TTYS2_DEV g_uart1port /* LPUART1 is ttyS2 */ +# define UART2_ASSIGNED 1 +#elif defined(CONFIG_S32K1XX_LPUART2) && !defined(UART3_ASSIGNED) +# define TTYS2_DEV g_uart2port /* LPUART2 is ttyS2 */ +# define UART3_ASSIGNED 1 +#endif + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_S32K1XX_PM_SERIAL_ACTIVITY) +# define CONFIG_S32K1XX_PM_SERIAL_ACTIVITY 10 +#endif + +#if defined(CONFIG_PM) +# define PM_IDLE_DOMAIN 0 /* Revisit */ +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct s32k1xx_uart_s +{ + uint32_t uartbase; /* Base address of UART registers */ + uint32_t baud; /* Configured baud */ + uint32_t ie; /* Saved enabled interrupts */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ +#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + uint8_t inviflow:1; /* Invert RTS sense */ + const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */ +#endif + + uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + uint8_t iflow:1; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + uint8_t oflow:1; /* output flow control (CTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_RS485CONTROL + uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t s32k1xx_serialin(struct s32k1xx_uart_s *priv, + uint32_t offset); +static inline void s32k1xx_serialout(struct s32k1xx_uart_s *priv, + uint32_t offset, uint32_t value); +static inline void s32k1xx_disableuartint(struct s32k1xx_uart_s *priv, + uint32_t *ie); +static inline void s32k1xx_restoreuartint(struct s32k1xx_uart_s *priv, + uint32_t ie); + +static int s32k1xx_setup(struct uart_dev_s *dev); +static void s32k1xx_shutdown(struct uart_dev_s *dev); +static int s32k1xx_attach(struct uart_dev_s *dev); +static void s32k1xx_detach(struct uart_dev_s *dev); +static int s32k1xx_interrupt(int irq, void *context, FAR void *arg); +static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg); +static int s32k1xx_receive(struct uart_dev_s *dev, uint32_t *status); +static void s32k1xx_rxint(struct uart_dev_s *dev, bool enable); +static bool s32k1xx_rxavailable(struct uart_dev_s *dev); +static void s32k1xx_send(struct uart_dev_s *dev, int ch); +static void s32k1xx_txint(struct uart_dev_s *dev, bool enable); +static bool s32k1xx_txready(struct uart_dev_s *dev); +static bool s32k1xx_txempty(struct uart_dev_s *dev); + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int dowmin, + enum pm_state_e pmstate); +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Serial driver UART operations */ + +static const struct uart_ops_s g_uart_ops = +{ + .setup = s32k1xx_setup, + .shutdown = s32k1xx_shutdown, + .attach = s32k1xx_attach, + .detach = s32k1xx_detach, + .ioctl = s32k1xx_ioctl, + .receive = s32k1xx_receive, + .rxint = s32k1xx_rxint, + .rxavailable = s32k1xx_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = s32k1xx_send, + .txint = s32k1xx_txint, + .txready = s32k1xx_txready, + .txempty = s32k1xx_txempty, +}; + +/* I/O buffers */ + +#ifdef CONFIG_S32K1XX_LPUART0 +static char g_uart0rxbuffer[CONFIG_LPUART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_LPUART0_TXBUFSIZE]; +#endif + +#ifdef CONFIG_S32K1XX_LPUART1 +static char g_uart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_LPUART1_TXBUFSIZE]; +#endif + +#ifdef CONFIG_S32K1XX_LPUART2 +static char g_uart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE]; +static char g_uart2txbuffer[CONFIG_LPUART2_TXBUFSIZE]; +#endif + +/* This describes the state of the S32K1XX lpuart0 port. */ + +#ifdef CONFIG_S32K1XX_LPUART0 +static struct s32k1xx_uart_s g_uart0priv = +{ + .uartbase = S32K1XX_LPUART0_BASE, + .baud = CONFIG_LPUART0_BAUD, + .irq = S32K1XX_IRQ_LPUART0, + .parity = CONFIG_LPUART0_PARITY, + .bits = CONFIG_LPUART0_BITS, + .stopbits2 = CONFIG_LPUART0_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART0_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART0_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART0_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART0_RTS, +#endif + +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART0_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART0_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart0port = +{ + .recv = + { + .size = CONFIG_LPUART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +/* This describes the state of the S32K1XX lpuart1 port. */ + +#ifdef CONFIG_S32K1XX_LPUART1 +static struct s32k1xx_uart_s g_uart1priv = +{ + .uartbase = S32K1XX_LPUART1_BASE, + .baud = CONFIG_LPUART1_BAUD, + .irq = S32K1XX_IRQ_LPUART1, + .parity = CONFIG_LPUART1_PARITY, + .bits = CONFIG_LPUART1_BITS, + .stopbits2 = CONFIG_LPUART1_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART1_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART1_RTS, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART1_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart1port = +{ + .recv = + { + .size = CONFIG_LPUART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +#ifdef CONFIG_S32K1XX_LPUART2 +static struct s32k1xx_uart_s g_uart2priv = +{ + .uartbase = S32K1XX_LPUART2_BASE, + .baud = CONFIG_LPUART2_BAUD, + .irq = S32K1XX_IRQ_LPUART2, + .parity = CONFIG_LPUART2_PARITY, + .bits = CONFIG_LPUART2_BITS, + .stopbits2 = CONFIG_LPUART2_2STOP, +#if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART2_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART2_CTS, +#endif +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL) + .iflow = 1, +#endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) \ + || (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART2_RTS, +#endif +#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \ + && defined(CONFIG_LPUART2_INVERTIFLOWCONTROL)) + .inviflow = 1, +#endif + +#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL) + .rs485mode = 1, +#endif +}; + +static struct uart_dev_s g_uart2port = +{ + .recv = + { + .size = CONFIG_LPUART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +#ifdef CONFIG_PM +static struct pm_callback_s g_serial_pmcb = +{ + .notify = up_pm_notify, + .prepare = up_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_serialin + ****************************************************************************/ + +static inline uint32_t s32k1xx_serialin(struct s32k1xx_uart_s *priv, + uint32_t offset) +{ + return getreg32(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: s32k1xx_serialout + ****************************************************************************/ + +static inline void s32k1xx_serialout(struct s32k1xx_uart_s *priv, uint32_t offset, + uint32_t value) +{ + putreg32(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: s32k1xx_disableuartint + ****************************************************************************/ + +static inline void s32k1xx_disableuartint(struct s32k1xx_uart_s *priv, + uint32_t *ie) +{ + irqstate_t flags; + uint32_t regval; + + flags = spin_lock_irqsave(); + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET); + + /* Return the current Rx and Tx interrupt state */ + + if (ie != NULL) + { + *ie = regval & LPUART_ALL_INTS; + } + + regval &= ~LPUART_ALL_INTS; + s32k1xx_serialout(priv, S32K1XX_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(flags); +} + +/**************************************************************************** + * Name: s32k1xx_restoreuartint + ****************************************************************************/ + +static inline void s32k1xx_restoreuartint(struct s32k1xx_uart_s *priv, + uint32_t ie) +{ + irqstate_t flags; + uint32_t regval; + + /* Enable/disable any interrupts that are currently disabled but should be + * enabled/disabled. + */ + + flags = spin_lock_irqsave(); + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= ie; + s32k1xx_serialout(priv, S32K1XX_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(flags); +} + +/**************************************************************************** + * Name: s32k1xx_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 s32k1xx_setup(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; +#ifndef CONFIG_SUPPRESS_LPUART_CONFIG + struct uart_config_s config = + { + 0 + }; + int ret; + + /* Configure the UART */ + + config.baud = priv->baud; /* Configured baud */ + config.parity = priv->parity; /* 0=none, 1=odd, 2=even */ + config.bits = priv->bits; /* Number of bits (5-9) */ + config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + config.usects = priv->iflow; /* Flow control on inbound side */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + config.userts = priv->oflow; /* Flow control on outbound side */ +#endif +#ifdef CONFIG_SERIAL_RS485CONTROL + config.users485 = priv->rs485mode; /* Switch into RS485 mode */ +#endif +#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + config.invrts = priv->inviflow; /* Inversion of outbound flow control */ +#endif + + ret = s32k1xx_lpuart_configure(priv->uartbase, &config); + + priv->ie = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET) & LPUART_ALL_INTS; + return ret; + +#else + priv->ie = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET) & LPUART_ALL_INTS; + return OK; +#endif +} + +/**************************************************************************** + * Name: s32k1xx_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void s32k1xx_shutdown(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + + /* Disable the UART */ + + s32k1xx_serialout(priv, S32K1XX_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST); +} + +/**************************************************************************** + * Name: s32k1xx_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method + * is called when the serial port is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate + * in a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supports multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int s32k1xx_attach(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, s32k1xx_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: s32k1xx_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void s32k1xx_detach(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: s32k1xx_interrupt (and front-ends) + * + * Description: + * This is the common UART interrupt handler. It should cal + * uart_transmitchars or uart_receivechar to perform the appropriate data + * transfers. + * + ****************************************************************************/ + +static int s32k1xx_interrupt(int irq, void *context, FAR void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct s32k1xx_uart_s *priv; + uint32_t usr; + int passes = 0; + bool handled; + + DEBUGASSERT(dev != NULL && dev->priv != NULL); + priv = (struct s32k1xx_uart_s *)dev->priv; + +#if defined(CONFIG_PM) && CONFIG_S32K1XX_PM_SERIAL_ACTIVITY > 0 + /* Report serial activity to the power management logic */ + + pm_activity(PM_IDLE_DOMAIN, CONFIG_S32K1XX_PM_SERIAL_ACTIVITY); +#endif + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + handled = true; + for (passes = 0; passes < 256 && handled; passes++) + { + handled = false; + + /* Get the current UART status and check for loop + * termination conditions + */ + + usr = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + usr &= (LPUART_STAT_RDRF | LPUART_STAT_TC | LPUART_STAT_OR | + LPUART_STAT_FE); + + /* Clear serial overrun and framing errors */ + + if ((usr & LPUART_STAT_OR) != 0) + { + s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, LPUART_STAT_OR); + } + + if ((usr & LPUART_STAT_FE) != 0) + { + s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, LPUART_STAT_FE); + } + + /* Handle incoming, receive bytes */ + + if ((usr & LPUART_STAT_RDRF) != 0 && + (priv->ie & LPUART_CTRL_RIE) != 0) + { + uart_recvchars(dev); + handled = true; + } + + /* Handle outgoing, transmit bytes */ + + if ((usr & LPUART_STAT_TC) != 0 && + (priv->ie & LPUART_CTRL_TCIE) != 0) + { + uart_xmitchars(dev); + handled = true; + } + } + + return OK; +} + +/**************************************************************************** + * Name: s32k1xx_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int s32k1xx_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct s32k1xx_uart_s *user = (struct s32k1xx_uart_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct s32k1xx_uart_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Return baud */ + + cfsetispeed(termiosp, priv->baud); + + /* Return parity */ + + termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0); + + /* Return stop bits */ + + termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; + + /* Return flow control */ + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + termiosp->c_cflag |= ((priv->oflow) ? CCTS_OFLOW : 0); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + termiosp->c_cflag |= ((priv->iflow) ? CRTS_IFLOW : 0); +#endif + /* Return number of bits */ + + switch (priv->bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + + case 6: + termiosp->c_cflag |= CS6; + break; + + case 7: + termiosp->c_cflag |= CS7; + break; + + default: + case 8: + termiosp->c_cflag |= CS8; + break; + + case 9: + termiosp->c_cflag |= CS8 /* CS9 */; + break; + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + uint32_t baud; + uint32_t ie; + uint8_t parity; + uint8_t nbits; + bool stop2; + + if ((!termiosp) +#ifdef CONFIG_SERIAL_OFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#endif + ) + { + ret = -EINVAL; + break; + } + + /* Decode baud. */ + + ret = OK; + baud = cfgetispeed(termiosp); + + /* Decode number of bits */ + + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + nbits = 5; + break; + + case CS6: + nbits = 6; + break; + + case CS7: + nbits = 7; + break; + + case CS8: + nbits = 8; + break; +#if 0 + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } + + /* Decode parity */ + + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } + + /* Decode stop bits */ + + stop2 = (termiosp->c_cflag & CSTOPB) != 0; + + /* Verify that all settings are valid before committing */ + + if (ret == OK) + { + /* Commit */ + + priv->baud = baud; + priv->parity = parity; + priv->bits = nbits; + priv->stopbits2 = stop2; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + s32k1xx_disableuartint(priv, &ie); + ret = s32k1xx_setup(dev); + + /* Restore the interrupt state */ + + s32k1xx_restoreuartint(priv, ie); + priv->ie = ie; + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + +#ifdef CONFIG_S32K1XX_LPUART_INVERT + case TIOCSINVERT: + { + uint32_t ctrl; + uint32_t stat; + uint32_t regval; + irqstate_t flags; + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + + flags = spin_lock_irqsave(); + ctrl = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET); + stat = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + regval = ctrl; + + /* {R|T}XINV bit field can only be written when the receiver is disabled (RE=0). */ + + regval &= ~LPUART_CTRL_RE; + + s32k1xx_serialout(priv, S32K1XX_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; + } + + s32k1xx_serialout(priv, S32K1XX_LPUART_STAT_OFFSET, stat); + s32k1xx_serialout(priv, S32K1XX_LPUART_CTRL_OFFSET, ctrl); + + spin_unlock_irqrestore(flags); + } + break; +#endif + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: s32k1xx_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +static int s32k1xx_receive(struct uart_dev_s *dev, uint32_t *status) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + uint32_t rxd; + + rxd = s32k1xx_serialin(priv, S32K1XX_LPUART_DATA_OFFSET); + *status = rxd >> LPUART_DATA_STATUS_SHIFT; + return (rxd & LPUART_DATA_MASK) >> LPUART_DATA_SHIFT; +} + +/**************************************************************************** + * Name: s32k1xx_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void s32k1xx_rxint(struct uart_dev_s *dev, bool enable) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupts for data available at Rx */ + + flags = spin_lock_irqsave(); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE; +#endif + } + else + { + priv->ie &= ~(LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE); + } + + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + s32k1xx_serialout(priv, S32K1XX_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(flags); +} + +/**************************************************************************** + * Name: s32k1xx_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +static bool s32k1xx_rxavailable(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + uint32_t regval; + + /* Return true is data is ready in the Rx FIFO */ + + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_RDRF) != 0); +} + +/**************************************************************************** + * Name: s32k1xx_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void s32k1xx_send(struct uart_dev_s *dev, int ch) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + s32k1xx_serialout(priv, S32K1XX_LPUART_DATA_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: s32k1xx_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void s32k1xx_txint(struct uart_dev_s *dev, bool enable) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupt for TX complete */ + + flags = spin_lock_irqsave(); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_TCIE; +#endif + } + else + { + priv->ie &= ~LPUART_CTRL_TCIE; + } + + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + s32k1xx_serialout(priv, S32K1XX_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(flags); +} + +/**************************************************************************** + * Name: s32k1xx_txready + * + * Description: + * Return true if the transmit is completed + * + ****************************************************************************/ + +static bool s32k1xx_txready(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + uint32_t regval; + + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TC) != 0); +} + +/**************************************************************************** + * Name: s32k1xx_txempty + * + * Description: + * Return true if the transmit reg is empty + * + ****************************************************************************/ + +static bool s32k1xx_txempty(struct uart_dev_s *dev) +{ + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)dev->priv; + uint32_t regval; + + regval = s32k1xx_serialin(priv, S32K1XX_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TDRE) != 0); +} + +/**************************************************************************** + * Name: up_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Logic for PM_NORMAL goes here */ + + } + break; + + case(PM_IDLE): + { + /* Logic for PM_IDLE goes here */ + + } + break; + + case(PM_STANDBY): + { + /* Logic for PM_STANDBY goes here */ + + } + break; + + case(PM_SLEEP): + { + /* Logic for PM_SLEEP goes here */ + + } + break; + + default: + /* Should not get here */ + + break; + } +} +#endif + +/**************************************************************************** + * Name: up_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* Logic to prepare for a reduced power state goes here. */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_earlyserialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before up_serialinit. + * + ****************************************************************************/ + +void s32k1xx_earlyserialinit(void) +{ + /* NOTE: This function assumes that low level hardware configuration + * -- including all clocking and pin configuration -- was performed by the + * function s32k1xx_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; + s32k1xx_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that s32k1xx_earlyserialinit was called previously. + * + ****************************************************************************/ + +void up_serialinit(void) +{ +#ifdef CONFIG_PM + int ret; + + /* Register to receive power management callbacks */ + + ret = pm_register(&g_serial_pmcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + +#ifdef CONSOLE_DEV + (void)uart_register("/dev/console", &CONSOLE_DEV); +#endif + + /* Register all UARTs */ + + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); +#ifdef TTYS1_DEV + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +#endif +#ifdef TTYS2_DEV + (void)uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef CONSOLE_DEV + struct s32k1xx_uart_s *priv = (struct s32k1xx_uart_s *)CONSOLE_DEV.priv; + uint32_t ie; + + s32k1xx_disableuartint(priv, &ie); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + s32k1xx_lowputc('\r'); + } + + s32k1xx_lowputc(ch); + s32k1xx_restoreuartint(priv, ie); +#endif + + return ch; +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#if CONSOLE_LPUART > 0 + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_lowputc('\r'); + } + + up_lowputc(ch); +#endif + + return ch; +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_serial.h b/arch/arm/src/s32k1xx/s32k1xx_serial.h new file mode 100644 index 0000000000..0a42a6912f --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_serial.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_serial.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_S32K1XX_S32K1XX_SERIAL_H +#define __ARCH_ARM_SRC_S32K1XX_S32K1XX_SERIAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "up_internal.h" +#include "s32k1xx_config.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_earlyserialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before up_serialinit. + * + ****************************************************************************/ + +#ifdef USE_EARLYSERIALINIT +void s32k1xx_earlyserialinit(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_S32K1XX_S32K1XX_SERIAL_H */