diff --git a/arch/arm/include/s32k1xx/s32k11x_irq.h b/arch/arm/include/s32k1xx/s32k11x_irq.h index 2cd7db84686..93c1053aa1f 100644 --- a/arch/arm/include/s32k1xx/s32k11x_irq.h +++ b/arch/arm/include/s32k1xx/s32k11x_irq.h @@ -103,7 +103,7 @@ #define S32K1XX_IRQ_ADC0 (44) /* ADC0 Interrupt */ #define S32K1XX_IRQ_CMP0 (45) /* CMP0 Interrupt */ #define S32K1XX_IRQ_LPUART1 (46) /* LPUART1 Interrupt */ -#define S32K1XX_IRQ_LPUART1 (47) /* LPUART0 Interrupt */ +#define S32K1XX_IRQ_LPUART0 (47) /* LPUART0 Interrupt */ #define S32K1XX_IRQ_NIRQS (48) #define S32K1XX_IRQ_NEXTINT (S32K1XX_IRQ_NIRQS - S32K1XX_IRQ_INTERRUPT) diff --git a/arch/arm/src/s32k1xx/Kconfig b/arch/arm/src/s32k1xx/Kconfig index da1a1900b79..78519772362 100644 --- a/arch/arm/src/s32k1xx/Kconfig +++ b/arch/arm/src/s32k1xx/Kconfig @@ -93,6 +93,16 @@ config S32K1XX_HAVE_SPLL bool default n +# Peripheral Group Selections + +config S32K1XX_HAVE_LPUART + bool + default n + +config S32K1XX_HAVE_LPSPI + bool + default n + # Peripheral Selection menu "S32K1XX Peripheral Selection" @@ -100,28 +110,70 @@ menu "S32K1XX Peripheral Selection" config S32K1XX_LPUART0 bool "LPUART0" default n + select S32K1XX_HAVE_LPUART select LPUART0_SERIALDRIVER config S32K1XX_LPUART1 bool "LPUART1" default n + select S32K1XX_HAVE_LPUART select LPUART1_SERIALDRIVER config S32K1XX_LPUART2 bool "LPUART2" default n + select S32K1XX_HAVE_LPUART select LPUART2_SERIALDRIVER config S32K1XX_LPSPI0 bool "LPSPI0" default n + select S32K1XX_HAVE_LPSPI select SPI config S32K1XX_LPSPI1 bool "LPSPI1" default n + select S32K1XX_HAVE_LPSPI select SPI -endmenu # iMX Peripheral Selection +endmenu # S32K1XX Peripheral Selection + +menu "S32K1xx GPIO Interrupt Configuration" + +config S32K1XX_GPIOIRQ + bool "GPIO pin interrupts" + ---help--- + Enable support for interrupting GPIO pins + +if S32K1XX_GPIOIRQ + +config S32K1XX_PORTAINTS + bool "GPIOA interrupts" + ---help--- + Enable support for 32 interrupts from GPIO port A pins + +config S32K1XX_PORTBINTS + bool "GPIOB interrupts" + ---help--- + Enable support for 32 interrupts from GPIO port B pins + +config S32K1XX_PORTCINTS + bool "GPIOC interrupts" + ---help--- + Enable support for 32 interrupts from GPIO port C pins + +config S32K1XX_PORTDINTS + bool "GPIOD interrupts" + ---help--- + Enable support for 32 interrupts from GPIO port D pins + +config S32K1XX_PORTEINTS + bool "GPIOE interrupts" + ---help--- + Enable support for 32 interrupts from GPIO port E pins + +endif +endmenu # S32K1xx GPIO Interrupt Configuration endif # ARCH_CHIP_S32K1XX diff --git a/arch/arm/src/s32k1xx/Make.defs b/arch/arm/src/s32k1xx/Make.defs index 8a933f80968..7cc45ac82be 100644 --- a/arch/arm/src/s32k1xx/Make.defs +++ b/arch/arm/src/s32k1xx/Make.defs @@ -53,7 +53,24 @@ endif # Source files common to all S32K1xx chip families. CHIP_ASRCS = -CHIP_CSRCS = s32k1xx_start.c s32k1xx_clockconfig.c +CHIP_CSRCS = s32k1xx_start.c s32k1xx_lowputc.c s32k1xx_clockconfig.c +CHIP_CSRCS += s32k1xx_pin.c + +ifeq ($(CONFIG_S32K1XX_HAVE_LPUART),y) +CHIP_CSRCS += s32k1xx_serial.c +endif + +ifeq ($(CONFIG_S32K1XX_GPIOIRQ),y) +CHIP_CSRCS += s32k1xx_pinirq.c +endif + +ifeq ($(CONFIG_S32K1XX_DMA),y) +CHIP_CSRCS += s32k1xx_pindma.c +endif + +ifeq ($(CONFIG_DEBUG_GPIO_INFO),y) +CHIP_CSRCS += s32k1xx_pindump.c +endif # Source files specific to the ARM CPU family and to the S32K1xx chip family diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_gpio.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_gpio.h index 1b85dfb88bc..2638e0d87c8 100644 --- a/arch/arm/src/s32k1xx/hardware/s32k1xx_gpio.h +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_gpio.h @@ -56,8 +56,6 @@ /* GPIO Register Offsets *************************************************************/ -#define S32K1XX_GPIO_OFFSET(g) ((g) << 6) - #define S32K1XX_GPIO_PDOR_OFFSET 0x0000 /* Port Data Output Register */ #define S32K1XX_GPIO_PSOR_OFFSET 0x0004 /* Port Set Output Register */ #define S32K1XX_GPIO_PCOR_OFFSET 0x0008 /* Port Clear Output Register */ @@ -68,8 +66,6 @@ /* GPIO Register Addresses ***********************************************************/ -#define S32K1XX_GPIO_BASE(g) (S32K1XX_GPIO_BASE + S32K1XX_GPIO_OFFSET(g)) - #define S32K1XX_GPIO_PDOR(g) (S32K1XX_GPIO_BASE(g) + S32K1XX_GPIO_PDOR_OFFSET) #define S32K1XX_GPIO_PSOR(g) (S32K1XX_GPIO_BASE(g) + S32K1XX_GPIO_PSOR_OFFSET) #define S32K1XX_GPIO_PCOR(g) (S32K1XX_GPIO_BASE(g) + S32K1XX_GPIO_PCOR_OFFSET) diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h index b8ac2e94541..a7d3635222a 100644 --- a/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_lpuart.h @@ -275,7 +275,7 @@ # 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_SHIFT (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 */ diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_memorymap.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_memorymap.h index 416f9d074fe..6767e1dee36 100644 --- a/arch/arm/src/s32k1xx/hardware/s32k1xx_memorymap.h +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_memorymap.h @@ -77,11 +77,12 @@ #define S32K1XX_CMU1_BASE 0x4003f000 /* Clock Monitor Unit 1 */ #define S32K1XX_LPTMR0_BASE 0x40040000 /* Low-power timer 0 */ #define S32K1XX_SIM_BASE 0x40048000 /* System integration module */ -#define S32K1XX_PORTA_BASE 0x40049000 /* Port A multiplexing control */ -#define S32K1XX_PORTB_BASE 0x4004a000 /* Port B multiplexing control */ -#define S32K1XX_PORTC_BASE 0x4004b000 /* Port C multiplexing control */ -#define S32K1XX_PORTD_BASE 0x4004c000 /* Port D multiplexing control */ -#define S32K1XX_PORTE_BASE 0x4004d000 /* Port E multiplexing control */ +#define S32K1XX_PORT_BASE(n) (0x40049000 + ((n) << 12)) /* Port n multiplexing control */ +# define S32K1XX_PORTA_BASE 0x40049000 /* Port A multiplexing control */ +# define S32K1XX_PORTB_BASE 0x4004a000 /* Port B multiplexing control */ +# define S32K1XX_PORTC_BASE 0x4004b000 /* Port C multiplexing control */ +# define S32K1XX_PORTD_BASE 0x4004c000 /* Port D multiplexing control */ +# define S32K1XX_PORTE_BASE 0x4004d000 /* Port E multiplexing control */ #define S32K1XX_WDOG_BASE 0x40052000 /* Software watchdog */ #define S32K1XX_SAI0_BASE 0x40054000 /* Synchronous Audio Interface 0 */ #define S32K1XX_SAI1_BASE 0x40055000 /* Synchronous Audio Interface 1 */ @@ -105,7 +106,7 @@ #define S32K1XX_PMC_BASE 0x4007d000 /* Power management controller */ #define S32K1XX_SMC_BASE 0x4007e000 /* System Mode controller */ #define S32K1XX_RCM_BASE 0x4007f000 /* Reset Control Module */ -#define S32K1XX_GPIO_BASE 0x400ff000 /* GPIO controller */ +#define S32K1XX_GPIO_BASE(n) (0x400ff000 +((n) << 6)) /* GPIO controller */ # define S32K1XX_GPIOA_BASE 0x400ff000 /* GPIOA controller */ # define S32K1XX_GPIOB_BASE 0x400ff040 /* GPIOB controller */ # define S32K1XX_GPIOC_BASE 0x400ff080 /* GPIOC controller */ diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_pinmux.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_pinmux.h new file mode 100644 index 00000000000..1c76e76839b --- /dev/null +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_pinmux.h @@ -0,0 +1,86 @@ +/******************************************************************************************** + * arch/arm/src/s32k1xx/hardware/s32k1xx_pinmux.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_PINMUX_H +#define __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_PINMUX_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +#warning REVISIT +#if 0 /* Need pin multiplexing files */ +/* This file is just a wrapper around pin muxing header files for the S32K1xx family selected + * by the logic in chip.h. + */ + +#if defined(CONFIG_ARCH_CHIP_S32K116) +# include "hardware/s32k116_pinmux.h" +#elif defined(CONFIG_ARCH_CHIP_S32K118) +# include "hardware/s32k118_pinmux.h" +#elif defined(CONFIG_ARCH_CHIP_S32K142) +# include "hardware/s32k142_pinmux.h" +#elif defined(CONFIG_ARCH_CHIP_S32K144) +# include "hardware/s32k144_pinmux.h" +#elif defined(CONFIG_ARCH_CHIP_S32K146) +# include "hardware/s32k146_pinmux.h" +#elif defined(CONFIG_ARCH_CHIP_S32K148) +# include "hardware/s32k148_pinmux.h" +#else +# error "No pin multiplexing for this S32K1xx part" +#endif +#endif + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_PINMUX_H */ diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_port.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_port.h index 77fd6b68609..fb653a4da79 100644 --- a/arch/arm/src/s32k1xx/hardware/s32k1xx_port.h +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_port.h @@ -56,7 +56,7 @@ /* PORT Register Offsets ****************************************************************************/ -#define S32K1XX_PORT_PCR_OFFSET(n) (0 + ((n) << 2) /* Pin Control Register n=0..31 */ +#define S32K1XX_PORT_PCR_OFFSET(n) (0 + ((n) << 2)) /* Pin Control Register n=0..31 */ #define S32K1XX_PORT_GPCLR_OFFSET 0x0080 /* Global Pin Control Low Register */ #define S32K1XX_PORT_GPCHR_OFFSET 0x0084 /* Global Pin Control High Register */ #define S32K1XX_PORT_GICLR_OFFSET 0x0088 /* Global Interrupt Control Low Register */ @@ -68,8 +68,6 @@ /* PORT Register Addresses **************************************************************************/ -#define S32K1XX_PORT_BASE(p) (S32K1XX_PORTA_BASE + ((p) << 2) - #define S32K1XX_PORT_PCR_BASE(p,n) (S32K1XX_PORT_BASE(p) + S32K1XX_PORT_PCR_OFFSET(n)) #define S32K1XX_PORT_GPCLR(p) (S32K1XX_PORT_BASE(p) + S32K1XX_PORT_GPCLR_OFFSET) #define S32K1XX_PORT_GPCHR(p) (S32K1XX_PORT_BASE(p) + S32K1XX_PORT_GPCHR_OFFSET) @@ -142,7 +140,7 @@ #define PORT_PCR_DSE (1 << 6) /* Bit 6: Drive Strength Enable */ #define PORT_PCR_MUX_SHIFT (8) /* Bits 8-10: Pin Mux Control */ #define PORT_PCR_MUX_MASK (7 << PORT_PCR_MUX_SHIFT) -# define PORT_PCR_MUX_DISABLE (0 << PORT_PCR_MUX_SHIFT) /* Alternative 0: Pin disable/analog */ +# define PORT_PCR_MUX_ANALOG (0 << PORT_PCR_MUX_SHIFT) /* Alternative 0: Pin disable/analog */ # define PORT_PCR_MUX_GPIO (1 << PORT_PCR_MUX_SHIFT) /* Alternative 1 (GPIO) */ # define PORT_PCR_MUX_ALT2 (2 << PORT_PCR_MUX_SHIFT) /* Alternative 2 (chip-specific) */ # define PORT_PCR_MUX_ALT3 (3 << PORT_PCR_MUX_SHIFT) /* Alternative 3 (chip-specific) */ @@ -153,15 +151,15 @@ #define PORT_PCR_LK (1 << 15) /* Bit 15: Lock Register */ #define PORT_PCR_IRQC_SHIFT (16) /* Bits 16-19: Interrupt Configuration */ #define PORT_PCR_IRQC_MASK (15 << PORT_PCR_IRQC_SHIFT) -# define PORT_PCR_IRQC_MASK (0 << PORT_PCR_IRQC_SHIFT) /* Interrupt Status Flag (ISF) is disabled */ +# define PORT_PCR_IRQC_DISABLED (0 << PORT_PCR_IRQC_SHIFT) /* Interrupt Status Flag (ISF) is disabled */ # define PORT_PCR_IRQC_DMARISING (1 << PORT_PCR_IRQC_SHIFT) /* ISF flag and DMA request on rising edge */ # define PORT_PCR_IRQC_DMAFALLING (2 << PORT_PCR_IRQC_SHIFT) /* ISF flag and DMA request on falling edge */ # define PORT_PCR_IRQC_DMABOTH (3 << PORT_PCR_IRQC_SHIFT) /* ISF flag and DMA request on either edge */ -# define PORT_PCR_IRQC_INTZERO (8 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt when logic 0 */ -# define PORT_PCR_IRQC_INTRISING (9 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt on rising-edge */ -# define PORT_PCR_IRQC_INTFALLING (10 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt on falling-edge */ -# define PORT_PCR_IRQC_INTEITHER (11 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt on either edge */ -# define PORT_PCR_IRQC_INTONE (12 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt when logic 1 */ +# define PORT_PCR_IRQC_ZERO (8 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt when logic 0 */ +# define PORT_PCR_IRQC_RISING (9 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt on rising-edge */ +# define PORT_PCR_IRQC_FALLING (10 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt on falling-edge */ +# define PORT_PCR_IRQC_BOTH (11 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt on either edge */ +# define PORT_PCR_IRQC_ONE (12 << PORT_PCR_IRQC_SHIFT) /* ISF flag and Interrupt when logic 1 */ #define PORT_PCR_ISF (1 << 24) /* Bit 24: Interrupt Status Flag */ /* Global Pin Control Low Register */ @@ -212,7 +210,7 @@ #define PORT_DFCR_CS (1 << 0) /* Bit 0: Clock Source */ # define PORT_DFCR_BUSCLK (0) /* Digital filters clocked by bus clock */ -# define PORT_DFCR_BUSCLK (1 << 0) /* Digital filters clocked by LPO clock */ +# define PORT_DFCR_LPOPCLK (1 << 0) /* Digital filters clocked by LPO clock */ /* Digital Filter Width Register */ diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_scg.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_scg.h index 3495d55f503..ad4f8484bb4 100644 --- a/arch/arm/src/s32k1xx/hardware/s32k1xx_scg.h +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_scg.h @@ -174,12 +174,13 @@ /* SCG CLKOUT Configuration Register */ -#define SCG_CLKOUTCNFG_SCS_SHIFT (24) /* Bits 24-27: SCG Clkout Select */ -#define SCG_CLKOUTCNFG_SCS_MASK (15 << SCG_CLKOUTCNFG_SCS_SHIFT) -# define SCG_CLKOUTCNFG_SCS_SOSC (1 << SCG_CLKOUTCNFG_SCS_SHIFT) /* System OSC (SOSC_CLK) */ -# define SCG_CLKOUTCNFG_SCS_SIRC (2 << SCG_CLKOUTCNFG_SCS_SHIFT) /* Slow IRC (SIRC_CLK) */ -# define SCG_CLKOUTCNFG_SCS_FIRC (3 << SCG_CLKOUTCNFG_SCS_SHIFT) /* Fast IRC (FIRC_CLK) */ -# define SCG_CLKOUTCNFG_SPLL_FIRC (6 << SCG_CLKOUTCNFG_SCS_SHIFT) /* System PLL (SPLL_CLK) */ +#define SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT (24) /* Bits 24-27: SCG Clkout Select */ +#define SCG_CLKOUTCNFG_CLKOUTSEL_MASK (15 << SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT) +# define SCG_CLKOUTCNFG_CLKOUTSEL(src) ((uint32_t)(src) << SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT) +# define SCG_CLKOUTCNFG_CLKOUTSEL_SOSC (1 << SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT) /* System OSC (SOSC_CLK) */ +# define SCG_CLKOUTCNFG_CLKOUTSEL_SIRC (2 << SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT) /* Slow IRC (SIRC_CLK) */ +# define SCG_CLKOUTCNFG_CLKOUTSEL_FIRC (3 << SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT) /* Fast IRC (FIRC_CLK) */ +# define SCG_CLKOUTCNFG_CLKOUTSEL_SPLL (6 << SCG_CLKOUTCNFG_CLKOUTSEL_SHIFT) /* System PLL (SPLL_CLK) */ /* System OSC Control Status Register */ @@ -195,6 +196,7 @@ #define SCG_SOSCDIV_SOSCDIV1_SHIFT (0) /* Bits 0-2: System OSC Clock Divide 1 */ #define SCG_SOSCDIV_SOSCDIV1_MASK (7 << SCG_SOSCDIV_SOSCDIV1_SHIFT) +# define SCG_SOSCDIV_SOSCDIV1(n) ((uint32_t)(n) << SCG_SOSCDIV_SOSCDIV1_SHIFT) # define SCG_SOSCDIV_SOSCDIV1_DISABLE (0 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Output disabled */ # define SCG_SOSCDIV_SOSCDIV1_DIV1 (1 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 1 */ # define SCG_SOSCDIV_SOSCDIV1_DIV2 (2 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 2 */ @@ -205,6 +207,7 @@ # define SCG_SOSCDIV_SOSCDIV1_DIV64 (7 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 64 */ #define SCG_SOSCDIV_SOSCDIV2_SHIFT (8) /* Bits 8-10: System OSC Clock Divide 2 */ #define SCG_SOSCDIV_SOSCDIV2_MASK (7 << SCG_SOSCDIV_SOSCDIV2_SHIFT) +# define SCG_SOSCDIV_SOSCDIV2(n) ((uint32_t)(n) << SCG_SOSCDIV_SOSCDIV2_SHIFT) # define SCG_SOSCDIV_SOSCDIV2_DISABLE (0 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Output disabled */ # define SCG_SOSCDIV_SOSCDIV2_DIV1 (1 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 1 */ # define SCG_SOSCDIV_SOSCDIV2_DIV2 (2 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 2 */ @@ -220,6 +223,7 @@ #define SCG_SOSCCFG_HGO (1 << 3) /* Bit 3: High Gain Oscillator Select */ #define SCG_SOSCCFG_RANGE_SHIFT (4) /* Bits 4-5: System OSC Range Select */ #define SCG_SOSCCFG_RANGE_MASK (3 << SCG_SOSCCFG_RANGE_SHIFT) +# define SCG_SOSCCFG_RANGE(n) ((uint32_t)(n) << SCG_SOSCCFG_RANGE_SHIFT) # define SCG_SOSCCFG_RANGE_LOW (1 << SCG_SOSCCFG_RANGE_SHIFT) /* Low frequency range */ # define SCG_SOSCCFG_RANGE_MED (2 << SCG_SOSCCFG_RANGE_SHIFT) /* Medium frequency range */ # define SCG_SOSCCFG_RANGE_HIGH (3 << SCG_SOSCCFG_RANGE_SHIFT) /* High frequency range */ @@ -237,6 +241,7 @@ #define SCG_SIRCDIV_SIRCDIV1_SHIFT (0) /* Bits 0-2: Slow IRC Clock Divide 1 */ #define SCG_SIRCDIV_SIRCDIV1_MASK (7 << SCG_SIRCDIV_SIRCDIV1_SHIFT) +# define SCG_SIRCDIV_SIRCDIV1(n) ((uint32_t)(n) << SCG_SIRCDIV_SIRCDIV1_SHIFT) # define SCG_SIRCDIV_SIRCDIV1_DISABLE (0 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Output disabled */ # define SCG_SIRCDIV_SIRCDIV1_DIV1 (1 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 1 */ # define SCG_SIRCDIV_SIRCDIV1_DIV2 (2 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 2 */ @@ -247,6 +252,7 @@ # define SCG_SIRCDIV_SIRCDIV1_DIV64 (7 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 64 */ #define SCG_SIRCDIV_SIRCDIV2_SHIFT (8) /* Bits 8-10: Slow IRC Clock Divide 2 */ #define SCG_SIRCDIV_SIRCDIV2_MASK (7 << SCG_SIRCDIV_SIRCDIV2_SHIFT) +# define SCG_SIRCDIV_SIRCDIV2(n) ((uint32_t)(n) << SCG_SIRCDIV_SIRCDIV2_SHIFT) # define SCG_SIRCDIV_SIRCDIV2_DISABLE (0 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Output disabled */ # define SCG_SIRCDIV_SIRCDIV2_DIV1 (1 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 1 */ # define SCG_SIRCDIV_SIRCDIV2_DIV2 (2 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 2 */ @@ -275,6 +281,7 @@ #define SCG_FIRCDIV_FIRCDIV1_SHIFT (0) /* Bits 0-2: Fast IRC Clock Divide 1 */ #define SCG_FIRCDIV_FIRCDIV1_MASK (7 << SCG_FIRCDIV_FIRCDIV1_SHIFT) +# define SCG_FIRCDIV_FIRCDIV1(n) ((uint32_t)(n) << SCG_FIRCDIV_FIRCDIV1_SHIFT) # define SCG_FIRCDIV_FIRCDIV1_DISABLE (0 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Output disabled */ # define SCG_FIRCDIV_FIRCDIV1_DIV1 (1 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 1 */ # define SCG_FIRCDIV_FIRCDIV1_DIV2 (2 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 2 */ @@ -285,6 +292,7 @@ # define SCG_FIRCDIV_FIRCDIV1_DIV64 (7 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 64 */ #define SCG_FIRCDIV_FIRCDIV2_SHIFT (8) /* Bits 8-10: Fast IRC Clock Divide 2 */ #define SCG_FIRCDIV_FIRCDIV2_MASK (7 << SCG_FIRCDIV_FIRCDIV2_SHIFT) +# define SCG_FIRCDIV_FIRCDIV2(n) ((uint32_t)(n) << SCG_FIRCDIV_FIRCDIV2_SHIFT) # define SCG_FIRCDIV_FIRCDIV2_DISABLE (0 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Output disabled */ # define SCG_FIRCDIV_FIRCDIV2_DIV1 (1 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 1 */ # define SCG_FIRCDIV_FIRCDIV2_DIV2 (2 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 2 */ @@ -313,6 +321,7 @@ #define SCG_SPLLDIV_SPLLDIV1_SHIFT (0) /* Bits 0-2: System PLL Clock Divide 1 */ #define SCG_SPLLDIV_SPLLDIV1_MASK (7 << SCG_SPLLDIV_SPLLDIV1_SHIFT) +# define SCG_SPLLDIV_SPLLDIV1(n) ((uint32_t)(n) << SCG_SPLLDIV_SPLLDIV1_SHIFT) # define SCG_SPLLDIV_SPLLDIV1_DISABLE (0 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Output disabled */ # define SCG_SPLLDIV_SPLLDIV1_DIV1 (1 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 1 */ # define SCG_SPLLDIV_SPLLDIV1_DIV2 (2 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 2 */ @@ -323,6 +332,7 @@ # define SCG_SPLLDIV_SPLLDIV1_DIV64 (7 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 64 */ #define SCG_SPLLDIV_SPLLDIV2_SHIFT (8) /* Bits 8-10: System PLL Clock Divide 2 */ #define SCG_SPLLDIV_SPLLDIV2_MASK (7 << SCG_SPLLDIV_SPLLDIV2_SHIFT) +# define SCG_SPLLDIV_SPLLDIV2(n) ((uint32_t)(n) << SCG_SPLLDIV_SPLLDIV2_SHIFT) # define SCG_SPLLDIV_SPLLDIV2_DISABLE (0 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Output disabled */ # define SCG_SPLLDIV_SPLLDIV2_DIV1 (1 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 1 */ # define SCG_SPLLDIV_SPLLDIV2_DIV2 (2 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 2 */ diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h new file mode 100644 index 00000000000..f0fc3d22ab2 --- /dev/null +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h @@ -0,0 +1,122 @@ +/******************************************************************************************** + * arch/arm/src/s32k1xx/chip/s32k1xx_smc.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_SMC_H +#define __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_SMC_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include +#include + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ + +/* SMC Register Offsets *********************************************************************/ + +#define S32K1XX_SMC_VERID_OFFSET 0x0000 /* SMC Version ID Register */ +#define S32K1XX_SMC_PARAM_OFFSET 0x0004 /* SMC Parameter Register */ +#define S32K1XX_SMC_PMPROT_OFFSET 0x0008 /* SMC Power Mode Protection register */ +#define S32K1XX_SMC_PMCTRL_OFFSET 0x000c /* SMC Power Mode Control register */ +#define S32K1XX_SMC_STOPCTRL_OFFSET 0x0010 /* SMC Stop Control Register */ +#define S32K1XX_SMC_PMSTAT_OFFSET 0x0014 /* SMC Power Mode Status register */ + +/* SMC Register Addresses *******************************************************************/ + +#define S32K1XX_SMC_VERID (S32K1XX_SMC_BASE + S32K1XX_SMC_VERID_OFFSET) +#define S32K1XX_SMC_PARAM (S32K1XX_SMC_BASE + S32K1XX_SMC_PARAM_OFFSET) +#define S32K1XX_SMC_PMPROT (S32K1XX_SMC_BASE + S32K1XX_SMC_PMPROT_OFFSET) +#define S32K1XX_SMC_PMCTRL (S32K1XX_SMC_BASE + S32K1XX_SMC_PMCTRL_OFFSET) +#define S32K1XX_SMC_STOPCTRL (S32K1XX_SMC_BASE + S32K1XX_SMC_STOPCTRL_OFFSET) +#define S32K1XX_SMC_PMSTAT (S32K1XX_SMC_BASE + S32K1XX_SMC_PMSTAT_OFFSET) + +/* SMC Register Bitfield Definitions ********************************************************/ + +/* SMC Version ID Register */ + +#define SMC_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number */ +#define SMC_VERID_FEATURE_MASK (0xffff << SMC_VERID_FEATURE_SHIFT) +# define SMC_VERID_FEATURE_STD (1 << SMC_VERID_FEATURE_SHIFT) /* Standard feature set */ +#define SMC_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number */ +#define SMC_VERID_MINOR_MASK (0xff << SMC_VERID_MINOR_SHIFT) +#define SMC_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number */ +#define SMC_VERID_MAJOR_MASK (0xff << SMC_VERID_MAJOR_SHIFT) + + +/* SMC Parameter Register */ + +#define SMC_PARAM_EHSRUN (1 << 0) /* Bit 0: Existence of HSRUN feature */ +#define SMC_PARAM_ELLS (1 << 3) /* Bit 3: Existence of LLS feature */ +#define SMC_PARAM_ELLS2 (1 << 5) /* Bit 5: Existence of LLS2 feature */ +#define SMC_PARAM_EVLLS0 (1 << 6) /* Bit 6: Existence of VLLS0 feature */ + +/* SMC Power Mode Protection register */ + +#define SMC_PMPROT_AVLP (1 << 5) /* Bit 5: Allow Very-Low-Power Modes */ +#define SMC_PMPROT_AHSRUN (1 << 7) /* Bit 7: Allow High Speed Run mode */ + +/* SMC Power Mode Control register */ + +#define SMC_PMCTRL_STOPM_SHIFT (0) /* Bits 0-2: Stop Mode Control */ +#define SMC_PMCTRL_STOPM_MASK (7 << SMC_PMCTRL_STOPM_SHIFT) +# define SMC_PMCTRL_STOPM_STOP (0 << SMC_PMCTRL_STOPM_SHIFT) /* Normal Stop */ +# define SMC_PMCTRL_STOPM_VLPS (2 << SMC_PMCTRL_STOPM_SHIFT) /* Very-Low-Power Stop */ +#define SMC_PMCTRL_VLPSA (1 << 3) /* Bit 3: Very Low Power Stop Aborted */ +#define SMC_PMCTRL_RUNM_SHIFT (5) /* Bits 5-6: Run Mode Control */ +#define SMC_PMCTRL_RUNM_MASK (3 << SMC_PMCTRL_RUNM_SHIFT) +# define SMC_PMCTRL_RUNM_RUN (0 << SMC_PMCTRL_RUNM_SHIFT) /* Normal Run mode */ +# define SMC_PMCTRL_RUNM_VLPR (2 << SMC_PMCTRL_RUNM_SHIFT) /* Very-Low-Power Run mode */ +# define SMC_PMCTRL_RUNM_HSRUN (3 << SMC_PMCTRL_RUNM_SHIFT) /* High Speed Run mode */ + +/* SMC Stop Control Register */ + +#define SMC_STOPCTRL_STOPO_SHIFT (6) /* Bits 6-7: Stop Option */ +#define SMC_STOPCTRL_STOPO_MASK (3 << SMC_STOPCTRL_STOPO_SHIFT) +# define SMC_STOPCTRL_STOPO_STOP1 (1 << SMC_STOPCTRL_STOPO_SHIFT) /* Stop with systclk+busclk disabled */ +# define SMC_STOPCTRL_STOPO_STOP2 (2 << SMC_STOPCTRL_STOPO_SHIFT) /* Stop with systclk disabled */ + +/* SMC Power Mode Status register */ + +#define SMC_PMSTAT_PMSTAT_SHIFT (0) /* Bits 0-7: Power Mode Status */ +#define SMC_PMSTAT_PMSTAT_MASK (0xff << SMC_PMSTAT_PMSTAT_SHIFT) +# define SMC_PMSTAT_PMSTAT_RUN (0x01 << SMC_PMSTAT_PMSTAT_SHIFT) /* Current power mode is RUN */ +# define SMC_PMSTAT_PMSTAT_VLPR (0x04 << SMC_PMSTAT_PMSTAT_SHIFT) /* Current power mode is VLPR */ +# define SMC_PMSTAT_PMSTAT_VLPS (0x10 << SMC_PMSTAT_PMSTAT_SHIFT) /* Current power mode is VLPS */ +# define SMC_PMSTAT_PMSTAT_HSRUN (0x80 << SMC_PMSTAT_PMSTAT_SHIFT) /* Current power mode is HSRUN */ + +#endif /* __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_SMC_H */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c b/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c index 5b3e5d4f2c7..0d6f61fdadc 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c +++ b/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c @@ -31,8 +31,8 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * Portions of the logic within this file derives from NXP sample code for - * the S32K1xx MCUs. That sample code has this licensing information: + * Much of the logic within this file derives heavily from NXP sample code + * for the S32K1xx MCUs. That sample code has this licensing information: * * Copyright (c) 2013 - 2015, Freescale Semiconductor, Inc. * Copyright 2016-2018 NXP @@ -68,14 +68,1206 @@ #include "up_internal.h" #include "hardware/s32k1xx_scg.h" +#include "hardware/s32k1xx_smc.h" #include "s32k1xx_clockconfig.h" #include /* Include last. May have dependencies */ +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Temporary system clock source configurations. */ + +#define TMP_SIRC_CLK 0 +#define TMP_FIRC_CLK 1 +#define TMP_SOSC_CLK 2 +#define TMP_SPLL_CLK 3 + +#define TMP_SYS_DIV 0 +#define TMP_BUS_DIV 1 +#define TMP_SLOW_DIV 2 + +#define TMP_SYS_CLK_NO 4 +#define TMP_SYS_DIV_NO 3 + +/* Supports arrays of maximum clock frequencies of system clocks in all + * power modes + */ + +#define MODES_MAX_NO 7 +#define SYS_CLK_MAX_NO 3 +#define CORE_CLK_INDEX 0 +#define BUS_CLK_INDEX 1 +#define SLOW_CLK_INDEX 2 + +/* Time to wait for clocks to stabilize, ie., number of cycles when core + * runs at maximum speed - 112 MHz. + */ + +#define SIRC_STABILIZATION_TIMEOUT 100 +#define FIRC_STABILIZATION_TIMEOUT 20 +#define SOSC_STABILIZATION_TIMEOUT 3205000 +#define SPLL_STABILIZATION_TIMEOUT 1000 + +/* System PLL reference clock after SCG_SPLLCFG[PREDIV] should be in the range of + * SCG_SPLL_REF_MIN to SCG_SPLL_REF_MAX. + */ + +#define SCG_SPLL_REF_MIN 8000000 +#define SCG_SPLL_REF_MAX 32000000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum scg_system_clock_mode_e +{ + SCG_SYSTEM_CLOCK_MODE_CURRENT = 0, /* Current mode. */ + SCG_SYSTEM_CLOCK_MODE_RUN = 1, /* Run mode. */ + SCG_SYSTEM_CLOCK_MODE_VLPR = 2, /* Very Low Power Run mode. */ + SCG_SYSTEM_CLOCK_MODE_HSRUN = 3, /* High Speed Run mode. */ + SCG_SYSTEM_CLOCK_MODE_NONE /* MAX value. */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const enum scg_system_clock_div_e + g_tmp_sysclk[TMP_SYS_CLK_NO][TMP_SYS_DIV_NO] = +{ + { + SCG_SYSTEM_CLOCK_DIV_BY_1, /* SIRC SYS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_1, /* SIRC BUS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_2 /* SIRC SLOW_CLK divider */ + }, + { + SCG_SYSTEM_CLOCK_DIV_BY_1, /* FIRC SYS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_2, /* FIRC BUS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_4 /* FIRC SLOW_CLK divider */ + }, + { + SCG_SYSTEM_CLOCK_DIV_BY_1, /* SOSC SYS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_2, /* SOSC BUS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_2 /* SOSC SLOW_CLK divider */ + }, + { + SCG_SYSTEM_CLOCK_DIV_BY_3, /* SPLL SYS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_2, /* SPLL BUS_CLK divider */ + SCG_SYSTEM_CLOCK_DIV_BY_2 /* SPLL SLOW_CLK divider */ + } +}; + +/* The maximum clock frequencies of system clocks in all power modes */ + +static const uint32_t g_vlpr_maxsysclks[MODES_MAX_NO][SYS_CLK_MAX_NO] = +{/* SYS_CLK BUS_CLK SLOW_CLK */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is SOSC */ + { 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is SIRC */ + { 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is FIRC */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 4000000ul, 4000000ul, 1000000ul }, /* Maximum frequencies when system clock is SPLL */ +}; + +static const uint32_t g_run_maxsysclks[MODES_MAX_NO][SYS_CLK_MAX_NO] = +{/* SYS_CLK BUS_CLK SLOW_CLK */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 80000000ul, 48000000ul, 26670000ul }, /* Maximum frequencies when system clock is SOSC */ + { 80000000ul, 48000000ul, 26670000ul }, /* Maximum frequencies when system clock is SIRC */ + { 80000000ul, 48000000ul, 26670000ul }, /* Maximum frequencies when system clock is FIRC */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 80000000ul, 40000000ul, 26670000ul }, /* Maximum frequencies when system clock is SPLL */ +}; +#ifdef CONFIG_S32K1XX_HAVE_HSRUN +static const uint32_t g_hsrun_maxsysclks[MODES_MAX_NO][SYS_CLK_MAX_NO] = +{/* SYS_CLK BUS_CLK SLOW_CLK */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is SOSC */ + { 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is SIRC */ + { 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is FIRC */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 0ul, 0ul, 0ul }, /* Invalid entry */ + { 112000000ul, 56000000ul, 28000000ul }, /* Maximum frequencies when system clock is SPLL */ +}; +#endif + +#if 0 /* Not used */ +static uint32_t g_rtc_clkin; /* RTC CLKIN clock */ +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: s32k1xx_get_scgclk_source + * + * Description: + * Gets SCG current system clock source + * + * Input Parameters: + * None + * + * Returned Value: + * The current system clock source. + * + *****************************************************************************/ + +static inline uint32_t s32k1xx_get_scgclk_source(void) +{ + return ((getreg32(S32K1XX_SCG_CSR) & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT); +} + +/**************************************************************************** + * Name: s32k1xx_get_runmode + * + * Description: + * Get the current running mode. + * + * Input Parameters: + * None + * + * Returned Value: + * The current running mode. + * + *****************************************************************************/ + +static enum scg_system_clock_mode_e s32k1xx_get_runmode(void) +{ + enum scg_system_clock_mode_e mode; + + /* Get the current running mode */ + + switch (getreg32(S32K1XX_SMC_PMSTAT) & SMC_PMSTAT_PMSTAT_MASK) + { + /* Run mode */ + + case SMC_PMSTAT_PMSTAT_RUN: + mode = SCG_SYSTEM_CLOCK_MODE_RUN; + break; + + /* Very low power run mode */ + + case SMC_PMSTAT_PMSTAT_VLPR: + mode = SCG_SYSTEM_CLOCK_MODE_VLPR; + break; + + /* Hight speed run mode */ + + case SMC_PMSTAT_PMSTAT_HSRUN: + mode = SCG_SYSTEM_CLOCK_MODE_HSRUN; + break; + + /* This should never happen - core has to be in some run mode to + * execute code + */ + + case SMC_PMSTAT_PMSTAT_VLPS: + default: + mode = SCG_SYSTEM_CLOCK_MODE_NONE; + break; + } + + return mode; +} + +/**************************************************************************** + * Name: s32k1xx_get_soscfreq + * + * Description: + * Gets SCG System OSC clock frequency (SOSC). + * + * Input Parameters: + * None + * + * Returned Value: + * The SOSC frequency. Zero is returned if the SOSC is invalid. + * + *****************************************************************************/ + +static uint32_t s32k1xx_get_soscfreq(void) +{ + /* Check if the SOSC is valid */ + + if ((getreg32(S32K1XX_SCG_SOSCCSR) & SCG_SOSCCSR_SOSCVLD) != 0) + { + return BOARD_XTAL_FREQUENCY; + } + else + { + return 0; + } +} + +/**************************************************************************** + * Name: s32k1xx_get_sircfreq + * + * Description: + * Gets SCG Slow IRC clock frequency (SIRC). + * + * Input Parameters: + * None + * + * Returned Value: + * The SIRC frequency. Zero is returned if the SIRC is invalid. + * + *****************************************************************************/ + +static uint32_t s32k1xx_get_sircfreq(void) +{ + /* Check if the SIRC is valid */ + + if ((getreg32(S32K1XX_SCG_SIRCCSR) & SCG_SIRCCSR_SIRCVLD) != 0) + { + /* Only high range is supported */ + + if ((getreg32(S32K1XX_SCG_SIRCCFG) & SCG_SIRCCFG_RANGE) != 0) + { + return SCG_SIRQ_HIGHRANGE_FREQUENCY; + } + } + + return 0; +} + +/**************************************************************************** + * Name: s32k1xx_get_fircfreq + * + * Description: + * Gets SCG Fast IRC clock frequency (FIRC). + * + * Input Parameters: + * None + * + * Returned Value: + * The FIRC frequency. Zero is returned if the FIRC is invalid. + * + *****************************************************************************/ + +static uint32_t s32k1xx_get_fircfreq(void) +{ + /* Check if the FIRC is valid */ + + if ((getreg32(S32K1XX_SCG_FIRCCSR) & SCG_FIRCCSR_FIRCVLD) != 0) + { + return SCG_FIRQ_FREQUENCY0; + } + else + { + return 0; + } +} + +/**************************************************************************** + * Name: s32k1xx_get_spllfreq + * + * Description: + * Gets SCG System PLL clock frequency (SPLL). + * + * Input Parameters: + * None + * + * Returned Value: + * The SPLL frequency. Zero is returned if the SPLL is invalid. + * + *****************************************************************************/ + +#ifdef CONFIG_S32K1XX_HAVE_SPLL +static uint32_t s32k1xx_get_spllfreq(void) +{ + uint32_t freq; + uint32_t regval; + uint32_t prediv; + uint32_t mult; + uint32_t ret; + + /* Check if the SPLL is valid */ + + if ((getreg32(S32K1XX_SCG_SPLLCSR) & SCG_SPLLCSR_SPLLVLD) != 0) + { + /* Get System Oscillator frequency. */ + + freq = s32k1xx_get_soscfreq(); + if (freq != 0) + { + regval = getreg32(S32K1XX_SCG_SPLLCFG); + prediv = ((regval & SCG_SPLLCFG_PREDIV_MASK) >> SCG_SPLLCFG_PREDIV_SHIFT) + 1; + mult = ((regval & SCG_SPLLCFG_MULT_MASK) >> SCG_SPLLCFG_MULT_SHIFT) + 16; + + freq /= prediv; + freq *= mult; + freq >>= 1; /* Divide VCO by 2. */ + } + + return freq; + } + else + { + return 0; + } +} +#endif + +/**************************************************************************** + * Name: s32k1xx_get_srcfreq + * + * Description: + * Return the clock source frequency. + * + * Input Parameters: + * src - Identities the clock source + * + * Returned Values: + * The requested clock source frequency. Zero is returned on any error. + * + *****************************************************************************/ + +static uint32_t s32k1xx_get_srcfreq(enum scg_system_clock_src_e src) +{ + uint32_t srcfreq = 0; + + switch (src) + { + case SCG_SYSTEM_CLOCK_SRC_SYS_OSC: + srcfreq = s32k1xx_get_soscfreq(); + break; + + case SCG_SYSTEM_CLOCK_SRC_SIRC: + srcfreq = s32k1xx_get_sircfreq(); + break; + + case SCG_SYSTEM_CLOCK_SRC_FIRC: + srcfreq = s32k1xx_get_fircfreq(); + break; + +#ifdef CONFIG_S32K1XX_HAVE_SPLL + case SCG_SYSTEM_CLOCK_SRC_SYS_PLL: + srcfreq = s32k1xx_get_spllfreq(); + break; +#endif + + default: + break; + } + + return srcfreq; +} +/**************************************************************************** + * Name: s32k1xx_set_sysclk_configuration + * + * Description: + * This function sets the system configuration for the specified mode. + * + * Input Parameters: + * mode - + * config - + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +static int s32k1xx_set_sysclk_configuration(enum scg_system_clock_mode_e mode, + const struct scg_system_clock_config_s *config) +{ + uint32_t srcfreq = 0; + uint32_t sysfreq_mul = ((uint32_t)config->divcore) + 1; + uint32_t busfreq_mul = (((uint32_t)config->divcore) + 1) * (((uint32_t)config->divbus) + 1); + uint32_t slowfreq_mul = (((uint32_t)config->divcore) + 1) * (((uint32_t)config->divslow) + 1); + uint32_t regval; + int ret = OK; + + DEBUGASSERT(mode != SCG_SYSTEM_CLOCK_MODE_CURRENT); + + srcfreq = s32k1xx_get_srcfreq(config->src) >> 4; + + switch (mode) + { + case SCG_SYSTEM_CLOCK_MODE_RUN: /* Run mode */ + /* Verify the frequencies of sys, bus and slow clocks. */ + + if ((srcfreq > + (sysfreq_mul * (g_run_maxsysclks[(uint32_t)config->src][CORE_CLK_INDEX] >> 4))) || + (srcfreq > + (busfreq_mul * (g_run_maxsysclks[(uint32_t)config->src][BUS_CLK_INDEX] >> 4))) || + (srcfreq > + (slowfreq_mul * (g_run_maxsysclks[(uint32_t)config->src][SLOW_CLK_INDEX] >> 4)))) + { + /* Configuration for the next system clock source is not valid. */ + + ret = -EINVAL; + } + else + { + regval = (((uint32_t)config->src << SCG_RCCR_SCS_SHIFT) | + SCG_RCCR_DIVCORE(config->divcore) | + SCG_RCCR_DIVBUS(config->divbus) | + SCG_RCCR_DIVSLOW(config->divslow)); + putreg32(regval, S32K1XX_SCG_RCCR); + } + break; + + case SCG_SYSTEM_CLOCK_MODE_VLPR: /* Very Low Power Run mode */ + DEBUGASSERT(SCG_SYSTEM_CLOCK_SRC_SIRC == config->src); + + /* Verify the frequencies of sys, bus and slow clocks. */ + + if ((srcfreq > + (sysfreq_mul * (g_vlpr_maxsysclks[(uint32_t)config->src][CORE_CLK_INDEX] >> 4))) || + (srcfreq > + (busfreq_mul * (g_vlpr_maxsysclks[(uint32_t)config->src][BUS_CLK_INDEX] >> 4))) || + (srcfreq > + (slowfreq_mul * (g_vlpr_maxsysclks[(uint32_t)config->src][SLOW_CLK_INDEX] >> 4)))) + { + /* Configuration for the next system clock source is not valid. */ + + ret = -EINVAL; + } + else + { + regval = (((uint32_t)config->src << SCG_VCCR_SCS_SHIFT) | + SCG_VCCR_DIVCORE(config->divcore) | + SCG_VCCR_DIVBUS(config->divbus) | + SCG_VCCR_DIVSLOW(config->divslow)); + putreg32(regval, S32K1XX_SCG_VCCR); + } + break; + +#ifdef CONFIG_S32K1XX_HAVE_HSRUN + case SCG_SYSTEM_CLOCK_MODE_HSRUN: /*!< High Speed Run mode. */ + DEVBUGASSERT(SCG_SYSTEM_CLOCK_SRC_FIRC == config->src || + SCG_SYSTEM_CLOCK_SRC_SYS_PLL == config->src); + + /* Verify the frequencies of sys, bus and slow clocks. */ + + if ((srcfreq > + (sysfreq_mul * (g_hsrun_maxsysclks[(uint32_t)config->src][CORE_CLK_INDEX] >> 4))) || + (srcfreq > + (busfreq_mul * (g_hsrun_maxsysclks[(uint32_t)config->src][BUS_CLK_INDEX] >> 4))) || + (srcfreq > + (slowfreq_mul * (g_hsrun_maxsysclks[(uint32_t)config->src][SLOW_CLK_INDEX] >> 4)))) + { + /* Configuration for the next system clock source is not valid. */ + + ret = -EINVAL; + } + else + { + SCG_SetHsrunClockControl((uint32_t)config->src, + (uint32_t)config->divcore, + (uint32_t)config->divbus, + (uint32_t)config->divslow); + } + break; +#endif + default: + /* Invalid mode */ + + DEBUGPANIC(); + break; + } + + return ret; +} + +/**************************************************************************** + * Name: s32k1xx_transition_systemclock + * + * Description: + * Transition to a new system clock. + * + * Input Parameters: + * cfg - Describes the new system clock configuration + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +static int +s32k1xx_transition_systemclock(const struct scg_system_clock_config_s *cfg) +{ + enum scg_system_clock_mode_e run_mode; + uint32_t timeout; + int ret = OK; + + DEBUGASSERT(cfg != NULL && cfg->src != SCG_SYSTEM_CLOCK_SRC_NONE); + + /* Get and convert Run mode from SMC to SCG defines */ + + run_mode = s32k1xx_get_runmode(); + + /* Check the current mode */ + + DEBUGASSERT(run_mode != SCG_SYSTEM_CLOCK_MODE_NONE); + + /* Update run mode configuration */ + + ret = s32k1xx_set_sysclk_configuration(run_mode, cfg); + if (ret == OK) + { + /* Wait for system clock to transition. */ + +#warning REVISIT +#ifdef ERRATA_E10777 + timeout = 10; +#else + timeout = 1; +#endif + + do + { + timeout--; + } + while ((s32k1xx_get_scgclk_source() != ((uint32_t)cfg->src)) && (timeout > 0U)); + + if (timeout == 0) + { + ret = -ETIMEDOUT; + } + } + + return ret; +} + +/**************************************************************************** + * Name: s32k1xx_firc_config + * + * Description: + * Configures FIRC module based on provided configuration. + * + * Input Parameters: + * firccfg - Describes the desired FORC configuration. + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +static int s32k1xx_firc_config(bool enable, + const struct scg_firc_config_s *firccfg) +{ + uint32_t regval; + int32_t timeout; + int ret = OK; + + DEBUGASSERT(firccfg != NULL); + + /* If clock is used by system, return error. */ + + regval = getreg32(S32K1XX_SCG_FIRCCSR); + if ((regval & SCG_FIRCCSR_FIRCSEL) != 0) + { + ret = -EBUSY; + } + + /* Disable the FIRC */ + + else + { + /* Clear LK bit field */ + + regval &= ~SCG_FIRCCSR_LK; + putreg32(regval, S32K1XX_SCG_FIRCCSR); + + /* Disable monitor, disable clock and clear error. */ + + putreg32(SCG_FIRCCSR_FIRCERR, S32K1XX_SCG_FIRCCSR); + } + + /* Configure FIRC. */ + + if (enable && (ret == OK)) + { + /* Now start to set up FIRC clock. */ + + /* Step 1. Setup dividers. */ + + regval = SCG_FIRCDIV_FIRCDIV1(firccfg->div1) | + SCG_FIRCDIV_FIRCDIV2(firccfg->div2); + putreg32(regval, S32K1XX_SCG_FIRCDIV); + + /* Step 2. Set FIRC configuration. */ + + regval = (firccfg->range == 0 ? 0 : SCG_FIRCCFG_48MHZ); + putreg32(regval, S32K1XX_SCG_FIRCCFG); + + /* Step 3. Enable clock, config regulator and locking feature. */ + + regval = SCG_FIRCCSR_FIRCEN | + firccfg->regulator ? 0 : SCG_FIRCCSR_FIRCREGOFF | + firccfg->locked ? SCG_FIRCCSR_LK : 0; + putreg32(regval, S32K1XX_SCG_FIRCCSR); + + /* Wait for FIRC to initialize */ + + for (timeout = FIRC_STABILIZATION_TIMEOUT; + s32k1xx_get_fircfreq() == 0 && timeout > 0; + timeout--) + { + } + + if (timeout <= 0) + { + ret = -ETIMEDOUT; + } + } + + return ret; +} + +/**************************************************************************** + * Name: s32k11_firc_clocksource + * + * Description: + * Configure to the FIRC clock source. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +static int s32k11_firc_clocksource(void) +{ + struct scg_system_clock_config_s firccfg; + int ret = OK; + + /* If the current system clock source is not FIRC: + * 1. Enable FIRC (if it's not enabled) + * 2. Switch to FIRC. + */ + + if (s32k1xx_get_scgclk_source() != ((uint32_t)SCG_SYSTEM_CLOCK_SRC_FIRC)) + { + /* If FIRC is not on, then FIRC is configured with the default + * configuration + */ + + if (s32k1xx_get_fircfreq() == 0) + { + ret = s32k1xx_firc_config(true, NULL); + } + + /* FIRC is enabled, transition the system clock source to FIRC. */ + + if (ret == OK) + { + firccfg.src = SCG_SYSTEM_CLOCK_SRC_FIRC; + firccfg.divcore = g_tmp_sysclk[TMP_FIRC_CLK][TMP_SYS_DIV]; + firccfg.divbus = g_tmp_sysclk[TMP_FIRC_CLK][TMP_BUS_DIV]; + firccfg.divslow = g_tmp_sysclk[TMP_FIRC_CLK][TMP_SLOW_DIV]; + ret = s32k1xx_transition_systemclock(&firccfg); + } + } + + return ret; +} + +/**************************************************************************** + * Name: s32k1xx_sirc_config + * + * Description: + * Configures SIRC module based on provided configuration. + * + * Input Parameters: + * sirccfg - Describes the desired SIRC configuration. + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +/*FUNCTION********************************************************************** + * Function Name : + * Description : + * END**************************************************************************/ +static int s32k1xx_sirc_config(bool enable, + const struct scg_sirc_config_s *sirccfg) +{ + uint32_t regval; + uint32_t timeout; + int ret = OK; + + DEBUGASSERT(sirccfg != NULL); + + /* If clock is used by system, return error. */ + + regval = getreg32(S32K1XX_SCG_SIRCCSR); + if ((regval & SCG_SIRCCSR_SIRCSEL) != 0) + { + ret = -EBUSY; + } + + /* Disable SIRC */ + + else + { + /* Clear LK bit field */ + + regval &= ~SCG_SIRCCSR_LK; + putreg32(regval, S32K1XX_SCG_SIRCCSR); + + /* Disable monitor, disable clock and clear error. */ + + putreg32(0, S32K1XX_SCG_SIRCCSR); + } + + /* Configure SIRC. */ + + if (enable && (ret == OK)) + { + /* Now start to set up SIRC clock. */ + + /* Step 1. Setup dividers. */ + + regval = SCG_SIRCDIV_SIRCDIV1(sirccfg->div1) | + SCG_SIRCDIV_SIRCDIV2(sirccfg->div2); + putreg32(regval, S32K1XX_SCG_SIRCDIV); + + /* Step 2. Set SIRC configuration: frequency range. */ + + regval = (sirccfg->range == 0) ? SCG_SIRCCFG_LOWRANGE : + SCG_SIRCCFG_HIGHRANGE; + putreg32(regval, S32K1XX_SCG_SIRCCFG); + + /* Step 3. Set SIRC control: enable clock, configure source in STOP + * and VLP modes, configure lock feature. + */ + + regval = SCG_SIRCCSR_SIRCEN | + (sirccfg->stopmode == 0) ? 0 : SCG_SIRCCSR_SIRCSTEN | + (sirccfg->lowpower == 0) ? 0 : SCG_SIRCCSR_SIRCLPEN | + (sirccfg->locked == 0) ? 0 : SCG_SIRCCSR_LK; + putreg32(regval, S32K1XX_SCG_SIRCCSR); + + /* Wait for SIRC to initialize */ + + for (timeout = SIRC_STABILIZATION_TIMEOUT; + s32k1xx_get_sircfreq() == 0 && timeout > 0; + timeout--) + { + } + + if (timeout <= 0) + { + ret = -ETIMEDOUT; + } + } + + return ret; +} + +/**************************************************************************** + * Name: s32k1xx_sosc_config + * + * Description: + * CConfigures SOSC module based on provided configuration. + * + * Input Parameters: + * sosccfg - Describes the desired SOSC configuration. + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +static int s32k1xx_sosc_config(bool enable, + const struct scg_sosc_config_s *sosccfg) +{ + uint32_t regval; + uint32_t timeout; + int ret = OK; + + DEBUGASSERT(sosccfg != NULL); + + /* If clock is used by system, return error. */ + + regval = getreg32(S32K1XX_SCG_SOSCCSR); + if ((regval & SCG_SOSCCSR_SOSCSEL) != 0) + { + ret = -EBUSY; + } + + /* Disable SOSC */ + + else + { + /* Clear LK bit field */ + + regval &= ~SCG_SOSCCSR_LK; + putreg32(regval, S32K1XX_SCG_SOSCCSR); + + /* Disable monitor, disable clock and clear error. */ + + putreg32(SCG_SOSCCSR_SOSCERR, S32K1XX_SCG_SOSCCSR); + } + + /* Configure the SOSC */ + + if (enable && (ret == OK)) + { + /* Now start to set up OSC clock */ + + /* Step 1. Setup dividers. */ + + regval = SCG_SOSCDIV_SOSCDIV1(sosccfg->div1) | + SCG_SOSCDIV_SOSCDIV2(sosccfg->div2); + putreg32(regval, S32K1XX_SCG_SOSCDIV); + + /* Step 2. Set OSC configuration. */ + + regval = SCG_SOSCCFG_RANGE(sosccfg->range) | + (sosccfg->gain == 0) ? 0 : SCG_SOSCCFG_HGO | + (sosccfg->extref == 0) ? 0 : SCG_SOSCCFG_EREFS; + putreg32(regval, S32K1XX_SCG_SOSCCFG); + + /* Step 3. Enable clock, configure monitor, lock register. */ + + regval = SCG_SOSCCSR_SOSCEN | sosccfg->locked ? SCG_SOSCCSR_LK : 0; + + switch (sosccfg->mode) + { + case SCG_SOSC_MONITOR_DISABLE: + { + putreg32(regval, S32K1XX_SCG_SOSCCSR); + } + break; + + case SCG_SOSC_MONITOR_INT: + { + regval |= SCG_SOSCCSR_SOSCCM; + putreg32(regval, S32K1XX_SCG_SOSCCSR); + } + break; + + case SCG_SOSC_MONITOR_RESET: + { + regval |= SCG_SOSCCSR_SOSCCM | SCG_SOSCCSR_SOSCCMRE; + putreg32(regval, S32K1XX_SCG_SOSCCSR); + } + break; + + default: + + /* Invalid monitor mode */ + + DEBUGPANIC(); + break; + } + + /* Wait for System OSC to initialize */ + + for (timeout = SOSC_STABILIZATION_TIMEOUT; + s32k1xx_get_soscfreq() == 0 && timeout > 0; + timeout--) + { + } + + if (timeout <= 0) + { + ret = -ETIMEDOUT; + } + } + + return ret; +} + +/**************************************************************************** + * Name: s32k1xx_spll_config + * + * Description: + * Configures SPLL module based on provided configuration. + * + * Input Parameters: + * spllccfg - Describes the desired SPLL configuration. + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +#ifdef CONFIG_S32K1XX_HAVE_SPLL +static int s32k1xx_spll_config(bool enable, + const struct scg_spll_config_s *spllcfg) +{ + uint32_t regval; + uint32_t srcfreq; + uint32_t timeout; + int ret = OK; + + DEBUASSERT(spllcfg != NULL); + + /* If clock is used by system, return error. */ + + regval = getreg32(S32K1XX_SCG_SPLLCSR); + if ((regval & SCG_SPLLCSR_SPLLSEL) != 0) + { + ret = -EBUSY; + } + + /* Disable the SPLL. */ + + else + { + /* Clear LK bit field */ + + regval &= ~SCG_SPLLCSR_LK; + putreg32(regval, S32K1XX_SCG_SPLLCSR); + + /* Disable monitor, disable clock and clear error. */ + + putreg32(SCG_SPLLCSR_SPLLERR, S32K1XX_SCG_SPLLCSR); + } + + /* Configure SPLL */ + + if (enable && (ret == OK)) + { + /* Get clock source frequency. */ + + srcfreq = s32k1xx_get_soscfreq(); + DEBUGASSERT(srcfreq != 0); + + /* Pre-divider checking. */ + + srcfreq /= (((uint32_t)spllcfg->prediv) + 1); + DEBUGASSERT(srcfreq >= SCG_SPLL_REF_MIN && srcfreq <= SCG_SPLL_REF_MAX); + + /* Now start to set up PLL clock. */ + + regval = SCG_SPLLDIV_SPLLDIV1(spllcfg->div1) | + SCG_SPLLDIV_SPLLDIV2(spllcfg->div2); + putreg32(regval, S32K1XX_SCG_SPLLDIV); + + /* Step 2. Set PLL configuration. */ + + regval = SCG_SPLLCFG_PREDIV(spllcfg->prediv) | + SCG_SPLLCFG_MULT(spllcfg->mult); + putreg32(regval, S32K1XX_SCG_SPLLCFG); + + /* Step 3. Enable clock, configure monitor, lock register. */ + + regval = SCG_SPLLCSR_SPLLEN | sosccfg->locked ? SCG_SOSCCSR_LK : 0; + + switch (spllcfg->monitorMode) + { + case SCG_SPLL_MONITOR_DISABLE: + { + putreg32(regval, S32K1XX_SCG_SPLLCSR); + } + break; + + case SCG_SPLL_MONITOR_INT: + { + regval |= SCG_SPLLCSR_SPLLCM; + putreg32(regval, S32K1XX_SCG_SPLLCSR); + } + break; + + case SCG_SPLL_MONITOR_RESET: + { + regval |= (SCG_SPLLCSR_SPLLCM | SCG_SPLLCSR_SPLLCMRE); + putreg32(regval, S32K1XX_SCG_SPLLCSR); + } + break; + + default: + /* Invalid monitor mode */ + + DEBUGPANIC(); + break; + } + + /* Wait for System PLL to initialize */ + + for (timeout = SPLL_STABILIZATION_TIMEOUT; + s32k1xx_get_spllfreq() == 0 && timeout > 0; + timeout--) + { + } + + if (timeout <= 0) + { + ret = -ETIMEDOUT; + } + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_configure_scgmodules + * + * Description: + * Configures all modules from SCG (SIRC, FIRC, SOSC and SPLL) + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned a success; A negated errno value is returned on + * any failure. + * + *****************************************************************************/ + +static int s32k1xx_configure_scgmodules(const struct scg_config_s *scgcfg) +{ + struct scg_system_clock_config_s sysclkcfg; + const struct scg_system_clock_config_s *next; + int ret = OK; + + /* Configure all clock sources that are different from the current system + * clock source FIRC (SIRC, SOSC, SPLL). + */ + + ret = s32k1xx_sirc_config(scgcfg->sirc.initialize, &scgcfg->sirc); + if (ret == OK) + { + ret = s32k1xx_sosc_config(scgcfg->sosc.initialize, &scgcfg->sosc); +#ifdef CONFIG_S32K1XX_HAVE_SPLL + if (ret == OK) + { + ret = s32k1xx_spll_config(scgcfg->spll.initialize, &scgcfg->spll); + } +#endif + } + + /* Get the next system clock source */ + + switch (s32k1xx_get_runmode()) + { + case SCG_SYSTEM_CLOCK_MODE_RUN: + { + next = &scgcfg->clockmode.rccr; + } + break; + + case SCG_SYSTEM_CLOCK_MODE_VLPR: + { + next = &scgcfg->clockmode.vccr; + } + break; + +#ifdef CONFIG_S32K1XX_HAVE_HSRUN + case SCG_SYSTEM_CLOCK_MODE_HSRUN: + { + next = &scgcfg->clockmode.hccr; + } + break; +#endif + + default: + DEBUGPANIC(); + next = NULL; + break; + } + + if (ret == OK) + { + /* The current system clock source is FIRC. Verify whether the next + * system clock source is FIRC. + */ + + if (next->src == SCG_SYSTEM_CLOCK_SRC_FIRC) + { + /* If they are the same, search for a temporary system clock source + * (use one of the following sources: SPLL, SOSC, SIRC). Assume + * that a temporary clock is not found ret = -ENOENT. + */ + + ret = -ENOENT; + +#ifdef CONFIG_S32K1XX_HAVE_SPLL + /* SPLL is enabled */ + + if (scgcfg->spll.initialize && (ret == -ENOENT)) + { + sysclkcfg.src = SCG_SYSTEM_CLOCK_SRC_SYS_PLL; + sysclkcfg.divcore = g_tmp_sysclk[TMP_SPLL_CLK][TMP_SYS_DIV]; + sysclkcfg.divbus = g_tmp_sysclk[TMP_SPLL_CLK][TMP_BUS_DIV]; + sysclkcfg.divslow = g_tmp_sysclk[TMP_SPLL_CLK][TMP_SLOW_DIV]; + ret = s32k1xx_transition_systemclock(&sysclkcfg); + } +#endif + + /* SOSC is enabled and SPLL configuration for system clock source is not valid */ + + if (scgcfg->sosc.initialize && (ret == -ENOENT)) + { + sysclkcfg.src = SCG_SYSTEM_CLOCK_SRC_SYS_OSC; + sysclkcfg.divcore = g_tmp_sysclk[TMP_SOSC_CLK][TMP_SYS_DIV]; + sysclkcfg.divbus = g_tmp_sysclk[TMP_SOSC_CLK][TMP_BUS_DIV]; + sysclkcfg.divslow = g_tmp_sysclk[TMP_SOSC_CLK][TMP_SLOW_DIV]; + ret = s32k1xx_transition_systemclock(&sysclkcfg); + } + + /* SIRC is enabled and SOSC configuration for system clock source is not valid */ + + if (scgcfg->sirc.initialize && (ret == -ENOENT)) + { + sysclkcfg.src = SCG_SYSTEM_CLOCK_SRC_SIRC; + sysclkcfg.divcore = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SYS_DIV]; + sysclkcfg.divbus = g_tmp_sysclk[TMP_SIRC_CLK][TMP_BUS_DIV]; + sysclkcfg.divslow = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SLOW_DIV]; + ret = s32k1xx_transition_systemclock(&sysclkcfg); + } + + /* Transitioned to a temporary system clock source. */ + + if (ret == OK) + { + /* Configure the remaining clock source (FIRC). */ + + ret = s32k1xx_firc_config(scgcfg->firc.initialize, &scgcfg->firc); + if (ret == OK) + { + /* Transition to the next system clock source. */ + + sysclkcfg.src = next->src; + sysclkcfg.divcore = next->divcore; + sysclkcfg.divbus = next->divbus; + sysclkcfg.divslow = next->divslow; + ret = s32k1xx_transition_systemclock(&sysclkcfg); + } + } + } + else + { + /* Transition to the next system clock source. */ + + sysclkcfg.src = next->src; + sysclkcfg.divcore = next->divcore; + sysclkcfg.divbus = next->divbus; + sysclkcfg.divslow = next->divslow; + ret = s32k1xx_transition_systemclock(&sysclkcfg); + + if (ret == OK) + { + /* Configure the remaining clock source (FIRC) */ + + ret = s32k1xx_firc_config(scgcfg->firc.initialize, &scgcfg->firc); + } + } + } + + return ret; +} + /**************************************************************************** * Name: s32k1xx_scgconfig * @@ -91,10 +1283,73 @@ * *****************************************************************************/ -static inline int s32k1xx_scgconfig(const struct scg_config_s *scgcfg) +static int s32k1xx_scgconfig(const struct scg_config_s *scgcfg) { -#warning Missing logic - return -ENOSYS; + uint32_t regval; + int ret = OK; + + DEBUGASSERT(scgcfg != NULL); + + /* Configure a temporary system clock source: FIRC */ + + ret = s32k11_firc_clocksource(); + if (ret == OK) + { + /* Configure clock sources from SCG */ + + ret = s32k1xx_configure_scgmodules(scgcfg); + } + + if (ret == OK) + { + /* Configure RTC. */ + +#if 0 /* Not used */ + if (scgcfg->rtc.initialize) + { + /* RTC Clock settings. */ + + g_rtc_clkin = scgcfg->rtc.clkin; + } +#endif + + /* Configure SCG ClockOut. */ + + if (scgcfg->clockout.initialize) + { + /* ClockOut settings. */ + + regval = getreg32(S32K1XX_SCG_CLKOUTCNFG); + regval &= ~SCG_CLKOUTCNFG_CLKOUTSEL_MASK; + regval |= SCG_CLKOUTCNFG_CLKOUTSEL(scgcfg->clockout.source); + putreg32(regval, S32K1XX_SCG_CLKOUTCNFG); + } + + /* Configure SCG clock modes. */ + + if (scgcfg->clockmode.initialize) + { + /* Configure SCG clock modes */ + + ret = s32k1xx_set_sysclk_configuration(SCG_SYSTEM_CLOCK_MODE_RUN, + &scgcfg->clockmode.rccr); + if (ret == OK) + { + ret = s32k1xx_set_sysclk_configuration(SCG_SYSTEM_CLOCK_MODE_VLPR, + &scgcfg->clockmode.vccr); + } + +#ifdef CONFIG_S32K1XX_HAVE_HSRUN + if (ret == OK) + { + ret = s32k1xx_set_sysclk_configuration(SCG_SYSTEM_CLOCK_MODE_HSRUN, + &scgcfg->clockmode.hccr); + } +#endif + } + } + + return ret; } /**************************************************************************** @@ -111,7 +1366,7 @@ static inline int s32k1xx_scgconfig(const struct scg_config_s *scgcfg) * *****************************************************************************/ -static inline void s32k1xx_pccconfig(const struct pcc_config_s *pcccfg) +static void s32k1xx_pccconfig(const struct pcc_config_s *pcccfg) { #warning Missing logic } @@ -130,7 +1385,7 @@ static inline void s32k1xx_pccconfig(const struct pcc_config_s *pcccfg) * *****************************************************************************/ -static inline void s32k1xx_simconfig(const struct sim_clock_config_s *simcfg) +static void s32k1xx_simconfig(const struct sim_clock_config_s *simcfg) { #warning Missing logic } @@ -149,7 +1404,7 @@ static inline void s32k1xx_simconfig(const struct sim_clock_config_s *simcfg) * *****************************************************************************/ -static inline void s32k1xx_pmcconfig(const struct pmc_config_s *pmccfg) +static void s32k1xx_pmcconfig(const struct pmc_config_s *pmccfg) { #warning Missing logic } @@ -223,7 +1478,7 @@ uint32_t s32k1xx_get_coreclk(void) uint32_t coreclk = 0; uint32_t regval; uint32_t divider; -#ifdef CONFIG_ARCH_CHIP_S32K14X +#ifdef CONFIG_S32K1XX_HAVE_SPLL uint32_t prediv; uint32_t mult; #endif @@ -268,7 +1523,7 @@ uint32_t s32k1xx_get_coreclk(void) coreclk = SCG_FIRQ_FREQUENCY0; break; -#ifdef CONFIG_ARCH_CHIP_S32K14X +#ifdef CONFIG_S32K1XX_HAVE_SPLL case 0x6SCG_CSR_SPLL_FIRC: /* System PLL */ /* Coreclock = Fxtal * mult / (2 * prediv) */ @@ -276,7 +1531,7 @@ uint32_t s32k1xx_get_coreclk(void) prediv = ((regval & SCG_SPLLCFG_PREDIV_MASK) >> SCG_SPLLCFG_PREDIV_SHIFT) + 1; mult = ((regval & SCG_SPLLCFG_MULT_MASK) >> SCG_SPLLCFG_MULT_SHIFT) + 16; - coreclk = BOARD_XTAL_FREQUENCY * mult / (2 * prediv); + coreclk = ((BOARD_XTAL_FREQUENCY / 2) * mult) / prediv; break; #endif diff --git a/arch/arm/src/s32k1xx/s32k1xx_pin.c b/arch/arm/src/s32k1xx/s32k1xx_pin.c new file mode 100644 index 00000000000..be41cc8655c --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_pin.c @@ -0,0 +1,254 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_pin.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 "up_arch.h" +#include "up_internal.h" + +#include "hardware/s32k1xx_port.h" +#include "hardware/s32k1xx_gpio.h" +#include "s32k1xx_pin.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_pinconfig + * + * Description: + * Configure a PIN based on bit-encoded description of the pin. NOTE that + * DMA/interrupts are disabled at the initial PIN configuration. + * + ****************************************************************************/ + +int s32k1xx_pinconfig(uint32_t cfgset) +{ + uintptr_t base; + uint32_t regval; + unsigned int port; + unsigned int pin; + unsigned int mode; + + /* Get the port number and pin number */ + + port = (cfgset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + pin = (cfgset & _PIN_MASK) >> _PIN_SHIFT; + + DEBUGASSERT(port < S32K1XX_NPORTS); + if (port < S32K1XX_NPORTS) + { + /* Get the base address of PORT block for this port */ + + base = S32K1XX_PORT_BASE(port); + + /* Get the port mode */ + + mode = (cfgset & _PIN_MODE_MASK) >> _PIN_MODE_SHIFT; + + /* Special case analog port mode. In this case, not of the digital + * options are applicable. + */ + + if (mode == PIN_MODE_ANALOG) + { + /* Set the analog mode with all digital options zeroed */ + + regval = PORT_PCR_MUX_ANALOG | PORT_PCR_IRQC_DISABLED; + putreg32(regval, base + S32K1XX_PORT_PCR_OFFSET(pin)); + } + else + { + /* Configure the digital pin options */ + + regval = (mode << PORT_PCR_MUX_SHIFT); + if ((cfgset & _PIN_IO_MASK) == _PIN_INPUT) + { + /* Handle input-only digital options */ + /* Check for pull-up or pull-down */ + + if ((cfgset & _PIN_INPUT_PULLMASK) == _PIN_INPUT_PULLDOWN) + { + regval |= PORT_PCR_PE; + } + else if ((cfgset & _PIN_INPUT_PULLMASK) == _PIN_INPUT_PULLUP) + { + regval |= (PORT_PCR_PE | PORT_PCR_PS); + } + } + else + { + /* Handle output-only digital options */ + /* Check for slow slew rate setting */ + +#warning REVISIT +#if 0 /* REVISIT -- bits don't exist in the S32K1xx PCR */ + if ((cfgset & _PIN_OUTPUT_SLEW_MASK) == _PIN_OUTPUT_SLOW) + { + regval |= PORT_PCR_SRE; + } + + /* Check for open drain output */ + + if ((cfgset & _PIN_OUTPUT_OD_MASK) == _PIN_OUTPUT_OPENDRAIN) + { + regval |= PORT_PCR_ODE; + } +#endif + + /* Check for high drive output */ + + if ((cfgset & _PIN_OUTPUT_DRIVE_MASK) == _PIN_OUTPUT_HIGHDRIVE) + { + regval |= PORT_PCR_DSE; + } + } + + /* Check for passive filter enable. Passive Filter configuration + * is valid in all digital pin muxing modes. + */ + + if ((cfgset & PIN_PASV_FILTER) != 0) + { + regval |= PORT_PCR_PFE; + } + + /* Set the digital mode with all of the selected options */ + + putreg32(regval, base + S32K1XX_PORT_PCR_OFFSET(pin)); + + /* Check for digital filter enable. Digital Filter configuration + * is valid in all digital pin muxing modes. + */ + + regval = getreg32(base + S32K1XX_PORT_DFER_OFFSET); + if ((cfgset & PIN_DIG_FILTER) != 0) + { + regval |= (1 << pin); + } + else + { + regval &= ~(1 << pin); + } + putreg32(regval, base + S32K1XX_PORT_DFER_OFFSET); + + /* Additional configuration for the case of Alternative 1 (GPIO) modes */ + + if (mode == PIN_MODE_GPIO) + { + /* Set the GPIO port direction */ + + base = S32K1XX_GPIO_BASE(port); + regval = getreg32(base + S32K1XX_GPIO_PDDR_OFFSET); + if ((cfgset & _PIN_IO_MASK) == _PIN_INPUT) + { + /* Select GPIO input */ + + regval &= ~(1 << pin); + putreg32(regval, base + S32K1XX_GPIO_PDDR_OFFSET); + } + else /* if ((cfgset & _PIN_IO_MASK) == _PIN_OUTPUT) */ + { + /* Select GPIO input */ + + regval |= (1 << pin); + putreg32(regval, base + S32K1XX_GPIO_PDDR_OFFSET); + + /* Set the initial value of the GPIO output */ + + s32k1xx_gpiowrite(cfgset, ((cfgset & GPIO_OUTPUT_ONE) != 0)); + } + } + } + + return OK; + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: s32k1xx_pinfilter + * + * Description: + * Configure the digital filter associated with a port. The digital filter + * capabilities of the PORT module are available in all digital pin muxing + * modes. + * + * Input Parameters: + * port - Port number. See S32K1XX_PORTn definitions in s32k1xx_port.h + * lpo - true: Digital Filters are clocked by the bus clock + * false: Digital Filters are clocked by the 1 kHz LPO clock + * width - Filter Length + * + *****************************************************************************/ + +int s32k1xx_pinfilter(unsigned int port, bool lpo, unsigned int width) +{ + uintptr_t base; + uint32_t regval; + + DEBUGASSERT(port < S32K1XX_NPORTS); + if (port < S32K1XX_NPORTS) + { + /* Get the base address of PORT block for this port */ + + base = S32K1XX_PORT_BASE(port); + + /* Select clocking */ + + regval = (lpo ? PORT_DFCR_CS : 0); + putreg32(regval, base + S32K1XX_PORT_DFCR_OFFSET); + + /* Select the filter width */ + + DEBUGASSERT(width < 32); + putreg32(width, base + S32K1XX_PORT_DFWR_OFFSET); + return OK; + } + + return -EINVAL; +} diff --git a/arch/arm/src/s32k1xx/s32k1xx_pin.h b/arch/arm/src/s32k1xx/s32k1xx_pin.h new file mode 100644 index 00000000000..12bca64d1ff --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_pin.h @@ -0,0 +1,497 @@ +/************************************************************************************ + * arch/arm/src/s32k1xx/s32k1xx.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Authors: 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_PIN_H +#define __ARCH_ARM_SRC_S32K1XX_S32K1XX_PIN_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include + +#include +#include +#include + +#include + +#include "up_internal.h" +#include "hardware/s32k1xx_port.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Bit-encoded input to s32k1xx_pinconfig() *****************************************/ +/* General form (32-bits, only 22 bits are unused in the encoding): + * + * oooo mmmv iiii ifd- ---- -ppp ---b bbbb + */ + +/* Bits 25-31: 7 bits are used to encode the basic pin configuration: + * + * oooo mmm- ---- ---- ---- ---- ---- ---- + * | `--- mmm: mode + * `------- oooo: options (may be combined) + */ + +#define _PIN_MODE_SHIFT (25) /* Bits 25-27: Pin mode */ +#define _PIN_MODE_MASK (7 << _PIN_MODE_SHIFT) +#define _PIN_OPTIONS_SHIFT (28) /* Bits 28-31: Pin mode options */ +#define _PIN_OPTIONS_MASK (15 << _PIN_OPTIONS_SHIFT) + +/* Port Modes */ + /* Unshifted versions: */ +#define PIN_MODE_ANALOG (0) /* 000 Pin Disabled (Analog) */ +#define PIN_MODE_ALT1 (1) /* 001 Alternative 1 */ +#define PIN_MODE_GPIO PIN_MODE_ALT1 /* 001 Alternative 1 (GPIO) */ +#define PIN_MODE_ALT2 (2) /* 010 Alternative 2 */ +#define PIN_MODE_ALT3 (3) /* 011 Alternative 3 */ +#define PIN_MODE_ALT4 (4) /* 100 Alternative 4 */ +#define PIN_MODE_ALT5 (5) /* 101 Alternative 5 */ +#define PIN_MODE_ALT6 (6) /* 110 Alternative 6 */ +#define PIN_MODE_ALT7 (7) /* 111 Alternative 7 */ + /* Shifted versions: */ +#define _PIN_MODE_ANALOG (0 << _PIN_MODE_SHIFT) /* 000 Pin Disabled (Analog) */ +#define _PIN_MODE_ALT1 (1 << _PIN_MODE_SHIFT) /* 001 Alternative 1 */ +#define _PIN_MODE_GPIO (1 << _PIN_MODE_SHIFT) /* 001 Alternative 1 (GPIO) */ +#define _PIN_MODE_ALT2 (2 << _PIN_MODE_SHIFT) /* 010 Alternative 2 */ +#define _PIN_MODE_ALT3 (3 << _PIN_MODE_SHIFT) /* 011 Alternative 3 */ +#define _PIN_MODE_ALT4 (4 << _PIN_MODE_SHIFT) /* 100 Alternative 4 */ +#define _PIN_MODE_ALT5 (5 << _PIN_MODE_SHIFT) /* 101 Alternative 5 */ +#define _PIN_MODE_ALT6 (6 << _PIN_MODE_SHIFT) /* 110 Alternative 6 */ +#define _PIN_MODE_ALT7 (7 << _PIN_MODE_SHIFT) /* 111 Alternative 7 */ + +/* Options for all digital modes (Alternatives 1-7). None of the digital + * options apply if the analog mode is selected. + */ + +#define _PIN_IO_MASK (1 << _PIN_OPTIONS_SHIFT) /* xxx1 Digital input/output mask */ +#define _PIN_INPUT (0 << _PIN_OPTIONS_SHIFT) /* xxx0 Digital input */ +#define _PIN_OUTPUT (1 << _PIN_OPTIONS_SHIFT) /* xxx1 Digital output */ + +#define _PIN_INPUT_PULLMASK (7 << _PIN_OPTIONS_SHIFT) /* x111 Mask for pull-up or -down bits */ +#define _PIN_INPUT_PULLDOWN (2 << _PIN_OPTIONS_SHIFT) /* x010 Input with internal pull-down resistor */ +#define _PIN_INPUT_PULLUP (6 << _PIN_OPTIONS_SHIFT) /* x110 Input with internal pull-up resistor */ + +#define _PIN_OUTPUT_SLEW_MASK (3 << _PIN_OPTIONS_SHIFT) /* xx11 Mask to test for slow slew rate */ +#define _PIN_OUTPUT_FAST (1 << _PIN_OPTIONS_SHIFT) /* xx01 Output with fast slew rate */ +#define _PIN_OUTPUT_SLOW (3 << _PIN_OPTIONS_SHIFT) /* xx11 Output with slow slew rate */ +#define _PIN_OUTPUT_OD_MASK (5 << _PIN_OPTIONS_SHIFT) /* x1x1 Mask to test for open drain */ +#define _PIN_OUTPUT_OPENDRAIN (5 << _PIN_OPTIONS_SHIFT) /* x1x1 Output with open drain enabled */ +#define _PIN_OUTPUT_DRIVE_MASK (9 << _PIN_OPTIONS_SHIFT) /* 1xx1 Mask to test for high drive strengh */ +#define _PIN_OUTPUT_LOWDRIVE (1 << _PIN_OPTIONS_SHIFT) /* 0xx1 Output with low drive strength */ +#define _PIN_OUTPUT_HIGHDRIVE (9 << _PIN_OPTIONS_SHIFT) /* 1xx1 Output with high drive strength */ + +/* End-user pin modes and configurations. Notes: (1) None of the digital options + * are available for the analog mode, (2) digital settings may be combined (OR'ed) + * provided that input-only and output-only options are not intermixed. + */ + +#define PIN_ANALOG _PIN_MODE_ANALOG + +#define GPIO_INPUT (_PIN_MODE_GPIO | _PIN_INPUT) +#define GPIO_PULLDOWN (_PIN_MODE_GPIO | _PIN_INPUT_PULLDOWN) +#define GPIO_PULLUP (_PIN_MODE_GPIO | _PIN_INPUT_PULLUP) +#define GPIO_OUTPUT (_PIN_MODE_GPIO | _PIN_OUTPUT) +#define GPIO_FAST (_PIN_MODE_GPIO | _PIN_OUTPUT_FAST) +#define GPIO_SLOW (_PIN_MODE_GPIO | _PIN_OUTPUT_SLOW) +#define GPIO_OPENDRAIN (_PIN_MODE_GPIO | _PIN_OUTPUT_OPENDRAIN) +#define GPIO_LOWDRIVE (_PIN_MODE_GPIO | _PIN_OUTPUT_LOWDRIVE) +#define GPIO_HIGHDRIVE (_PIN_MODE_GPIO | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT1 _PIN_MODE_ALT1 +#define PIN_ALT1_INPUT (_PIN_MODE_ALT1 | _PIN_INPUT) +#define PIN_ALT1_PULLDOWN (_PIN_MODE_ALT1 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT1_PULLUP (_PIN_MODE_ALT1 | _PIN_INPUT_PULLUP) +#define PIN_ALT1_OUTPUT (_PIN_MODE_ALT1 | _PIN_OUTPUT) +#define PIN_ALT1_FAST (_PIN_MODE_ALT1 | _PIN_OUTPUT_FAST) +#define PIN_ALT1_SLOW (_PIN_MODE_ALT1 | _PIN_OUTPUT_SLOW) +#define PIN_ALT1_OPENDRAIN (_PIN_MODE_ALT1 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT1_LOWDRIVE (_PIN_MODE_ALT1 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT1_HIGHDRIVE (_PIN_MODE_ALT1 | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT2 _PIN_MODE_ALT2 +#define PIN_ALT2_INPUT (_PIN_MODE_ALT2 | _PIN_INPUT) +#define PIN_ALT2_PULLDOWN (_PIN_MODE_ALT2 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT2_PULLUP (_PIN_MODE_ALT2 | _PIN_INPUT_PULLUP) +#define PIN_ALT2_OUTPUT (_PIN_MODE_ALT2 | _PIN_OUTPUT) +#define PIN_ALT2_FAST (_PIN_MODE_ALT2 | _PIN_OUTPUT_FAST) +#define PIN_ALT2_SLOW (_PIN_MODE_ALT2 | _PIN_OUTPUT_SLOW) +#define PIN_ALT2_OPENDRAIN (_PIN_MODE_ALT2 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT2_LOWDRIVE (_PIN_MODE_ALT2 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT2_HIGHDRIVE (_PIN_MODE_ALT2 | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT3 _PIN_MODE_ALT3 +#define PIN_ALT3_INPUT (_PIN_MODE_ALT3 | _PIN_INPUT) +#define PIN_ALT3_PULLDOWN (_PIN_MODE_ALT3 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT3_PULLUP (_PIN_MODE_ALT3 | _PIN_INPUT_PULLUP) +#define PIN_ALT3_OUTPUT (_PIN_MODE_ALT3 | _PIN_OUTPUT) +#define PIN_ALT3_FAST (_PIN_MODE_ALT3 | _PIN_OUTPUT_FAST) +#define PIN_ALT3_SLOW (_PIN_MODE_ALT3 | _PIN_OUTPUT_SLOW) +#define PIN_ALT3_OPENDRAIN (_PIN_MODE_ALT3 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT3_LOWDRIVE (_PIN_MODE_ALT3 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT3_HIGHDRIVE (_PIN_MODE_ALT3 | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT4 _PIN_MODE_ALT4 +#define PIN_ALT4_INPUT (_PIN_MODE_ALT4 | _PIN_INPUT) +#define PIN_ALT4_PULLDOWN (_PIN_MODE_ALT4 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT4_PULLUP (_PIN_MODE_ALT4 | _PIN_INPUT_PULLUP) +#define PIN_ALT4_OUTPUT (_PIN_MODE_ALT4 | _PIN_OUTPUT) +#define PIN_ALT4_FAST (_PIN_MODE_ALT4 | _PIN_OUTPUT_FAST) +#define PIN_ALT4_SLOW (_PIN_MODE_ALT4 | _PIN_OUTPUT_SLOW) +#define PIN_ALT4_OPENDRAIN (_PIN_MODE_ALT4 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT4_LOWDRIVE (_PIN_MODE_ALT4 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT4_HIGHDRIVE (_PIN_MODE_ALT4 | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT5 _PIN_MODE_ALT5 +#define PIN_ALT5_INPUT (_PIN_MODE_ALT5 | _PIN_INPUT) +#define PIN_ALT5_PULLDOWN (_PIN_MODE_ALT5 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT5_PULLUP (_PIN_MODE_ALT5 | _PIN_INPUT_PULLUP) +#define PIN_ALT5_OUTPUT (_PIN_MODE_ALT5 | _PIN_OUTPUT) +#define PIN_ALT5_FAST (_PIN_MODE_ALT5 | _PIN_OUTPUT_FAST) +#define PIN_ALT5_SLOW (_PIN_MODE_ALT5 | _PIN_OUTPUT_SLOW) +#define PIN_ALT5_OPENDRAIN (_PIN_MODE_ALT5 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT5_LOWDRIVE (_PIN_MODE_ALT5 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT5_HIGHDRIVE (_PIN_MODE_ALT5 | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT6 _PIN_MODE_ALT6 +#define PIN_ALT6_INPUT (_PIN_MODE_ALT6 | _PIN_INPUT) +#define PIN_ALT6_PULLDOWN (_PIN_MODE_ALT6 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT6_PULLUP (_PIN_MODE_ALT6 | _PIN_INPUT_PULLUP) +#define PIN_ALT6_OUTPUT (_PIN_MODE_ALT6 | _PIN_OUTPUT) +#define PIN_ALT6_FAST (_PIN_MODE_ALT6 | _PIN_OUTPUT_FAST) +#define PIN_ALT6_SLOW (_PIN_MODE_ALT6 | _PIN_OUTPUT_SLOW) +#define PIN_ALT6_OPENDRAIN (_PIN_MODE_ALT6 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT6_LOWDRIVE (_PIN_MODE_ALT6 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT6_HIGHDRIVE (_PIN_MODE_ALT6 | _PIN_OUTPUT_HIGHDRIVE) + +#define PIN_ALT7 _PIN_MODE_ALT7 +#define PIN_ALT7_INPUT (_PIN_MODE_ALT7 | _PIN_INPUT) +#define PIN_ALT7_PULLDOWN (_PIN_MODE_ALT7 | _PIN_INPUT_PULLDOWN) +#define PIN_ALT7_PULLUP (_PIN_MODE_ALT7 | _PIN_INPUT_PULLUP) +#define PIN_ALT7_OUTPUT (_PIN_MODE_ALT7 | _PIN_OUTPUT) +#define PIN_ALT7_FAST (_PIN_MODE_ALT7 | _PIN_OUTPUT_FAST) +#define PIN_ALT7_SLOW (_PIN_MODE_ALT7 | _PIN_OUTPUT_SLOW) +#define PIN_ALT7_OPENDRAIN (_PIN_MODE_ALT7 | _PIN_OUTPUT_OPENDRAIN) +#define PIN_ALT7_LOWDRIVE (_PIN_MODE_ALT7 | _PIN_OUTPUT_LOWDRIVE) +#define PIN_ALT7_HIGHDRIVE (_PIN_MODE_ALT7 | _PIN_OUTPUT_HIGHDRIVE) + +/* The initial value for GPIO (Alternative 1 outputs): + * + * ---- ---v ---- ---- ---- ---- ---- ---- + * + * Passive Filter and digital filter enable are valid in all digital pin + * muxing modes. + */ + +#define GPIO_OUTPUT_ONE (1 << 24) /* Bit 24: 1:Initial output value=1 */ +#define GPIO_OUTPUT_ZERO (0) /* Bit 24: 0:Initial output value=0 */ + +/* Five bits are used to incode DMA/interrupt options: + * + * ---- ---- iiii i--- ---- ---- ---- ---- + * + * The pin interrupt configuration is valid in all digital pin muxing modes + * (restricted to inputs). + */ + +#define _PIN_INT_SHIFT (19) +#define _PIN_INT_MASK (31 << _PIN_INT_SHIFT) + +#define _PIN_INTDMA_MASK (3 << _PIN_INT_SHIFT) +#define _PIN_INTDMA_NONE (0 << _PIN_INT_SHIFT) +#define _PIN_DMA (1 << _PIN_INT_SHIFT) +#define _PIN_INTERRUPT (2 << _PIN_INT_SHIFT) + +#define PIN_DMA_RISING (5 << _PIN_INT_SHIFT) /* 00101 DMA Request on rising edge */ +#define PIN_DMA_FALLING (9 << _PIN_INT_SHIFT) /* 01001 DMA Request on falling edge */ +#define PIN_DMA_BOTH (13 << _PIN_INT_SHIFT) /* 01101 DMA Request on either edge */ +#define PIN_INT_ZERO (2 << _PIN_INT_SHIFT) /* 00010 Interrupt when logic zero */ +#define PIN_INT_RISING (6 << _PIN_INT_SHIFT) /* 00110 Interrupt on rising edge */ +#define PIN_INT_FALLING (10 << _PIN_INT_SHIFT) /* 01010 Interrupt on falling edge */ +#define PIN_INT_BOTH (14 << _PIN_INT_SHIFT) /* 01110 Interrupt on either edge */ +#define PIN_INT_ONE (18 << _PIN_INT_SHIFT) /* 10010 Interrupt when logic one */ + +/* Two bits is used to enable the filter options: + * + * ---- ---- ---- -fd- ---- ---- ---- ---- + * + * Passive Filter and digital filter enable are valid in all digital pin + * muxing modes. + */ + +#define PIN_PASV_FILTER (1 << 18) /* Bit 18: Enable passive filter */ +#define PIN_DIG_FILTER (1 << 17) /* Bit 17: Enable digital filter */ + +/* Three bits are used to define the port number: + * + * ---- ---- ---- ---- ---- -ppp ---- ---- + */ + +#define _PIN_PORT_SHIFT (8) /* Bits 8-10: port number */ +#define _PIN_PORT_MASK (7 << _PIN_PORT_SHIFT) + +#define PIN_PORTA (S32K1XX_PORTA << _PIN_PORT_SHIFT) +#define PIN_PORTB (S32K1XX_PORTB << _PIN_PORT_SHIFT) +#define PIN_PORTC (S32K1XX_PORTC << _PIN_PORT_SHIFT) +#define PIN_PORTD (S32K1XX_PORTD << _PIN_PORT_SHIFT) +#define PIN_PORTE (S32K1XX_PORTE << _PIN_PORT_SHIFT) + +/* Five bits are used to define the pin number: + * + * ---- ---- ---- ---- ---- ---- ---b bbbb + */ + +#define _PIN_SHIFT (0) /* Bits 0-4: port number */ +#define _PIN_MASK (31 << _PIN_SHIFT) + +#define PIN(n) ((n) << _PIN_SHIFT) +#define PIN0 (0 << _PIN_SHIFT) +#define PIN1 (1 << _PIN_SHIFT) +#define PIN2 (2 << _PIN_SHIFT) +#define PIN3 (3 << _PIN_SHIFT) +#define PIN4 (4 << _PIN_SHIFT) +#define PIN5 (5 << _PIN_SHIFT) +#define PIN6 (6 << _PIN_SHIFT) +#define PIN7 (7 << _PIN_SHIFT) +#define PIN8 (8 << _PIN_SHIFT) +#define PIN9 (9 << _PIN_SHIFT) +#define PIN10 (10 << _PIN_SHIFT) +#define PIN11 (11 << _PIN_SHIFT) +#define PIN12 (12 << _PIN_SHIFT) +#define PIN13 (13 << _PIN_SHIFT) +#define PIN14 (14 << _PIN_SHIFT) +#define PIN15 (15 << _PIN_SHIFT) +#define PIN16 (16 << _PIN_SHIFT) +#define PIN17 (17 << _PIN_SHIFT) +#define PIN18 (18 << _PIN_SHIFT) +#define PIN19 (19 << _PIN_SHIFT) +#define PIN20 (20 << _PIN_SHIFT) +#define PIN21 (21 << _PIN_SHIFT) +#define PIN22 (22 << _PIN_SHIFT) +#define PIN23 (23 << _PIN_SHIFT) +#define PIN24 (24 << _PIN_SHIFT) +#define PIN25 (25 << _PIN_SHIFT) +#define PIN26 (26 << _PIN_SHIFT) +#define PIN27 (27 << _PIN_SHIFT) +#define PIN28 (28 << _PIN_SHIFT) +#define PIN29 (29 << _PIN_SHIFT) +#define PIN30 (30 << _PIN_SHIFT) +#define PIN31 (31 << _PIN_SHIFT) + +/************************************************************************************ + * 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_pinconfig + * + * Description: + * Configure a pin based on bit-encoded description of the pin. + * + ************************************************************************************/ + +int s32k1xx_pinconfig(uint32_t cfgset); + +/************************************************************************************ + * Name: s32k1xx_pinfilter + * + * Description: + * Configure the digital filter associated with a port. The digital filter + * capabilities of the PORT module are available in all digital pin muxing modes. + * + * Input Parameters: + * port - See S32K1XX_PORTn definitions in s32k1xx_port.h + * lpo - true: Digital Filters are clocked by the bus clock + * false: Digital Filters are clocked by the 1 kHz LPO clock + * width - Filter Length + * + ************************************************************************************/ + +int s32k1xx_pinfilter(unsigned int port, bool lpo, unsigned int width); + +/************************************************************************************ + * Name: s32k1xx_gpiowrite + * + * Description: + * Write one or zero to the selected GPIO pin + * + ************************************************************************************/ + +void s32k1xx_gpiowrite(uint32_t pinset, bool value); + +/************************************************************************************ + * Name: s32k1xx_gpioread + * + * Description: + * Read one or zero from the selected GPIO pin + * + ************************************************************************************/ + +bool s32k1xx_gpioread(uint32_t pinset); + +/************************************************************************************ + * Name: s32k1xx_pinirqi_nitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for GPIO pins. + * + ************************************************************************************/ + +#ifdef CONFIG_S32K1XX_GPIOIRQ +void s32k1xx_pinirqi_nitialize(void); +#else +# define s32k1xx_pinirqi_nitialize() +#endif + +/************************************************************************************ + * Name: s32k1xx_pinirqattach + * + * Description: + * Attach a pin interrupt handler. The normal initalization sequence is: + * + * 1. Call s32k1xx_pinconfig() to configure the interrupting pin (pin interrupts + * will be disabled. + * 2. Call s32k1xx_pinirqattach() to attach the pin interrupt handling function. + * 3. Call s32k1xx_pinirqenable() to enable interrupts on the pin. + * + * Input Parameters: + * pinset - Pin configuration + * pinisr - Pin interrupt service routine + * arg - An argument that will be provided to the interrupt service routine. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on any + * failure to indicate the nature of the failure. + * + ************************************************************************************/ + +int s32k1xx_pinirqattach(uint32_t pinset, xcpt_t pinisr, void *arg); + +/************************************************************************************ + * Name: s32k1xx_pinirqenable + * + * Description: + * Enable the interrupt for specified pin IRQ + * + ************************************************************************************/ + +#ifdef CONFIG_S32K1XX_GPIOIRQ +void s32k1xx_pinirqenable(uint32_t pinset); +#else +# define s32k1xx_pinirqenable(pinset) +#endif + +/************************************************************************************ + * Name: s32k1xx_pinirqdisable + * + * Description: + * Disable the interrupt for specified pin + * + ************************************************************************************/ + +#ifdef CONFIG_S32K1XX_GPIOIRQ +void s32k1xx_pinirqdisable(uint32_t pinset); +#else +# define s32k1xx_pinirqdisable(pinset) +#endif + +/************************************************************************************ + * Name: s32k1xx_pindmaenable + * + * Description: + * Enable DMA for specified pin + * + ************************************************************************************/ + +#ifdef CONFIG_S32K1XX_DMA +void s32k1xx_pindmaenable(uint32_t pinset); +#endif + +/************************************************************************************ + * Name: s32k1xx_pindmadisable + * + * Description: + * Disable DMA for specified pin + * + ************************************************************************************/ + +#ifdef CONFIG_S32K1XX_DMA +void s32k1xx_pindmadisable(uint32_t pinset); +#endif + +/************************************************************************************ + * Function: s32k1xx_pindump + * + * Description: + * Dump all GPIO registers associated with the base address of the provided pinset. + * + ************************************************************************************/ + +#ifdef CONFIG_DEBUG_GPIO_INFO +void s32k1xx_pindump(uint32_t pinset, const char *msg); +#else +# define s32k1xx_pindump(p,m) +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_S32K1XX_S32K1XX_PIN_H */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_pindma.c b/arch/arm/src/s32k1xx/s32k1xx_pindma.c new file mode 100644 index 00000000000..2632b4c6ebc --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_pindma.c @@ -0,0 +1,149 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_pindma.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 "up_arch.h" +#include "up_internal.h" + +#include "s32k1xx_pin.h" + +#ifdef CONFIG_S32K1XX_DMA + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/************************************************************************************ + * Name: s32k1xx_pindmaenable + * + * Description: + * Enable DMA for specified pin + * + ************************************************************************************/ + +void s32k1xx_pindmaenable(uint32_t pinset) +{ + uintptr_t base; + uint32_t regval; + unsigned int port; + unsigned int pin; + + /* Get the port number and pin number */ + + port = (pinset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + pin = (pinset & _PIN_MASK) >> _PIN_SHIFT; + + DEBUGASSERT(port < S32K1XX_NPORTS); + if (port < S32K1XX_NPORTS) + { + /* Get the base address of PORT block for this port */ + + base = S32K1XX_PORT_BASE(port); + + /* Modify the IRQC field of the port PCR register in order to enable DMA. */ + + regval = getreg32(base + S32K1XX_PORT_PCR_OFFSET(pin)); + regval &= ~PORT_PCR_IRQC_MASK; + + switch (pinset & _PIN_INT_MASK) + { + case PIN_DMA_RISING : /* DMA Request on rising edge */ + regval |= PORT_PCR_IRQC_DMARISING; + break; + + case PIN_DMA_FALLING : /* DMA Request on falling edge */ + regval |= PORT_PCR_IRQC_DMAFALLING; + break; + + case PIN_DMA_BOTH : /* DMA Request on either edge */ + regval |= PORT_PCR_IRQC_DMABOTH; + break; + + default: + return; + } + + putreg32(regval, base + S32K1XX_PORT_PCR_OFFSET(pin)); + } +} + +/************************************************************************************ + * Name: s32k1xx_pindmadisable + * + * Description: + * Disable DMA for specified pin + * + ************************************************************************************/ + +void s32k1xx_pindmadisable(uint32_t pinset) +{ + uintptr_t base; + uint32_t regval; + unsigned int port; + unsigned int pin; + + /* Get the port number and pin number */ + + port = (pinset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + pin = (pinset & _PIN_MASK) >> _PIN_SHIFT; + + DEBUGASSERT(port < S32K1XX_NPORTS); + if (port < S32K1XX_NPORTS) + { + /* Get the base address of PORT block for this port */ + + base = S32K1XX_PORT_BASE(port); + + /* Clear the IRQC field of the port PCR register in order to disable DMA. */ + + regval = getreg32(base + S32K1XX_PORT_PCR_OFFSET(pin)); + regval &= ~PORT_PCR_IRQC_MASK; + putreg32(regval, base + S32K1XX_PORT_PCR_OFFSET(pin)); + } +} + +#endif diff --git a/arch/arm/src/s32k1xx/s32k1xx_pindump.c b/arch/arm/src/s32k1xx/s32k1xx_pindump.c new file mode 100644 index 00000000000..13b1b67d440 --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_pindump.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_pindump.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_gpio.h" +#include "hardware/s32k1xx_port.h" +#include "s32k1xx_pin.h" + +#ifdef CONFIG_DEBUG_GPIO_INFO + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Port letters for prettier debug output */ + +static const char g_portchar[S32K1XX_NPORTS] = +{ +#if S32K1XX_NPORTS > 9 +# error "Additional support required for this number of GPIOs" +#elif S32K1XX_NPORTS > 8 + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' +#elif S32K1XX_NPORTS > 7 + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' +#elif S32K1XX_NPORTS > 6 + 'A', 'B', 'C', 'D', 'E', 'F', 'G' +#elif S32K1XX_NPORTS > 5 + 'A', 'B', 'C', 'D', 'E', 'F' +#elif S32K1XX_NPORTS > 4 + 'A', 'B', 'C', 'D', 'E' +#elif S32K1XX_NPORTS > 3 + 'A', 'B', 'C', 'D' +#elif S32K1XX_NPORTS > 2 + 'A', 'B', 'C' +#elif S32K1XX_NPORTS > 1 + 'A', 'B' +#elif S32K1XX_NPORTS > 0 + 'A' +#else +# error "Bad number of GPIOs" +#endif +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: s32k1xx_pindump + * + * Description: + * Dump all GPIO registers associated with the provided pin description + * along with a descriptive messasge. + * + ****************************************************************************/ + +void s32k1xx_pindump(uint32_t pinset, const char *msg) +{ + irqstate_t flags; + uintptr_t base; + int port; + + /* Decode the port and pin. Use the port number to get the GPIO base + * address. + */ + + port = (pinset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + DEBUGASSERT((unsigned)port < S32K1XX_NPORTS); + base = S32K1XX_GPIO_BASE(port); + + /* The following requires exclusive access to the GPIO registers */ + + flags = enter_critical_section(); + + gpioinfo("GPIO%c pinset: %08x base: %08x -- %s\n", + g_portchar[port], pinset, base, msg); + gpioinfo(" PDOR: %08x PDIR: %08x PDDR: %08x\n", + getreg32(base + S32K1XX_GPIO_PDOR_OFFSET), + getreg32(base + S32K1XX_GPIO_PDIR_OFFSET), + getreg32(base + S32K1XX_GPIO_PDDR_OFFSET)); + + leave_critical_section(flags); +} + +#endif /* CONFIG_DEBUG_GPIO_INFO */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_pinirq.c b/arch/arm/src/s32k1xx/s32k1xx_pinirq.c new file mode 100644 index 00000000000..c3194cafa2f --- /dev/null +++ b/arch/arm/src/s32k1xx/s32k1xx_pinirq.c @@ -0,0 +1,467 @@ +/**************************************************************************** + * arch/arm/src/s32k1xx/s32k1xx_pinirq.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 "up_arch.h" +#include "up_internal.h" + +#include "s32k1xx.h" +#include "hardware/s32k1xx_port.h" + +#ifdef CONFIG_S32K1XX_GPIOIRQ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* The S32K1xx port interrupt logic is very flexible and will program + * interrupts on most all pin events. In order to keep the memory usage to + * a minimum, the NuttX port supports enabling interrupts on a per-port + * basis. + */ + +#if defined (CONFIG_S32K1XX_PORTAINTS) || defined (CONFIG_S32K1XX_PORTBINTS) || \ + defined (CONFIG_S32K1XX_PORTCINTS) || defined (CONFIG_S32K1XX_PORTDINTS) || \ + defined (CONFIG_S32K1XX_PORTEINTS) +# define HAVE_PORTINTS 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct s32k1xx_pinirq_s +{ + xcpt_t handler; + void *arg; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* Per pin port interrupt vectors. NOTE: Not all pins in each port + * correspond to externally available GPIOs. However, I believe that the + * Kinesis will support interrupts even if the pin is not available as + * a GPIO. Hence, we need to support all 32 pins for each port. To keep the + * memory usage at a minimum, the logic may be configure per port. + */ + +#ifdef CONFIG_S32K1XX_PORTAINTS +static struct s32k1xx_pinirq_s g_portaisrs[32]; +#endif +#ifdef CONFIG_S32K1XX_PORTBINTS +static struct s32k1xx_pinirq_s g_portbisrs[32]; +#endif +#ifdef CONFIG_S32K1XX_PORTCINTS +static struct s32k1xx_pinirq_s g_portcisrs[32]; +#endif +#ifdef CONFIG_S32K1XX_PORTDINTS +static struct s32k1xx_pinirq_s g_portdisrs[32]; +#endif +#ifdef CONFIG_S32K1XX_PORTEINTS +static struct s32k1xx_pinirq_s g_porteisrs[32]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_portinterrupt + * + * Description: + * Common port interrupt handling. + * + ****************************************************************************/ + +#ifdef HAVE_PORTINTS +static int s32k1xx_portinterrupt(int irq, FAR void *context, + uintptr_t addr, struct s32k1xx_pinirq_s *isrtab) +{ + uint32_t isfr = getreg32(addr); + int i; + + /* Examine each pin in the port */ + + for (i = 0; i < 32 && isfr != 0; i++) + { + /* A bit set in the ISR means that an interrupt is pending for this + * pin. If the pin is programmed for level sensitive inputs, then + * the interrupt handling logic MUST disable the interrupt (or cause + * the level to change) to prevent infinite interrupts. + */ + + uint32_t bit = (1 << i); + if ((isfr & bit) != 0) + { + /* I think that bits may be set in the ISFR for DMA activities + * well. So, no error is declared if there is no registered + * interrupt handler for the pin. + */ + + if (isrtab[i].handler != NULL) + { + xcpt_t handler = isrtab[i].handler; + void *arg = isrtab[i].arg; + + /* There is a registered interrupt handler... invoke it */ + + (void)handler(irq, context, arg); + } + + /* Writing a one to the ISFR register will clear the pending + * interrupt. If pin is configured to generate a DMA request + * then the ISFR bit will be cleared automatically at the + * completion of the requested DMA transfer. If configured for + * a level sensitive interrupt and the pin remains asserted and + * the bit will set again immediately after it is cleared. + */ + + isfr &= ~bit; + putreg32(bit, addr); + } + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_portXinterrupt + * + * Description: + * Handle interrupts arriving on individual ports + * + ****************************************************************************/ + +#ifdef CONFIG_S32K1XX_PORTAINTS +static int s32k1xx_portainterrupt(int irq, FAR void *context, FAR void *arg) +{ + return s32k1xx_portinterrupt(irq, context, S32K1XX_PORTA_ISFR, g_portaisrs); +} +#endif +#ifdef CONFIG_S32K1XX_PORTBINTS +static int s32k1xx_portbinterrupt(int irq, FAR void *context, FAR void *arg) +{ + return s32k1xx_portinterrupt(irq, context, S32K1XX_PORTB_ISFR, g_portbisrs); +} +#endif +#ifdef CONFIG_S32K1XX_PORTCINTS +static int s32k1xx_portcinterrupt(int irq, FAR void *context, FAR void *arg) +{ + return s32k1xx_portinterrupt(irq, context, S32K1XX_PORTC_ISFR, g_portcisrs); +} +#endif +#ifdef CONFIG_S32K1XX_PORTDINTS +static int s32k1xx_portdinterrupt(int irq, FAR void *context, FAR void *arg) +{ + return s32k1xx_portinterrupt(irq, context, S32K1XX_PORTD_ISFR, g_portdisrs); +} +#endif +#ifdef CONFIG_S32K1XX_PORTEINTS +static int s32k1xx_porteinterrupt(int irq, FAR void *context, FAR void *arg) +{ + return s32k1xx_portinterrupt(irq, context, S32K1XX_PORTE_ISFR, g_porteisrs); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s32k1xx_pinirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + ****************************************************************************/ + +void s32k1xx_pinirqinitialize(void) +{ +#ifdef CONFIG_S32K1XX_PORTAINTS + (void)irq_attach(S32K1XX_IRQ_PORTA, s32k1xx_portainterrupt, NULL); + putreg32(0xffffffff, S32K1XX_PORTA_ISFR); + up_enable_irq(S32K1XX_IRQ_PORTA); +#endif +#ifdef CONFIG_S32K1XX_PORTBINTS + (void)irq_attach(S32K1XX_IRQ_PORTB, s32k1xx_portbinterrupt, NULL); + putreg32(0xffffffff, S32K1XX_PORTB_ISFR); + up_enable_irq(S32K1XX_IRQ_PORTB); +#endif +#ifdef CONFIG_S32K1XX_PORTCINTS + (void)irq_attach(S32K1XX_IRQ_PORTC, s32k1xx_portcinterrupt, NULL); + putreg32(0xffffffff, S32K1XX_PORTC_ISFR); + up_enable_irq(S32K1XX_IRQ_PORTC); +#endif +#ifdef CONFIG_S32K1XX_PORTDINTS + (void)irq_attach(S32K1XX_IRQ_PORTD, s32k1xx_portdinterrupt, NULL); + putreg32(0xffffffff, S32K1XX_PORTD_ISFR); + up_enable_irq(S32K1XX_IRQ_PORTD); +#endif +#ifdef CONFIG_S32K1XX_PORTEINTS + (void)irq_attach(S32K1XX_IRQ_PORTE, s32k1xx_porteinterrupt, NULL); + putreg32(0xffffffff, S32K1XX_PORTE_ISFR); + up_enable_irq(S32K1XX_IRQ_PORTE); +#endif +} + +/**************************************************************************** + * Name: s32k1xx_pinirqattach + * + * Description: + * Attach a pin interrupt handler. The normal initialization sequence is: + * + * 1. Call s32k1xx_pinconfig() to configure the interrupting pin (pin + * interrupts will be disabled. + * 2. Call s32k1xx_pinirqattach() to attach the pin interrupt handling + * function. + * 3. Call s32k1xx_pinirqenable() to enable interrupts on the pin. + * + * Input Parameters: + * pinset - Pin configuration + * pinisr - Pin interrupt service routine + * arg - An argument that will be provided to the interrupt service + * routine. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + *******************************************************************************/ + +int s32k1xx_pinirqattach(uint32_t pinset, xcpt_t pinisr, void *arg) +{ +#ifdef HAVE_PORTINTS + struct s32k1xx_pinirq_s *isrtab; + irqstate_t flags; + unsigned int port; + unsigned int pin; + + /* It only makes sense to call this function for input pins that are configured + * as interrupts. + */ + + DEBUGASSERT((pinset & _PIN_INTDMA_MASK) == _PIN_INTERRUPT); + DEBUGASSERT((pinset & _PIN_IO_MASK) == _PIN_INPUT); + + /* Get the port number and pin number */ + + port = (pinset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + pin = (pinset & _PIN_MASK) >> _PIN_SHIFT; + + /* Get the table associated with this port */ + + DEBUGASSERT(port < S32K1XX_NPORTS); + flags = enter_critical_section(); + switch (port) + { +#ifdef CONFIG_S32K1XX_PORTAINTS + case S32K1XX_PORTA : + isrtab = g_portaisrs; + break; +#endif +#ifdef CONFIG_S32K1XX_PORTBINTS + case S32K1XX_PORTB : + isrtab = g_portbisrs; + break; +#endif +#ifdef CONFIG_S32K1XX_PORTCINTS + case S32K1XX_PORTC : + isrtab = g_portcisrs; + break; +#endif +#ifdef CONFIG_S32K1XX_PORTDINTS + case S32K1XX_PORTD : + isrtab = g_portdisrs; + break; +#endif +#ifdef CONFIG_S32K1XX_PORTEINTS + case S32K1XX_PORTE : + isrtab = g_porteisrs; + break; +#endif + default: + leave_critical_section(flags); + return -EINVAL; + } + + /* Get the old PIN ISR and set the new PIN ISR */ + + isrtab[pin].handler = pinisr; + isrtab[pin].arg = arg; + + /* And return the old PIN isr address */ + + leave_critical_section(flags); + return OK; +#else + return -ENOSYS; +#endif /* HAVE_PORTINTS */ +} + +/************************************************************************************ + * Name: s32k1xx_pinirqenable + * + * Description: + * Enable the interrupt for specified pin IRQ + * + ************************************************************************************/ + +void s32k1xx_pinirqenable(uint32_t pinset) +{ +#ifdef HAVE_PORTINTS + uintptr_t base; + uint32_t regval; + unsigned int port; + unsigned int pin; + + /* Get the port number and pin number */ + + port = (pinset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + pin = (pinset & _PIN_MASK) >> _PIN_SHIFT; + + DEBUGASSERT(port < S32K1XX_NPORTS); + if (port < S32K1XX_NPORTS) + { + /* Get the base address of PORT block for this port */ + + base = S32K1XX_PORT_BASE(port); + + /* Modify the IRQC field of the port PCR register in order to enable + * the interrupt. + */ + + regval = getreg32(base + S32K1XX_PORT_PCR_OFFSET(pin)); + regval &= ~PORT_PCR_IRQC_MASK; + + switch (pinset & _PIN_INT_MASK) + { + case PIN_INT_ZERO : /* Interrupt when logic zero */ + regval |= PORT_PCR_IRQC_ZERO; + break; + + case PIN_INT_RISING : /* Interrupt on rising edge */ + regval |= PORT_PCR_IRQC_RISING; + break; + + case PIN_INT_FALLING : /* Interrupt on falling edge */ + regval |= PORT_PCR_IRQC_FALLING; + break; + + case PIN_INT_BOTH : /* Interrupt on either edge */ + regval |= PORT_PCR_IRQC_BOTH; + break; + + case PIN_INT_ONE : /* Interrupt when logic one */ + regval |= PORT_PCR_IRQC_ONE; + break; + + case PIN_DMA_RISING : /* DMA on rising edge */ + regval |= PORT_PCR_IRQC_DMARISING; + break; + + case PIN_DMA_FALLING : /* DMA on falling edge */ + regval |= PORT_PCR_IRQC_DMAFALLING; + break; + + case PIN_DMA_BOTH : /* DMA on either edge */ + regval |= PORT_PCR_IRQC_DMABOTH; + break; + + default: + return; + } + + putreg32(regval, base + S32K1XX_PORT_PCR_OFFSET(pin)); + } +#endif /* HAVE_PORTINTS */ +} + +/************************************************************************************ + * Name: s32k1xx_pinirqdisable + * + * Description: + * Disable the interrupt for specified pin + * + ************************************************************************************/ + +void s32k1xx_pinirqdisable(uint32_t pinset) +{ +#ifdef HAVE_PORTINTS + uintptr_t base; + uint32_t regval; + unsigned int port; + unsigned int pin; + + /* Get the port number and pin number */ + + port = (pinset & _PIN_PORT_MASK) >> _PIN_PORT_SHIFT; + pin = (pinset & _PIN_MASK) >> _PIN_SHIFT; + + DEBUGASSERT(port < S32K1XX_NPORTS); + if (port < S32K1XX_NPORTS) + { + /* Get the base address of PORT block for this port */ + + base = S32K1XX_PORT_BASE(port); + + /* Clear the IRQC field of the port PCR register in order to disable + * the interrupt. + */ + + regval = getreg32(base + S32K1XX_PORT_PCR_OFFSET(pin)); + regval &= ~PORT_PCR_IRQC_MASK; + putreg32(regval, base + S32K1XX_PORT_PCR_OFFSET(pin)); + } +#endif /* HAVE_PORTINTS */ +} +#endif /* CONFIG_S32K1XX_GPIOIRQ */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_serial.c b/arch/arm/src/s32k1xx/s32k1xx_serial.c index d9881f90fb8..81c5323cc67 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_serial.c +++ b/arch/arm/src/s32k1xx/s32k1xx_serial.c @@ -66,9 +66,9 @@ #include "up_internal.h" #include "hardware/s32k1xx_lpuart.h" -#include "s32k1xx_gpio.h" #include "hardware/s32k1xx_pinmux.h" #include "s32k1xx_config.h" +#include "s32k1xx_pin.h" #include "s32k1xx_lowputc.h" #ifdef USE_SERIALDRIVER diff --git a/arch/arm/src/s32k1xx/s32k1xx_start.c b/arch/arm/src/s32k1xx/s32k1xx_start.c index 751da4b417e..c8ae72fed6e 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_start.c +++ b/arch/arm/src/s32k1xx/s32k1xx_start.c @@ -190,7 +190,7 @@ void __start(void) * .bss or .data have been initialized. */ - DEBUG_VERIFY(s32k1xx_clockconfig(&g_initial_clkconfig)); + DEBUGVERIFY(s32k1xx_clockconfig(&g_initial_clkconfig)); s32k1xx_lowsetup(); showprogress('A');