XMC4xxx: Finishes implementation of GPIO support.

This commit is contained in:
Gregory Nutt 2017-03-17 13:02:07 -06:00
parent 41758d8e4c
commit 8bfb735351
4 changed files with 450 additions and 33 deletions

View File

@ -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

View File

@ -58,6 +58,8 @@
#include <nuttx/config.h>
#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 */

View File

@ -44,6 +44,7 @@
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#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);
}

View File

@ -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 */