drivers: gpio_mcux: Add support for GPIO ICR

Add support for devices that use the kinetis
GPIO/PORT scheme but with the slight modification
that the interrupt control bits are in the GPIO
peripheral instead of the PORT peripheral.

Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
This commit is contained in:
Declan Snyder 2023-01-17 17:19:41 -06:00 committed by Fabio Baltieri
parent 205a8fed79
commit 5254fcbd0a

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016 Freescale Semiconductor, Inc.
* Copyright (c) 2017, NXP
* Copyright 2017, 2023-2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -96,7 +96,7 @@ static int gpio_mcux_configure(const struct device *dev,
pcr |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
} else if ((flags & GPIO_PULL_DOWN) != 0) {
/* Enable the pull and select the pulldown resistor (deselect
/* Enable the pull and select the pulldown resistor, deselect
* the pullup resistor.
*/
pcr |= PORT_PCR_PE_MASK;
@ -178,6 +178,7 @@ static int gpio_mcux_port_toggle_bits(const struct device *dev, uint32_t mask)
return 0;
}
#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,
@ -213,6 +214,54 @@ static uint32_t get_port_pcr_irqc_value_from_flags(const struct device *dev,
return PORT_PCR_IRQC(port_interrupt);
}
#endif /* !defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT */
#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
#define GPIO_MCUX_INTERRUPT_RISING_EDGE 0x9
#define GPIO_MCUX_INTERRUPT_FALLING_EDGE 0xA
#define GPIO_MCUX_INTERRUPT_BOTH_EDGE 0xB
#define GPIO_MCUX_INTERRUPT_LOGIC_1 0xC
static uint32_t get_gpio_icr_irqc_value_from_flags(const struct device *dev,
uint32_t pin,
enum gpio_int_mode mode,
enum gpio_int_trig trig)
{
uint8_t gpio_interrupt = 0;
if (mode == GPIO_INT_MODE_DISABLED) {
gpio_interrupt = GPIO_MCUX_INTERRUPT_DISABLED;
} else {
if (mode == GPIO_INT_MODE_LEVEL) {
if (trig == GPIO_INT_TRIG_LOW) {
gpio_interrupt = GPIO_MCUX_INTERRUPT_LOGIC_0;
} else {
gpio_interrupt = GPIO_MCUX_INTERRUPT_LOGIC_1;
}
} else {
switch (trig) {
case GPIO_INT_TRIG_LOW:
gpio_interrupt = GPIO_MCUX_INTERRUPT_FALLING_EDGE;
break;
case GPIO_INT_TRIG_HIGH:
gpio_interrupt = GPIO_MCUX_INTERRUPT_RISING_EDGE;
break;
case GPIO_INT_TRIG_BOTH:
gpio_interrupt = GPIO_MCUX_INTERRUPT_BOTH_EDGE;
break;
default:
return -EINVAL;
}
}
}
return GPIO_ICR_IRQC(gpio_interrupt);
}
#endif /* (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) */
static int gpio_mcux_pin_interrupt_configure(const struct device *dev,
gpio_pin_t pin, enum gpio_int_mode mode,
@ -239,9 +288,16 @@ static int gpio_mcux_pin_interrupt_configure(const struct device *dev,
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)
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;
#endif /* !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) */
return 0;
}
@ -260,10 +316,18 @@ 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)
int_status = config->gpio_base->ISFR[0];
/* Clear the gpio interrupts */
config->gpio_base->ISFR[0] = int_status;
#endif /* !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) */
gpio_fire_callbacks(&data->callbacks, dev, int_status);
}