drivers: gpio: update gpio_mcux.c driver

update gpio driver to adapt rt7xx gpio model:
1. There is no PORT_Type on RT7xx,so set PORT_Type as void
2. Add port_no parameter in gpio_mcux_config to adapt IOPCTL driver
3. Add gpio-port-offest parameter in blinding, it will help map the
   relation between index n and gpio port when some soc have domain
   access attribution.
3. Splite gpio_mcux_configure function into two functions(
   gpio_mcux_iopctl_configure and gpio_mcux_port_configure)
   according to CONFIG_PINCTRL_NXP_IOCON macro
4. Add code to adapt RT700 GPIO attribute configuration

Signed-off-by: Lucien Zhao <lucien.zhao@nxp.com>
This commit is contained in:
Lucien Zhao 2024-10-03 23:22:43 +08:00 committed by Benjamin Cabé
commit 87e4db9b86
2 changed files with 118 additions and 17 deletions

View file

@ -17,12 +17,22 @@
#include <zephyr/drivers/gpio/gpio_utils.h>
#if defined(CONFIG_PINCTRL_NXP_IOCON)
#include <fsl_iopctl.h>
#include <fsl_reset.h>
#include <fsl_clock.h>
#include <fsl_gpio.h>
/* Use IOCON to configure electrical characteristic, set PORT_Type as void. */
#define PORT_Type void
#endif
struct gpio_mcux_config {
/* gpio_driver_config needs to be first */
struct gpio_driver_config common;
GPIO_Type *gpio_base;
PORT_Type *port_base;
unsigned int flags;
uint32_t port_no;
};
struct gpio_mcux_data {
@ -32,7 +42,80 @@ struct gpio_mcux_data {
sys_slist_t callbacks;
};
static int gpio_mcux_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
#if defined(CONFIG_PINCTRL_NXP_IOCON)
static int gpio_mcux_iopctl_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
{
const struct gpio_mcux_config *config = dev->config;
GPIO_Type *gpio_base = config->gpio_base;
uint32_t port_no = config->port_no;
volatile uint32_t pinconfig = 0;
if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
return -ENOTSUP;
}
if ((flags & GPIO_SINGLE_ENDED) != 0) {
return -ENOTSUP;
}
/* The flags contain options that require touching registers in the
* GPIO module and the corresponding PORT module.
*
* Start with the GPIO module and set up the pin direction register.
* 0 - pin is input, 1 - pin is output
*/
switch (flags & GPIO_DIR_MASK) {
case GPIO_INPUT:
gpio_base->PDDR &= ~BIT(pin);
/* Enable input buffer for input pins */
pinconfig |= IOPCTL_INBUF_EN;
break;
case GPIO_OUTPUT:
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
gpio_base->PSOR = BIT(pin);
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
gpio_base->PCOR = BIT(pin);
}
gpio_base->PDDR |= BIT(pin);
break;
default:
return -ENOTSUP;
}
/* Select GPIO mux for this pin (func 0 is always GPIO) */
pinconfig |= IOPCTL_FUNC0;
if ((flags & GPIO_PULL_UP) != 0) {
/* Enable and select pull up. */
pinconfig |= (IOPCTL_PUPD_EN | IOPCTL_PULLUP_EN);
} else if ((flags & GPIO_PULL_DOWN) != 0) {
/* Enable and select pull down. */
pinconfig |= (IOPCTL_PUPD_EN | IOPCTL_PULLDOWN_EN);
}
#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH
/* Determine the drive strength */
switch (flags & KINETIS_GPIO_DS_MASK) {
case KINETIS_GPIO_DS_DFLT:
/* Default is low drive strength */
pinconfig |= IOPCTL_DRIVE_100OHM;
break;
case KINETIS_GPIO_DS_ALT:
/* Alternate is high drive strength */
pinconfig |= IOPCTL_DRIVE_33OHM;
break;
default:
return -ENOTSUP;
}
#endif /* defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH */
IOPCTL_PinMuxSet(port_no, pin, pinconfig);
return 0;
}
#else
static int gpio_mcux_port_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
{
const struct gpio_mcux_config *config = dev->config;
GPIO_Type *gpio_base = config->gpio_base;
@ -122,6 +205,7 @@ static int gpio_mcux_configure(const struct device *dev, gpio_pin_t pin, gpio_fl
return 0;
}
#endif /* defined(CONFIG_PINCTRL_NXP_IOCON) */
static int gpio_mcux_port_get_raw(const struct device *dev, uint32_t *value)
{
@ -173,6 +257,7 @@ static int gpio_mcux_port_toggle_bits(const struct device *dev, uint32_t mask)
return 0;
}
#if !(defined(CONFIG_PINCTRL_NXP_IOCON))
#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
static uint32_t get_port_pcr_irqc_value_from_flags(const struct device *dev, uint32_t pin,
enum gpio_int_mode mode, enum gpio_int_trig trig)
@ -208,9 +293,10 @@ static uint32_t get_port_pcr_irqc_value_from_flags(const struct device *dev, uin
return PORT_PCR_IRQC(port_interrupt);
}
#endif /* !defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT */
#endif /* !(defined(CONFIG_PINCTRL_NXP_IOCON)) */
#if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
#if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
#define GPIO_MCUX_INTERRUPT_DISABLED 0
#define GPIO_MCUX_INTERRUPT_LOGIC_0 0x8
@ -259,12 +345,14 @@ static int gpio_mcux_pin_interrupt_configure(const struct device *dev, gpio_pin_
{
const struct gpio_mcux_config *config = dev->config;
GPIO_Type *gpio_base = config->gpio_base;
#if !(defined(CONFIG_PINCTRL_NXP_IOCON))
PORT_Type *port_base = config->port_base;
/* Check for an invalid pin number */
if (pin >= ARRAY_SIZE(port_base->PCR)) {
return -EINVAL;
}
#endif
/* Check for an invalid pin configuration */
if ((mode != GPIO_INT_MODE_DISABLED) && ((gpio_base->PDDR & BIT(pin)) != 0)) {
@ -276,15 +364,15 @@ static int gpio_mcux_pin_interrupt_configure(const struct device *dev, gpio_pin_
return -ENOTSUP;
}
#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
uint32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, mode, trig);
port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr;
#elif (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
#if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
uint32_t icr = get_gpio_icr_irqc_value_from_flags(dev, pin, mode, trig);
gpio_base->ICR[pin] = (gpio_base->ICR[pin] & ~GPIO_ICR_IRQC_MASK) | icr;
#elif !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
uint32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, mode, trig);
port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr;
#endif /* !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) */
return 0;
@ -304,17 +392,17 @@ static void gpio_mcux_port_isr(const struct device *dev)
struct gpio_mcux_data *data = dev->data;
uint32_t int_status;
#if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
int_status = config->port_base->ISFR;
/* Clear the port interrupts */
config->port_base->ISFR = int_status;
#elif (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
#if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
int_status = config->gpio_base->ISFR[0];
/* Clear the gpio interrupts */
config->gpio_base->ISFR[0] = int_status;
#elif !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
int_status = config->port_base->ISFR;
/* Clear the port interrupts */
config->port_base->ISFR = int_status;
#else
int_status = 0U;
ARG_UNUSED(config);
@ -377,7 +465,11 @@ static int gpio_mcux_port_get_direction(const struct device *dev, gpio_port_pins
#endif /* CONFIG_GPIO_GET_DIRECTION */
static DEVICE_API(gpio, gpio_mcux_driver_api) = {
.pin_configure = gpio_mcux_configure,
#if defined(CONFIG_PINCTRL_NXP_IOCON)
.pin_configure = gpio_mcux_iopctl_configure,
#else
.pin_configure = gpio_mcux_port_configure,
#endif
.port_get_raw = gpio_mcux_port_get_raw,
.port_set_masked_raw = gpio_mcux_port_set_masked_raw,
.port_set_bits_raw = gpio_mcux_port_set_bits_raw,
@ -399,6 +491,8 @@ static DEVICE_API(gpio, gpio_mcux_driver_api) = {
} while (false)
#define GPIO_PORT_BASE_ADDR(n) DT_REG_ADDR(DT_INST_PHANDLE(n, nxp_kinetis_port))
#define GPIO_PORT_NUMBER(n) COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpio_port_offest), \
(DT_INST_PROP(n, gpio_port_offest) + n), (n)) \
#define GPIO_DEVICE_INIT_MCUX(n) \
static int gpio_mcux_port##n##_init(const struct device *dev); \
@ -412,6 +506,7 @@ static DEVICE_API(gpio, gpio_mcux_driver_api) = {
.port_base = (PORT_Type *)GPIO_PORT_BASE_ADDR(n), \
.flags = UTIL_AND(UTIL_OR(DT_INST_IRQ_HAS_IDX(n, 0), GPIO_HAS_SHARED_IRQ), \
GPIO_INT_ENABLE), \
.port_no = GPIO_PORT_NUMBER(n), \
}; \
\
static struct gpio_mcux_data gpio_mcux_port##n##_data; \

View file

@ -18,6 +18,12 @@ properties:
A phandle reference to the device tree node that contains the pinmux
port associated with this GPIO controller.
gpio-port-offest:
type: int
default: 0
description: |
Describes an offset between inst index and actual GPIO port number.
gpio-cells:
- pin
- flags