drivers: gpio_mcux: update to use new GPIO API

Update driver code and board files to use new GPIO configuration flags
such as GPIO_ACTIVE_LOW. Also add implementation of new port_* driver
API as well as gpio_pin_interrupt_configure function.

Tested on frdm_k64f board.

Signed-off-by: Piotr Mienkowski <piotr.mienkowski@gmail.com>
This commit is contained in:
Piotr Mienkowski 2019-08-09 01:28:40 +02:00 committed by Carles Cufí
commit 30a97ce28e
7 changed files with 198 additions and 64 deletions

View file

@ -29,15 +29,15 @@
leds {
compatible = "gpio-leds";
red_led: led_0 {
gpios = <&gpiob 22 0>;
gpios = <&gpiob 22 GPIO_ACTIVE_LOW>;
label = "User LD1";
};
green_led: led_1 {
gpios = <&gpioe 26 0>;
gpios = <&gpioe 26 GPIO_ACTIVE_LOW>;
label = "User LD2";
};
blue_led: led_2 {
gpios = <&gpiob 21 0>;
gpios = <&gpiob 21 GPIO_ACTIVE_LOW>;
label = "User LD3";
};
};
@ -46,11 +46,11 @@
compatible = "gpio-keys";
user_button_2: button_0 {
label = "User SW2";
gpios = <&gpioc 6 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpioc 6 GPIO_ACTIVE_LOW>;
};
user_button_3: button_1 {
label = "User SW3";
gpios = <&gpioa 4 (GPIO_INT_ACTIVE_LOW | GPIO_PUD_PULL_UP)>;
gpios = <&gpioa 4 GPIO_ACTIVE_LOW>;
};
};

View file

@ -26,15 +26,15 @@
leds {
compatible = "gpio-leds";
red_led: led_0 {
gpios = <&gpiob 18 0>;
gpios = <&gpiob 18 GPIO_ACTIVE_LOW>;
label = "User LD1";
};
green_led: led_1 {
gpios = <&gpiob 19 0>;
gpios = <&gpiob 19 GPIO_ACTIVE_LOW>;
label = "User LD2";
};
blue_led: led_2 {
gpios = <&gpiod 1 0>;
gpios = <&gpiod 1 GPIO_ACTIVE_LOW>;
label = "User LD3";
};
};
@ -43,11 +43,11 @@
compatible = "gpio-keys";
user_button_0: button_0 {
label = "User SW0";
gpios = <&gpioa 16 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpioa 16 GPIO_ACTIVE_LOW>;
};
user_button_1: button_1 {
label = "User SW1";
gpios = <&gpioa 17 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpioa 17 GPIO_ACTIVE_LOW>;
};
};

View file

@ -26,15 +26,15 @@
leds {
compatible = "gpio-leds";
red_led: led_0 {
gpios = <&gpioc 1 0>;
gpios = <&gpioc 1 GPIO_ACTIVE_LOW>;
label = "User LD1";
};
green_led: led_1 {
gpios = <&gpioa 19 0>;
gpios = <&gpioa 19 GPIO_ACTIVE_LOW>;
label = "User LD2";
};
blue_led: led_2 {
gpios = <&gpioa 18 0>;
gpios = <&gpioa 18 GPIO_ACTIVE_LOW>;
label = "User LD3";
};
};
@ -43,11 +43,11 @@
compatible = "gpio-keys";
user_button_3: button_0 {
label = "User SW3";
gpios = <&gpioc 4 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpioc 4 GPIO_ACTIVE_LOW>;
};
user_button_4: button_1 {
label = "User SW4";
gpios = <&gpioc 5 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpioc 5 GPIO_ACTIVE_LOW>;
};
};

View file

@ -31,15 +31,15 @@
leds {
compatible = "gpio-leds";
red_led: led_0 {
gpios = <&gpioc 8 0>;
gpios = <&gpioc 8 GPIO_ACTIVE_LOW>;
label = "User LD1";
};
green_led: led_1 {
gpios = <&gpiod 0 0>;
gpios = <&gpiod 0 GPIO_ACTIVE_LOW>;
label = "User LD2";
};
blue_led: led_2 {
gpios = <&gpioc 9 0>;
gpios = <&gpioc 9 GPIO_ACTIVE_LOW>;
label = "User LD3";
};
};

View file

