blob: 8b94e1ddd776253e6fa716d6081b6c9dbbc4092c [file] [log] [blame]
/****************************************************************************
* arch/arm/src/xmc4/xmc4_gpio.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/board/board.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include "arm_internal.h"
#include "hardware/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 enable)
{
uint32_t regval;
uint32_t mask;
/* Read the PDISC register */
regval = xmc4_gpio_getreg(portbase, XMC4_PORT_PDISC_OFFSET);
/* Set or clear the pin field in the PDISC register.
*
* Disable = set
* Analog = set
* Enable = clear
*/
mask = PORT_PIN(pin);
if (enable)
{
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 powersave)
{
uint32_t regval;
uint32_t mask;
/* Read the PPS register */
regval = xmc4_gpio_getreg(portbase, XMC4_PORT_PPS_OFFSET);
/* Set/clear the enable/disable power save value for this field */
mask = PORT_PIN(pin);
if (powersave)
{
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 PDR register */
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
*
****************************************************************************/
static inline bool xmc4_gpio_opendrain(gpioconfig_t pinconfig)
{
return ((pinconfig & GPIO_OUTPUT_OPENDRAIN) != 0);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: xmc4_gpio_config
*
* Description:
* Configure a PIN based on bit-encoded description of the pin,
* 'pincconfig'.
*
****************************************************************************/
int xmc4_gpio_config(gpioconfig_t pinconfig)
{
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 (PDR) */
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 (PPS) */
xmc4_gpio_pps(portbase, pin, false);
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: xmc4_gpio_write
*
* Description:
* Write one or zero to the PORT pin selected by 'pinconfig'
*
****************************************************************************/
void xmc4_gpio_write(gpioconfig_t pinconfig, bool value)
{
uintptr_t portbase = xmc4_gpio_portbase(pinconfig);
unsigned int pin = xmc4_gpio_pin(pinconfig);
uint32_t regval;
/* Setup OMR value for this pin:
*
* PRx PSx Function
* 0 0 Bit Pn_OUT.Px is not changed.
* 0 1 Bit Pn_OUT.Px is set.
* 1 0 Bit Pn_OUT.Px is reset.
* 1 1 Bit Pn_OUT.Px is toggled.
*/
if (value)
{
/* PRx==0; PSx==1 -> Set output */
regval = OMR_PS(pin);
}
else
{
/* PRx==1; PSx==0 -> Reset output */
regval = OMR_PR(pin);
}
/* Set/clear the OUTPUT. This is an atomoc operation so no critical
* section is needed.
*/
xmc4_gpio_putreg(portbase, XMC4_PORT_OMR_OFFSET, regval);
}
/****************************************************************************
* Name: xmc4_gpio_read
*
* Description:
* Read one or zero from the PORT pin selected by 'pinconfig'
*
****************************************************************************/
bool xmc4_gpio_read(gpioconfig_t pinconfig)
{
uintptr_t portbase = xmc4_gpio_portbase(pinconfig);
unsigned int pin = xmc4_gpio_pin(pinconfig);
uint32_t regval;
/* Read the OUT register. This is an atomoc operation so no critical
* section is needed.
*/
regval = xmc4_gpio_getreg(portbase, XMC4_PORT_IN_OFFSET);
/* Return in the input state for this pin at the time is was read */
return ((regval & PORT_PIN(pin)) != 0);
}