zephyr/drivers/gpio/gpio_imx.c
Stanislav Poboril 6422e1a36b gpio: Update imx gpio driver to use new gpio api
Updates the imx gpio driver and all associated boards to use new
device tree compatible gpio configuration flags. Implements new port
get/set/clear/toggle and pin_interrupt_configure functions recently
added to the gpio api.

Assumes the gpio api layer handles translating logical flags to physical
flags.

Tested with:
- samples/basic/blinky
- samples/basic/button
- tests/drivers/gpio/gpio_api_1pin
- tests/drivers/gpio/gpio_basic_api

On boards:
- udoo_neo_full_m4

Signed-off-by: Stanislav Poboril <stanislav.poboril@nxp.com>
2020-02-05 12:00:36 +01:00

517 lines
13 KiB
C

/*
* Copyright (c) 2018-2019, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <device.h>
#include <drivers/gpio.h>
#include <soc.h>
#include <sys/util.h>
#include <gpio_imx.h>
#include "gpio_utils.h"
struct imx_gpio_config {
GPIO_Type *base;
};
struct imx_gpio_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data common;
/* port ISR callback routine address */
sys_slist_t callbacks;
/* pin callback routine enable flags, by pin number */
u32_t pin_callback_enables;
};
static int imx_gpio_configure(struct device *port, int access_op, u32_t pin,
int flags)
{
const struct imx_gpio_config *config = port->config->config_info;
GPIO_Type *base = config->base;
if (access_op != GPIO_ACCESS_BY_PIN) {
return -ENOTSUP;
}
if (((flags & GPIO_INPUT) != 0U) && ((flags & GPIO_OUTPUT) != 0U)) {
return -ENOTSUP;
}
if ((flags & (GPIO_SINGLE_ENDED
| GPIO_PULL_UP
| GPIO_PULL_DOWN)) != 0U) {
return -ENOTSUP;
}
/* Disable interrupts for pin */
GPIO_SetPinIntMode(base, pin, false);
GPIO_SetIntEdgeSelect(base, pin, false);
if ((flags & GPIO_OUTPUT) != 0U) {
/* Set output pin initial value */
if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
GPIO_WritePinOutput(base, pin, gpioPinClear);
} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
GPIO_WritePinOutput(base, pin, gpioPinSet);
}
/* Set pin as output */
WRITE_BIT(base->GDIR, pin, 1U);
} else {
/* Set pin as input */
WRITE_BIT(base->GDIR, pin, 0U);
}
return 0;
}
static int imx_gpio_write(struct device *port,
int access_op, u32_t pin, u32_t value)
{
const struct imx_gpio_config *config = port->config->config_info;
if (access_op == GPIO_ACCESS_BY_PIN) {
GPIO_WritePinOutput(config->base, pin,
(gpio_pin_action_t)value);
} else { /* GPIO_ACCESS_BY_PORT */
GPIO_WritePortOutput(config->base, value);
}
return 0;
}
static int imx_gpio_read(struct device *port,
int access_op, u32_t pin, u32_t *value)
{
const struct imx_gpio_config *config = port->config->config_info;
if (access_op == GPIO_ACCESS_BY_PIN) {
*value = GPIO_ReadPinInput(config->base, pin);
} else { /* GPIO_ACCESS_BY_PORT */
*value = GPIO_ReadPortInput(config->base);
}
return 0;
}
static int imx_gpio_port_get_raw(struct device *port, u32_t *value)
{
const struct imx_gpio_config *config = port->config->config_info;
GPIO_Type *base = config->base;
*value = GPIO_ReadPortInput(base);
return 0;
}
static int imx_gpio_port_set_masked_raw(struct device *port,
gpio_port_pins_t mask,
gpio_port_value_t value)
{
const struct imx_gpio_config *config = port->config->config_info;
GPIO_Type *base = config->base;
GPIO_WritePortOutput(base,
(GPIO_ReadPortInput(base) & ~mask) | (value & mask));
return 0;
}
static int imx_gpio_port_set_bits_raw(struct device *port,
gpio_port_pins_t pins)
{
const struct imx_gpio_config *config = port->config->config_info;
GPIO_Type *base = config->base;
GPIO_WritePortOutput(base, GPIO_ReadPortInput(base) | pins);
return 0;
}
static int imx_gpio_port_clear_bits_raw(struct device *port,
gpio_port_pins_t pins)
{
const struct imx_gpio_config *config = port->config->config_info;
GPIO_Type *base = config->base;
GPIO_WritePortOutput(base, GPIO_ReadPortInput(base) & ~pins);
return 0;
}
static int imx_gpio_port_toggle_bits(struct device *port, gpio_port_pins_t pins)
{
const struct imx_gpio_config *config = port->config->config_info;
GPIO_Type *base = config->base;
GPIO_WritePortOutput(base, GPIO_ReadPortInput(base) ^ pins);
return 0;
}
static int imx_gpio_pin_interrupt_configure(struct device *port,
unsigned int pin,
enum gpio_int_mode mode,
enum gpio_int_trig trig)
{
const struct imx_gpio_config *config = port->config->config_info;
struct imx_gpio_data *data = port->driver_data;
GPIO_Type *base = config->base;
volatile u32_t *icr_reg;
unsigned int key;
u32_t icr_val;
u8_t shift;
if (((base->GDIR & BIT(pin)) != 0U)
&& (mode != GPIO_INT_MODE_DISABLED)) {
/* Interrupt on output pin not supported */
return -ENOTSUP;
}
if ((mode == GPIO_INT_MODE_EDGE) && (trig == GPIO_INT_TRIG_LOW)) {
icr_val = 3U;
} else if ((mode == GPIO_INT_MODE_EDGE) &&
(trig == GPIO_INT_TRIG_HIGH)) {
icr_val = 2U;
} else if ((mode == GPIO_INT_MODE_LEVEL) &&
(trig == GPIO_INT_TRIG_HIGH)) {
icr_val = 1U;
} else {
icr_val = 0U;
}
if (pin < 16U) {
shift = 2U * pin;
icr_reg = &(base->ICR1);
} else if (pin < 32U) {
shift = 2U * (pin - 16U);
icr_reg = &(base->ICR2);
} else {
return -EINVAL;
}
key = irq_lock();
*icr_reg = (*icr_reg & ~(3U << shift)) | (icr_val << shift);
WRITE_BIT(base->EDGE_SEL, pin, trig == GPIO_INT_TRIG_BOTH);
WRITE_BIT(base->ISR, pin, mode != GPIO_INT_MODE_DISABLED);
WRITE_BIT(base->IMR, pin, mode != GPIO_INT_MODE_DISABLED);
WRITE_BIT(data->pin_callback_enables, pin,
mode != GPIO_INT_MODE_DISABLED);
irq_unlock(key);
return 0;
}
static int imx_gpio_manage_callback(struct device *port,
struct gpio_callback *cb, bool set)
{
struct imx_gpio_data *data = port->driver_data;
return gpio_manage_callback(&data->callbacks, cb, set);
}
static int imx_gpio_enable_callback(struct device *port, int access_op,
u32_t pin)
{
const struct imx_gpio_config *config = port->config->config_info;
struct imx_gpio_data *data = port->driver_data;
u32_t i;
if (access_op == GPIO_ACCESS_BY_PIN) {
data->pin_callback_enables |= BIT(pin);
GPIO_SetPinIntMode(config->base, pin, true);
} else {
data->pin_callback_enables = 0xFFFFFFFFU;
for (i = 0U; i < 32U; i++) {
GPIO_SetPinIntMode(config->base, i, true);
}
}
return 0;
}
static int imx_gpio_disable_callback(struct device *port, int access_op,
u32_t pin)
{
const struct imx_gpio_config *config = port->config->config_info;
struct imx_gpio_data *data = port->driver_data;
u32_t i;
if (access_op == GPIO_ACCESS_BY_PIN) {
GPIO_SetPinIntMode(config->base, pin, false);
data->pin_callback_enables &= ~BIT(pin);
} else {
for (i = 0U; i < 32U; i++) {
GPIO_SetPinIntMode(config->base, i, false);
}
data->pin_callback_enables = 0U;
}
return 0;
}
static void imx_gpio_port_isr(void *arg)
{
struct device *port = (struct device *)arg;
const struct imx_gpio_config *config = port->config->config_info;
struct imx_gpio_data *data = port->driver_data;
u32_t enabled_int;
enabled_int = config->base->ISR & data->pin_callback_enables;
config->base->ISR = enabled_int;
gpio_fire_callbacks(&data->callbacks, port, enabled_int);
}
static const struct gpio_driver_api imx_gpio_driver_api = {
.config = imx_gpio_configure,
.write = imx_gpio_write,
.read = imx_gpio_read,
.port_get_raw = imx_gpio_port_get_raw,
.port_set_masked_raw = imx_gpio_port_set_masked_raw,
.port_set_bits_raw = imx_gpio_port_set_bits_raw,
.port_clear_bits_raw = imx_gpio_port_clear_bits_raw,
.port_toggle_bits = imx_gpio_port_toggle_bits,
.pin_interrupt_configure = imx_gpio_pin_interrupt_configure,
.manage_callback = imx_gpio_manage_callback,
.enable_callback = imx_gpio_enable_callback,
.disable_callback = imx_gpio_disable_callback,
};
#ifdef CONFIG_GPIO_IMX_PORT_1
static int imx_gpio_1_init(struct device *port);
static const struct imx_gpio_config imx_gpio_1_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_1_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_1_data;
DEVICE_AND_API_INIT(imx_gpio_1, DT_GPIO_IMX_PORT_1_NAME,
imx_gpio_1_init,
&imx_gpio_1_data, &imx_gpio_1_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_1_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_1_IRQ_0,
DT_GPIO_IMX_PORT_1_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_1), 0);
irq_enable(DT_GPIO_IMX_PORT_1_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_1_IRQ_1,
DT_GPIO_IMX_PORT_1_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_1), 0);
irq_enable(DT_GPIO_IMX_PORT_1_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_1 */
#ifdef CONFIG_GPIO_IMX_PORT_2
static int imx_gpio_2_init(struct device *port);
static const struct imx_gpio_config imx_gpio_2_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_2_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_2_data;
DEVICE_AND_API_INIT(imx_gpio_2, DT_GPIO_IMX_PORT_2_NAME,
imx_gpio_2_init,
&imx_gpio_2_data, &imx_gpio_2_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_2_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_2_IRQ_0,
DT_GPIO_IMX_PORT_2_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_2), 0);
irq_enable(DT_GPIO_IMX_PORT_2_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_2_IRQ_1,
DT_GPIO_IMX_PORT_2_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_2), 0);
irq_enable(DT_GPIO_IMX_PORT_2_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_2 */
#ifdef CONFIG_GPIO_IMX_PORT_3
static int imx_gpio_3_init(struct device *port);
static const struct imx_gpio_config imx_gpio_3_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_3_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_3_data;
DEVICE_AND_API_INIT(imx_gpio_3, DT_GPIO_IMX_PORT_3_NAME,
imx_gpio_3_init,
&imx_gpio_3_data, &imx_gpio_3_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_3_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_3_IRQ_0,
DT_GPIO_IMX_PORT_3_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_3), 0);
irq_enable(DT_GPIO_IMX_PORT_3_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_3_IRQ_1,
DT_GPIO_IMX_PORT_3_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_3), 0);
irq_enable(DT_GPIO_IMX_PORT_3_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_3 */
#ifdef CONFIG_GPIO_IMX_PORT_4
static int imx_gpio_4_init(struct device *port);
static const struct imx_gpio_config imx_gpio_4_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_4_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_4_data;
DEVICE_AND_API_INIT(imx_gpio_4, DT_GPIO_IMX_PORT_4_NAME,
imx_gpio_4_init,
&imx_gpio_4_data, &imx_gpio_4_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_4_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_4_IRQ_0,
DT_GPIO_IMX_PORT_4_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_4), 0);
irq_enable(DT_GPIO_IMX_PORT_4_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_4_IRQ_1,
DT_GPIO_IMX_PORT_4_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_4), 0);
irq_enable(DT_GPIO_IMX_PORT_4_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_4 */
#ifdef CONFIG_GPIO_IMX_PORT_5
static int imx_gpio_5_init(struct device *port);
static const struct imx_gpio_config imx_gpio_5_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_5_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_5_data;
DEVICE_AND_API_INIT(imx_gpio_5, DT_GPIO_IMX_PORT_5_NAME,
imx_gpio_5_init,
&imx_gpio_5_data, &imx_gpio_5_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_5_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_5_IRQ_0,
DT_GPIO_IMX_PORT_5_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_5), 0);
irq_enable(DT_GPIO_IMX_PORT_5_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_5_IRQ_1,
DT_GPIO_IMX_PORT_5_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_5), 0);
irq_enable(DT_GPIO_IMX_PORT_5_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_5 */
#ifdef CONFIG_GPIO_IMX_PORT_6
static int imx_gpio_6_init(struct device *port);
static const struct imx_gpio_config imx_gpio_6_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_6_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_6_data;
DEVICE_AND_API_INIT(imx_gpio_6, DT_GPIO_IMX_PORT_6_NAME,
imx_gpio_6_init,
&imx_gpio_6_data, &imx_gpio_6_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_6_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_6_IRQ_0,
DT_GPIO_IMX_PORT_6_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_6), 0);
irq_enable(DT_GPIO_IMX_PORT_6_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_6_IRQ_1,
DT_GPIO_IMX_PORT_6_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_6), 0);
irq_enable(DT_GPIO_IMX_PORT_6_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_6 */
#ifdef CONFIG_GPIO_IMX_PORT_7
static int imx_gpio_7_init(struct device *port);
static const struct imx_gpio_config imx_gpio_7_config = {
.base = (GPIO_Type *)DT_GPIO_IMX_PORT_7_BASE_ADDRESS,
};
static struct imx_gpio_data imx_gpio_7_data;
DEVICE_AND_API_INIT(imx_gpio_7, DT_GPIO_IMX_PORT_7_NAME,
imx_gpio_7_init,
&imx_gpio_7_data, &imx_gpio_7_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&imx_gpio_driver_api);
static int imx_gpio_7_init(struct device *port)
{
IRQ_CONNECT(DT_GPIO_IMX_PORT_7_IRQ_0,
DT_GPIO_IMX_PORT_7_IRQ_0_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_7), 0);
irq_enable(DT_GPIO_IMX_PORT_7_IRQ_0);
IRQ_CONNECT(DT_GPIO_IMX_PORT_7_IRQ_1,
DT_GPIO_IMX_PORT_7_IRQ_1_PRI,
imx_gpio_port_isr, DEVICE_GET(imx_gpio_7), 0);
irq_enable(DT_GPIO_IMX_PORT_7_IRQ_1);
return 0;
}
#endif /* CONFIG_GPIO_IMX_PORT_7 */