@ -46,32 +46,32 @@
leds {
compatible = "gpio-leds";
orange_led: led_0 {
gpios = <&gpioc 13 0>;
gpios = <&gpioc 13 GPIO_ACTIVE_LOW>;
label = "User LED D9";
};
yellow_led: led_1 {
gpios = <&gpioc 12 0>;
gpios = <&gpioc 12 GPIO_ACTIVE_LOW>;
label = "User LED D8";
};
green_led: led_2 {
gpios = <&gpioc 11 0>;
gpios = <&gpioc 11 GPIO_ACTIVE_LOW>;
label = "User LED D7";
};
red_led: led_3 {
gpios = <&gpioc 10 0>;
gpios = <&gpioc 10 GPIO_ACTIVE_LOW>;
label = "User LED D6";
};
tri_red_led: led_4 {
gpios = <&gpiod 16 0>;
gpios = <&gpiod 16 GPIO_ACTIVE_LOW>;
label = "User Tricolor LED D5 (Red)";
};
tri_green_led: led_5 {
gpios = <&gpiod 15 0>;
gpios = <&gpiod 15 GPIO_ACTIVE_LOW>;
label = "User Tricolor LED D5 (Green)";
};
tri_blue_led: led_6 {
gpios = <&gpiob 5 0>;
gpios = <&gpiob 5 GPIO_ACTIVE_LOW>;
label = "User Tricolor LED D5 (Blue)";
};
};
@ -113,11 +113,11 @@
compatible = "gpio-keys";
user_button_2: button_0 {
label = "User SW2";
gpios = <&gpiod 3 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpiod 3 GPIO_ACTIVE_LOW>;
};
user_button_3: button_1 {
label = "User SW3";
gpios = <&gpiod 6 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpiod 6 GPIO_ACTIVE_LOW>;
};
};
};

View file

@ -25,11 +25,11 @@
leds {
compatible = "gpio-leds";
led_0: led_0 {
gpios = <&gpiod 4 0>;
gpios = <&gpiod 4 GPIO_ACTIVE_LOW>;
label = "User LD1";
};
led_1: led_1 {
gpios = <&gpiod 5 0>;
gpios = <&gpiod 5 GPIO_ACTIVE_LOW>;
label = "User LD2";
};
};
@ -38,7 +38,7 @@
compatible = "gpio-keys";
user_button_1: button_0 {
label = "User SW1";
gpios = <&gpioc 4 GPIO_INT_ACTIVE_LOW>;
gpios = <&gpioc 4 GPIO_ACTIVE_LOW>;
};
};
};

View file

