diff --git a/arch/arm/src/xmc4/chip/xmc4_memorymap.h b/arch/arm/src/xmc4/chip/xmc4_memorymap.h index c2b847d4e0..ea41ac30b1 100644 --- a/arch/arm/src/xmc4/chip/xmc4_memorymap.h +++ b/arch/arm/src/xmc4/chip/xmc4_memorymap.h @@ -148,6 +148,7 @@ #define XMC4_USIC2_CH0_BASE 0x48024000 #define XMC4_USIC2_CH1_BASE 0x48024200 #define XMC4_USIC2_RAM_BASE 0x48024400 +#define XMC4_PORT_BASE(n) (0x48028000 + ((n) << 8)) #define XMC4_PORT0_BASE 0x48028000 #define XMC4_PORT1_BASE 0x48028100 #define XMC4_PORT2_BASE 0x48028200 diff --git a/arch/arm/src/xmc4/chip/xmc4_ports.h b/arch/arm/src/xmc4/chip/xmc4_ports.h index 3478d9dedb..588965c9f0 100644 --- a/arch/arm/src/xmc4/chip/xmc4_ports.h +++ b/arch/arm/src/xmc4/chip/xmc4_ports.h @@ -58,6 +58,8 @@ #include +#include "chip/xmc4_memorymap.h" + /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ @@ -68,13 +70,19 @@ #define XMC4_PORT_OUT_OFFSET 0x0000 /* Port Output Register */ #define XMC4_PORT_OMR_OFFSET 0x0004 /* Port Output Modification Register */ + +#define XMC4_PORT_IOCR_OFFSET(n) (0x0010 + ((n) & 3)) #define XMC4_PORT_IOCR0_OFFSET 0x0010 /* Port Input/Output Control Register 0 */ #define XMC4_PORT_IOCR4_OFFSET 0x0014 /* Port Input/Output Control Register 4 */ #define XMC4_PORT_IOCR8_OFFSET 0x0018 /* Port Input/Output Control Register 8 */ #define XMC4_PORT_IOCR12_OFFSET 0x001c /* Port Input/Output Control Register 12 */ + #define XMC4_PORT_IN_OFFSET 0x0024 /* Port Input Register */ + +#define XMC4_PORT_PDR_OFFSET(n) (0x0010 + (((n) >> 1) & 3)) #define XMC4_PORT_PDR0_OFFSET 0x0040 /* Port Pad Driver Mode 0 Register */ #define XMC4_PORT_PDR1_OFFSET 0x0044 /* Port Pad Driver Mode 1 Register */ + #define XMC4_PORT_PDISC_OFFSET 0x0060 /* Port Pin Function Decision Control Register */ #define XMC4_PORT_PPS_OFFSET 0x0070 /* Port Pin Power Save Register */ #define XMC4_PORT_HWSEL_OFFSET 0x0074 /* Port Pin Hardware Select Register */ diff --git a/arch/arm/src/xmc4/xmc4_gpio.c b/arch/arm/src/xmc4/xmc4_gpio.c index 4080a0be99..2bc8f10828 100644 --- a/arch/arm/src/xmc4/xmc4_gpio.c +++ b/arch/arm/src/xmc4/xmc4_gpio.c @@ -44,6 +44,7 @@ #include #include +#include #include "up_arch.h" #include "up_internal.h" @@ -51,6 +52,301 @@ #include "chip/xmc4_ports.h" #include "xmc4_gpio.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xmc4_gpio_getreg + * + * Description: + * Return the pin number for this pin configuration + * + ****************************************************************************/ + +static inline uint32_t xmc4_gpio_getreg(uintptr_t portbase, + unsigned int offset) +{ + return getreg32(portbase + offset); +} + +/**************************************************************************** + * Name: xmc4_gpio_putreg + * + * Description: + * Return the pin number for this pin configuration + * + ****************************************************************************/ + +static inline void xmc4_gpio_putreg(uintptr_t portbase, unsigned int offset, + uint32_t regval) +{ + putreg32(regval, portbase + offset); +} + +/**************************************************************************** + * Name: xmc4_gpio_port + * + * Description: + * Return the port number for this pin configuration + * + ****************************************************************************/ + +static inline int xmc4_gpio_port(gpioconfig_t pinconfig) +{ + return ((pinconfig & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT); +} + +/**************************************************************************** + * Name: xmc4_gpio_portbase + * + * Description: + * Return the base address of the port register for this pin configuration. + * + ****************************************************************************/ + +static uintptr_t xmc4_gpio_portbase(gpioconfig_t pinconfig) +{ + return XMC4_PORT_BASE(xmc4_gpio_port(pinconfig)); +} + +/**************************************************************************** + * Name: xmc4_gpio_pin + * + * Description: + * Return the pin number for this pin configuration + * + ****************************************************************************/ + +static unsigned int xmc4_gpio_pin(gpioconfig_t pinconfig) +{ + return ((pinconfig & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT); +} + +/**************************************************************************** + * Name: xmc4_gpio_pintype + * + * Description: + * Return the pintype for this pin configuration + * + ****************************************************************************/ + +static inline unsigned int xmc4_gpio_pintype(gpioconfig_t pinconfig) +{ + return ((pinconfig & GPIO_PINTYPE_MASK) >> GPIO_PINTYPE_SHIFT); +} + +/**************************************************************************** + * Name: xmc4_gpio_pinctrl + * + * Description: + * Return the pintype for this pin configuration + * + ****************************************************************************/ + +static inline unsigned int xmc4_gpio_pinctrl(gpioconfig_t pinconfig) +{ + return ((pinconfig & GPIO_PINCTRL_MASK) >> GPIO_PINCTRL_SHIFT); +} + +/**************************************************************************** + * Name: xmc4_gpio_padtype + * + * Description: + * Return the padtype for this pin configuration + * + ****************************************************************************/ + +static inline unsigned int xmc4_gpio_padtype(gpioconfig_t pinconfig) +{ + return ((pinconfig & GPIO_PADTYPE_MASK) >> GPIO_PADTYPE_SHIFT); +} + +/**************************************************************************** + * Name: xmc4_gpio_iocr + * + * Description: + * Update the IOCR register + * + ****************************************************************************/ + +static void xmc4_gpio_iocr(uintptr_t portbase, unsigned int pin, + unsigned int value) +{ + uint32_t regval; + uint32_t mask; + unsigned int offset; + unsigned int shift; + + /* Read the IOCR register */ + + offset = XMC4_PORT_IOCR_OFFSET(pin); + regval = xmc4_gpio_getreg(portbase, offset); + + /* Set the new value for this field */ + + pin &= 3; + shift = PORT_IOCR0_PC_SHIFT(pin); + mask = PORT_IOCR0_PC_MASK(pin); + + regval &= ~mask; + regval |= (uint32_t)value << shift; + + xmc4_gpio_putreg(portbase, offset, regval); +} + +/**************************************************************************** + * Name: xmc4_gpio_hwsel + * + * Description: + * Update the HWSEL register + * + ****************************************************************************/ + +static inline void xmc4_gpio_hwsel(uintptr_t portbase, unsigned int pin, + unsigned int value) +{ + uint32_t regval; + uint32_t mask; + unsigned int shift; + + /* Read the HWSEL register */ + + regval = xmc4_gpio_getreg(portbase, XMC4_PORT_HWSEL_OFFSET); + + /* Set the new value for this field */ + + shift = PORT_HWSEL_HW_SHIFT(pin); + mask = PORT_HWSEL_HW_MASK(pin); + + regval &= ~mask; + regval |= (uint32_t)value << shift; + + xmc4_gpio_putreg(portbase, XMC4_PORT_HWSEL_OFFSET, regval); +} + +/**************************************************************************** + * Name: xmc4_gpio_pdisc + * + * Description: + * Update the PDISC register + * + ****************************************************************************/ + +static inline void xmc4_gpio_pdisc(uintptr_t portbase, unsigned int pin, + bool value) +{ + uint32_t regval; + uint32_t mask; + + /* Read the PDISC register */ + + regval = xmc4_gpio_getreg(portbase, XMC4_PORT_PDISC_OFFSET); + + /* Set/clear the enable/disable (or analg) value for this field */ + + mask = PORT_PIN(pin); + if (value) + { + regval |= mask; + } + else + { + regval &= ~mask; + } + + xmc4_gpio_putreg(portbase, XMC4_PORT_PDISC_OFFSET, regval); +} + +/**************************************************************************** + * Name: xmc4_gpio_pps + * + * Description: + * Update the PPS register + * + ****************************************************************************/ + +static inline void xmc4_gpio_pps(uintptr_t portbase, unsigned int pin, + bool value) +{ + uint32_t regval; + uint32_t mask; + + /* Read the PPS register */ + + regval = xmc4_gpio_getreg(portbase, XMC4_PORT_PPS_OFFSET); + + /* Set/clear the enable/disable (or analg) value for this field */ + + mask = PORT_PIN(pin); + if (value) + { + regval |= mask; + } + else + { + regval &= ~mask; + } + + xmc4_gpio_putreg(portbase, XMC4_PORT_PPS_OFFSET, regval); +} + +/**************************************************************************** + * Name: xmc4_gpio_pdr + * + * Description: + * Update the IOCR register + * + ****************************************************************************/ + +static void xmc4_gpio_pdr(uintptr_t portbase, unsigned int pin, + unsigned int value) +{ + uint32_t regval; + uint32_t mask; + unsigned int offset; + unsigned int shift; + + /* Read the PDRregister */ + + offset = XMC4_PORT_PDR_OFFSET(pin); + regval = xmc4_gpio_getreg(portbase, offset); + + /* Set the new value for this field */ + + pin &= 7; + shift = PORT_PDR0_PD_SHIFT(pin); + mask = PORT_PDR0_PD_MASK(pin); + + regval &= ~mask; + regval |= (uint32_t)value << shift; + + xmc4_gpio_putreg(portbase, offset, regval); +} + +/**************************************************************************** + * Name: xmc4_gpio_inverted + * + * Description: + * Check if the input is inverted + * + ****************************************************************************/ + +static inline bool xmc4_gpio_inverted(gpioconfig_t pinconfig) +{ + return ((pinconfig & GPIO_INPUT_INVERT) != 0); +} + +/**************************************************************************** + * Name: xmc4_gpio_opendrain + * + * Description: + * Check if the output is opendram + * + ****************************************************************************/ + +#define xmc4_gpio_opendrain(p) xmc4_gpio_inverted(p) + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -66,8 +362,71 @@ int xmc4_gpio_config(gpioconfig_t pinconfig) { -#warning Missing logic - return -EINVAL; + uintptr_t portbase = xmc4_gpio_portbase(pinconfig); + unsigned int pin = xmc4_gpio_pin(pinconfig); + unsigned int value; + irqstate_t flags; + + flags = enter_critical_section(); + if (GPIO_ISINPUT(pinconfig)) + { + /* Get input pin type (IOCR) */ + + value = xmc4_gpio_pintype(pinconfig); + + /* Check if the input is inverted */ + + if (xmc4_gpio_inverted(pinconfig)) + { + value |= IOCR_INPUT_INVERT; + } + } + else + { + /* Force input while we configure */ + + xmc4_gpio_iocr(portbase, pin, IOCR_INPUT_NOPULL); + + /* Set output value before enabling output */ + + xmc4_gpio_write(pinconfig, ((pinconfig & GPIO_OUTPUT_SET) != 0)); + + /* Get output pin type (IOCR) */ + + value = xmc4_gpio_pintype(pinconfig); + + /* Get if the output is opendrain */ + + if (xmc4_gpio_opendrain(pinconfig)) + { + value |= IOCR_OUTPUT_OPENDRAIN; + } + } + + /* Update the IOCR register to instantiate the pin type */ + + xmc4_gpio_iocr(portbase, pin, value); + + /* Select pin control (HWSEL) */ + + value = xmc4_gpio_pinctrl(pinconfig); + xmc4_gpio_hwsel(portbase, pin, value); + + /* Select drive strength */ + + value = xmc4_gpio_padtype(pinconfig); + xmc4_gpio_pdr(portbase, pin, value); + + /* Enable/enable pad or Analog only (PDISC) */ + + xmc4_gpio_pdisc(portbase, pin, ((pinconfig & GPIO_PAD_DISABLE) != 0)); + + /* Make sure pin is not in power save mode (PDR) */ + + xmc4_gpio_pdisc(portbase, pin, false); + + leave_critical_section(flags); + return OK; } /**************************************************************************** @@ -80,7 +439,28 @@ int xmc4_gpio_config(gpioconfig_t pinconfig) void xmc4_gpio_write(gpioconfig_t pinconfig, bool value) { -#warning Missing logic + uintptr_t portbase = xmc4_gpio_portbase(pinconfig); + unsigned int pin = xmc4_gpio_pin(pinconfig); + uint32_t regval; + uint32_t mask; + + /* Read the OUT register */ + + regval = xmc4_gpio_getreg(portbase, XMC4_PORT_OUT_OFFSET); + + /* Set/clear output value for this pin */ + + mask = PORT_PIN(pin); + if (value) + { + regval |= mask; + } + else + { + regval &= ~mask; + } + + xmc4_gpio_putreg(portbase, XMC4_PORT_OUT_OFFSET, regval); } /**************************************************************************** @@ -93,6 +473,15 @@ void xmc4_gpio_write(gpioconfig_t pinconfig, bool value) bool xmc4_gpio_read(gpioconfig_t pinconfig) { -#warning Missing logic - return false; + uintptr_t portbase = xmc4_gpio_portbase(pinconfig); + unsigned int pin = xmc4_gpio_pin(pinconfig); + uint32_t regval; + + /* Read the OUT register */ + + regval = xmc4_gpio_getreg(portbase, XMC4_PORT_IN_OFFSET); + + /* Return in the input state for this pin */ + + return ((regval & PORT_PIN(pin)) != 0); } diff --git a/arch/arm/src/xmc4/xmc4_gpio.h b/arch/arm/src/xmc4/xmc4_gpio.h index 716d821192..62b11bf048 100644 --- a/arch/arm/src/xmc4/xmc4_gpio.h +++ b/arch/arm/src/xmc4/xmc4_gpio.h @@ -50,16 +50,16 @@ /* 32-bit GIO encoding: * - * .... TTTT TMDD DCC. .... .... PPPP BBBB + * TTTT TMPD DDCC V.... .... .... PPPP BBBB */ /* This identifies the GPIO pint type: * - * .... TTTT T... .... .... .... .... .... + * TTTT T... .... .... .... .... .... .... */ -#define GPIO_PINTYPE_SHIFT (23) /* Bits 23-27: Pin type */ +#define GPIO_PINTYPE_SHIFT (27) /* Bits 27-31: Pin type */ #define GPIO_PINTYPE_MASK (31 << GPIO_PINTYPE_SHIFT) /* See chip/xmc4_ports.h for the IOCR definitions */ @@ -84,60 +84,79 @@ /* Pin type modifier: * - * .... .... .M.. .... .... .... .... .... + * .... .M.. .... .... .... .... .... .... */ -#define GPIO_INPUT_INVERT (1 << 22) /* Inverted direct input modifier */ +#define GPIO_INPUT_INVERT (1 << 26) /* Bit 26: Inverted direct input modifier */ -#define GPIOS_OUTPUT_PUSHPULL (0) /* Push-ull output is the default */ -#define GPIOS_OUTPUT_OPENDRAIN (1 << 22) /* Output drain output modifier */ +#define GPIO_OUTPUT_OPENDRAIN (1 << 26) /* Bit 26: Output drain output modifier */ +#define GPIO_OUTPUT_PUSHPULL (0) /* Push-pull output is the default */ + +/* Disable PAD: + * + * .... ..P. .... ..... .... .... .... .... + * + * For P0-P6, the PDISC register is ready only. + * For P14-P15, the bit setting also selects Analog+Digital or Analog only + */ + +#define GPIO_PAD_DISABLE (1 << 25) /* Bit 25: Disable Pad (P7-P9) */ +#define GPIO_PAD_ANALOG (1 << 25) /* Bit 25: Analog only (P14-P15) */ /* Pad driver strength: * - * .... .... ..DD D... .... .... .... .... + * .... ...D DD.. ..... .... ......... .... */ -#define GPIO_PADTYPE_SHIFT (19) /* Bits 19-21: Pad driver strength */ -#define GPIO_PADTYPE_MASK (7 << GPIO_PADTYPE_SHIFT) +#define GPIO_PADTYPE_SHIFT (22) /* Bits 22-24: Pad driver strength */ +#define GPIO_PADTYPE_MASK (7 << GPIO_PADTYPE_SHIFT) /* See chip/xmc4_ports.h for the PDR definitions */ /* Pad class A1: */ -# define GPIO_PADA1_MEDIUM (PDR_PADA1_MEDIUM << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA1_WEAK (PDR_PADA1_WEAK << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA1_MEDIUM (PDR_PADA1_MEDIUM << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA1_WEAK (PDR_PADA1_WEAK << GPIO_PADTYPE_SHIFT) /* Pad class A1+: */ -# define GPIO_PADA1P_STRONGSOFT (PDR_PADA1P_STRONGSOFT << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA1P_STRONGSLOW (PDR_PADA1P_STRONGSLOW << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA1P_MEDIUM (PDR_PADA1P_MEDIUM << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA1P_WEAK (PDR_PADA1P_WEAK << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA1P_STRONGSOFT (PDR_PADA1P_STRONGSOFT << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA1P_STRONGSLOW (PDR_PADA1P_STRONGSLOW << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA1P_MEDIUM (PDR_PADA1P_MEDIUM << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA1P_WEAK (PDR_PADA1P_WEAK << GPIO_PADTYPE_SHIFT) /* Pad class A2: */ -# define GPIO_PADA2_STRONGSHARP (PDR_PADA2_STRONGSHARP << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA2_STRONGMEDIUM (PDR_PADA2_STRONGMEDIUM << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA2_STRONGSOFT (PDR_PADA2_STRONGSOFT << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA2_MEDIUM (PDR_PADA2_MEDIUM << GPIO_PADTYPE_SHIFT) -# define GPIO_PADA2_WEAK (PDR_PADA2_WEAK << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA2_STRONGSHARP (PDR_PADA2_STRONGSHARP << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA2_STRONGMEDIUM (PDR_PADA2_STRONGMEDIUM << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA2_STRONGSOFT (PDR_PADA2_STRONGSOFT << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA2_MEDIUM (PDR_PADA2_MEDIUM << GPIO_PADTYPE_SHIFT) +# define GPIO_PADA2_WEAK (PDR_PADA2_WEAK << GPIO_PADTYPE_SHIFT) /* Pin control: * - * .... .... .... .CC. .... .... .... .... + * .... .... ..CC ..... .... .... .... .... */ -#define GPIO_PINCTRL_SHIFT (17) /* Bits 17-18: Pad driver strength */ -#define GPIO_PINCTRL_MASK (3 << GPIO_PINCTRL_SHIFT) +#define GPIO_PINCTRL_SHIFT (20) /* Bits 20-21: Pad driver strength */ +#define GPIO_PINCTRL_MASK (3 << GPIO_PINCTRL_SHIFT) /* See chip/xmc4_ports.h for the PDR definitions */ -# define GPIO_PINCTRL_SOFTWARE (HWSEL_SOFTWARE << GPIO_PINCTRL_SHIFT) -# define GPIO_PINCTRL_OVERRIDE0 (HWSEL_OVERRIDE0 << GPIO_PINCTRL_SHIFT) -# define GPIO_PINCTRL_OVERRIDE1 (HWSEL_OVERRIDE1 << GPIO_PINCTRL_SHIFT) +# define GPIO_PINCTRL_SOFTWARE (HWSEL_SOFTWARE << GPIO_PINCTRL_SHIFT) +# define GPIO_PINCTRL_OVERRIDE0 (HWSEL_OVERRIDE0 << GPIO_PINCTRL_SHIFT) +# define GPIO_PINCTRL_OVERRIDE1 (HWSEL_OVERRIDE1 << GPIO_PINCTRL_SHIFT) + +/* If the pin is an GPIO output, then this identifies the initial output value: + * + * .... .... .... V.... .... .... PPPP BBBB + */ + +#define GPIO_OUTPUT_SET (1 << 19) /* Bit 19: Initial value of output */ +#define GPIO_OUTPUT_CLEAR (0) /* This identifies the GPIO port: * - * .... ... .... .... .... .... PPPP .... + * .... .... .... .... .... .... PPPP .... */ #define GPIO_PORT_SHIFT (4) /* Bit 4-7: Port number */