diff --git a/drivers/gpio/gpio_mcux.c b/drivers/gpio/gpio_mcux.c index 6f07050b932..9346c23129c 100644 --- a/drivers/gpio/gpio_mcux.c +++ b/drivers/gpio/gpio_mcux.c @@ -17,12 +17,22 @@ #include +#if defined(CONFIG_PINCTRL_NXP_IOCON) +#include +#include +#include +#include +/* 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; \ diff --git a/dts/bindings/gpio/nxp,kinetis-gpio.yaml b/dts/bindings/gpio/nxp,kinetis-gpio.yaml index 845a13714e0..1ee1c8db0dd 100644 --- a/dts/bindings/gpio/nxp,kinetis-gpio.yaml +++ b/dts/bindings/gpio/nxp,kinetis-gpio.yaml @@ -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