@ -21,19 +21,60 @@ struct gpio_mcux_config {
};
struct gpio_mcux_data {
struct gpio_driver_data general;
/* port ISR callback routine address */
sys_slist_t callbacks;
/* pin callback routine enable flags, by pin number */
u32_t pin_callback_enables;
};
static u32_t get_port_pcr_irqc_value_from_flags(struct device *dev,
u32_t pin, unsigned int flags)
{
struct gpio_mcux_data *data = dev->driver_data;
port_interrupt_t port_interrupt = 0;
bool rising_edge;
bool falling_edge;
if ((flags & GPIO_INT_LEVELS_LOGICAL) &&
(data->general.invert & BIT(pin))) {
rising_edge = flags & GPIO_INT_LOW_0;
falling_edge = flags & GPIO_INT_HIGH_1;
} else {
rising_edge = flags & GPIO_INT_HIGH_1;
falling_edge = flags & GPIO_INT_LOW_0;
}
if (flags & GPIO_INT_ENABLE) {
if (flags & GPIO_INT_EDGE) {
if (rising_edge && falling_edge) {
port_interrupt = kPORT_InterruptEitherEdge;
} else if (rising_edge) {
port_interrupt = kPORT_InterruptRisingEdge;
} else {
port_interrupt = kPORT_InterruptFallingEdge;
}
} else { /* GPIO_INT_LEVEL */
if (rising_edge) {
port_interrupt = kPORT_InterruptLogicOne;
} else {
port_interrupt = kPORT_InterruptLogicZero;
}
}
} else {
port_interrupt = kPORT_InterruptOrDMADisabled;
}
return PORT_PCR_IRQC(port_interrupt);
}
static int gpio_mcux_configure(struct device *dev,
int access_op, u32_t pin, int flags)
{
const struct gpio_mcux_config *config = dev->config->config_info;
GPIO_Type *gpio_base = config->gpio_base;
PORT_Type *port_base = config->port_base;
port_interrupt_t port_interrupt = 0;
struct gpio_mcux_data *data = dev->driver_data;
u32_t mask = 0U;
u32_t pcr = 0U;
u8_t i;
@ -44,15 +85,30 @@ static int gpio_mcux_configure(struct device *dev,
}
/* Check for an invalid pin configuration */
if ((flags & GPIO_INT) && (flags & GPIO_DIR_OUT)) {
if ((flags & GPIO_INT_ENABLE) && ((flags & GPIO_INPUT) == 0)) {
return -EINVAL;
}
/* Check if GPIO port supports interrupts */
if ((flags & GPIO_INT) && ((config->flags & GPIO_INT) == 0U)) {
if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
return -ENOTSUP;
}
if ((flags & GPIO_SINGLE_ENDED) != 0) {
return -ENOTSUP;
}
/* Check if GPIO port supports interrupts */
if ((flags & GPIO_INT_ENABLE) &&
((config->flags & GPIO_INT_ENABLE) == 0U)) {
return -ENOTSUP;
}
if ((flags & GPIO_ACTIVE_LOW) != 0) {
data->general.invert |= BIT(pin);
} else {
data->general.invert &= ~BIT(pin);
}
/* The flags contain options that require touching registers in the
* GPIO module and the corresponding PORT module.
*
@ -61,15 +117,20 @@ static int gpio_mcux_configure(struct device *dev,
*/
if (access_op == GPIO_ACCESS_BY_PIN) {
if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) {
if ((flags & GPIO_INPUT) != 0) {
gpio_base->PDDR &= ~BIT(pin);
} else { /* GPIO_DIR_OUT */
} else { /* 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);
}
} else { /* GPIO_ACCESS_BY_PORT */
if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) {
if ((flags & GPIO_INPUT) != 0) {
gpio_base->PDDR = 0x0;
} else { /* GPIO_DIR_OUT */
} else { /* GPIO_OUTPUT */
gpio_base->PDDR = 0xFFFFFFFF;
}
}
@ -79,11 +140,11 @@ static int gpio_mcux_configure(struct device *dev,
*/
mask |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) {
if ((flags & GPIO_PULL_UP) != 0) {
/* Enable the pull and select the pullup resistor. */
pcr |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
} else if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) {
} else if ((flags & GPIO_PULL_DOWN) != 0) {
/* Enable the pull and select the pulldown resistor (deselect
* the pullup resistor.
*/
@ -94,25 +155,7 @@ static int gpio_mcux_configure(struct device *dev,
* but don't write it to the PCR register yet.
*/
mask |= PORT_PCR_IRQC_MASK;
if (flags & GPIO_INT) {
if (flags & GPIO_INT_EDGE) {
if (flags & GPIO_INT_ACTIVE_HIGH) {
port_interrupt = kPORT_InterruptRisingEdge;
} else if (flags & GPIO_INT_DOUBLE_EDGE) {
port_interrupt = kPORT_InterruptEitherEdge;
} else {
port_interrupt = kPORT_InterruptFallingEdge;
}
} else { /* GPIO_INT_LEVEL */
if (flags & GPIO_INT_ACTIVE_HIGH) {
port_interrupt = kPORT_InterruptLogicOne;
} else {
port_interrupt = kPORT_InterruptLogicZero;
}
}
pcr |= PORT_PCR_IRQC(port_interrupt);
}
pcr |= get_port_pcr_irqc_value_from_flags(dev, pin, flags);
/* Now we can write the PORT PCR register(s). If accessing by pin, we
* only need to write one PCR register. Otherwise, write all the PCR
@ -120,10 +163,17 @@ static int gpio_mcux_configure(struct device *dev,
*/
if (access_op == GPIO_ACCESS_BY_PIN) {
port_base->PCR[pin] = (port_base->PCR[pin] & ~mask) | pcr;
WRITE_BIT(data->pin_callback_enables, pin,
flags & GPIO_INT_ENABLE);
} else { /* GPIO_ACCESS_BY_PORT */
for (i = 0U; i < ARRAY_SIZE(port_base->PCR); i++) {
port_base->PCR[i] = (port_base->PCR[pin] & ~mask) | pcr;
}
if (flags & GPIO_INT_ENABLE) {
data->pin_callback_enables = 0xFFFFFFFF;
} else {
data->pin_callback_enables = 0x0;
}
}
return 0;
@ -174,6 +224,84 @@ static int gpio_mcux_read(struct device *dev,
return 0;
}
static int gpio_mcux_port_get_raw(struct device *dev, u32_t *value)
{
const struct gpio_mcux_config *config = dev->config->config_info;
GPIO_Type *gpio_base = config->gpio_base;
*value = gpio_base->PDIR;
return 0;
}
static int gpio_mcux_port_set_masked_raw(struct device *dev, u32_t mask,
u32_t value)
{
const struct gpio_mcux_config *config = dev->config->config_info;
GPIO_Type *gpio_base = config->gpio_base;
gpio_base->PDOR = (gpio_base->PDOR & ~mask) | (mask & value);
return 0;
}
static int gpio_mcux_port_set_bits_raw(struct device *dev, u32_t mask)
{
const struct gpio_mcux_config *config = dev->config->config_info;
GPIO_Type *gpio_base = config->gpio_base;
gpio_base->PSOR = mask;
return 0;
}
static int gpio_mcux_port_clear_bits_raw(struct device *dev, u32_t mask)
{
const struct gpio_mcux_config *config = dev->config->config_info;
GPIO_Type *gpio_base = config->gpio_base;
gpio_base->PCOR = mask;
return 0;
}
static int gpio_mcux_port_toggle_bits(struct device *dev, u32_t mask)
{
const struct gpio_mcux_config *config = dev->config->config_info;
GPIO_Type *gpio_base = config->gpio_base;
gpio_base->PTOR = mask;
return 0;
}
static int gpio_mcux_pin_interrupt_configure(struct device *dev,
unsigned int pin, unsigned int flags)
{
const struct gpio_mcux_config *config = dev->config->config_info;
PORT_Type *port_base = config->port_base;
struct gpio_mcux_data *data = dev->driver_data;
/* Check for an invalid pin number */
if (pin >= ARRAY_SIZE(port_base->PCR)) {
return -EINVAL;
}
/* Check if GPIO port supports interrupts */
if ((flags & GPIO_INT_ENABLE) &&
((config->flags & GPIO_INT_ENABLE) == 0U)) {
return -ENOTSUP;
}
u32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, flags);
port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr;
WRITE_BIT(data->pin_callback_enables, pin, flags & GPIO_INT_ENABLE);
return 0;
}
static int gpio_mcux_manage_callback(struct device *dev,
struct gpio_callback *callback, bool set)
{
@ -231,6 +359,12 @@ static const struct gpio_driver_api gpio_mcux_driver_api = {
.config = gpio_mcux_configure,
.write = gpio_mcux_write,
.read = gpio_mcux_read,
.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,
.port_clear_bits_raw = gpio_mcux_port_clear_bits_raw,
.port_toggle_bits = gpio_mcux_port_toggle_bits,
.pin_interrupt_configure = gpio_mcux_pin_interrupt_configure,
.manage_callback = gpio_mcux_manage_callback,
.enable_callback = gpio_mcux_enable_callback,
.disable_callback = gpio_mcux_disable_callback,
@ -243,7 +377,7 @@ static const struct gpio_mcux_config gpio_mcux_porta_config = {
.gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_A_BASE_ADDRESS,
.port_base = PORTA,
#ifdef DT_NXP_KINETIS_GPIO_GPIO_A_IRQ_0
.flags = GPIO_INT,
.flags = GPIO_INT_ENABLE,
#else
.flags = 0,
#endif
@ -276,7 +410,7 @@ static const struct gpio_mcux_config gpio_mcux_portb_config = {
.gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_B_BASE_ADDRESS,
.port_base = PORTB,
#ifdef DT_NXP_KINETIS_GPIO_GPIO_B_IRQ_0
.flags = GPIO_INT,
.flags = GPIO_INT_ENABLE,
#else
.flags = 0,
#endif
@ -309,7 +443,7 @@ static const struct gpio_mcux_config gpio_mcux_portc_config = {
.gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_C_BASE_ADDRESS,
.port_base = PORTC,
#ifdef DT_NXP_KINETIS_GPIO_GPIO_C_IRQ_0
.flags = GPIO_INT,
.flags = GPIO_INT_ENABLE,
#else
.flags = 0,
#endif
@ -342,7 +476,7 @@ static const struct gpio_mcux_config gpio_mcux_portd_config = {
.gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_D_BASE_ADDRESS,
.port_base = PORTD,
#ifdef DT_NXP_KINETIS_GPIO_GPIO_D_IRQ_0
.flags = GPIO_INT,
.flags = GPIO_INT_ENABLE,
#else
.flags = 0,
#endif
@ -375,7 +509,7 @@ static const struct gpio_mcux_config gpio_mcux_porte_config = {
.gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_E_BASE_ADDRESS,
.port_base = PORTE,
#ifdef DT_NXP_KINETIS_GPIO_GPIO_E_IRQ_0
.flags = GPIO_INT,
.flags = GPIO_INT_ENABLE,
#else
.flags = 0,
#endif