597 lines
16 KiB
C
597 lines
16 KiB
C
/*
|
|
* Copyright 2022-2024 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT nxp_s32_gpio
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/drivers/gpio.h>
|
|
#include <zephyr/drivers/gpio/gpio_utils.h>
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
#include <zephyr/dt-bindings/gpio/nxp-s32-gpio.h>
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(nxp_s32_gpio, CONFIG_GPIO_LOG_LEVEL);
|
|
|
|
#ifdef CONFIG_NXP_S32_EIRQ
|
|
#include <zephyr/drivers/interrupt_controller/intc_eirq_nxp_s32.h>
|
|
#endif
|
|
#ifdef CONFIG_NXP_S32_WKPU
|
|
#include <zephyr/drivers/interrupt_controller/intc_wkpu_nxp_s32.h>
|
|
#endif
|
|
|
|
/* SIUL2 Multiplexed Signal Configuration Register (offset from port base) */
|
|
#define SIUL2_MSCR(n) (0x4 * (n))
|
|
/* SIUL2 Parallel GPIO Pad Data Out (offset from gpio base) */
|
|
#define SIUL2_PGPDO 0
|
|
/* SIUL2 Parallel GPIO Pad Data In */
|
|
#define SIUL2_PGPDI 0x40
|
|
|
|
/* Handy accessors */
|
|
#define GPIO_READ(r) sys_read16(config->gpio_base + (r))
|
|
#define GPIO_WRITE(r, v) sys_write16((v), config->gpio_base + (r))
|
|
#define PORT_READ(p) sys_read32(config->port_base + SIUL2_MSCR(p))
|
|
#define PORT_WRITE(p, v) sys_write32((v), config->port_base + SIUL2_MSCR(p))
|
|
|
|
#if defined(CONFIG_NXP_S32_EIRQ) || defined(CONFIG_NXP_S32_WKPU)
|
|
#define NXP_S32_GPIO_LINE_NOT_FOUND 0xff
|
|
|
|
struct gpio_nxp_s32_irq_map {
|
|
uint8_t pin;
|
|
uint8_t line;
|
|
} __packed;
|
|
|
|
struct gpio_nxp_s32_irq_config {
|
|
const struct device *ctrl;
|
|
uint8_t map_cnt;
|
|
struct gpio_nxp_s32_irq_map *map;
|
|
};
|
|
#endif
|
|
|
|
struct gpio_nxp_s32_config {
|
|
/* gpio_driver_config needs to be first */
|
|
struct gpio_driver_config common;
|
|
mem_addr_t gpio_base;
|
|
mem_addr_t port_base;
|
|
#ifdef CONFIG_NXP_S32_EIRQ
|
|
struct gpio_nxp_s32_irq_config *eirq_info;
|
|
#endif
|
|
#ifdef CONFIG_NXP_S32_WKPU
|
|
struct gpio_nxp_s32_irq_config *wkpu_info;
|
|
#endif
|
|
};
|
|
|
|
struct gpio_nxp_s32_data {
|
|
/* gpio_driver_data needs to be first */
|
|
struct gpio_driver_data common;
|
|
|
|
#if defined(CONFIG_NXP_S32_EIRQ) || defined(CONFIG_NXP_S32_WKPU)
|
|
sys_slist_t callbacks;
|
|
#if defined(CONFIG_NXP_S32_WKPU)
|
|
uint32_t pin_wkpu_mask;
|
|
#endif /* defined(CONFIG_NXP_S32_WKPU) */
|
|
#endif
|
|
};
|
|
|
|
static ALWAYS_INLINE uint16_t reverse_bits_16(uint16_t value)
|
|
{
|
|
return (uint16_t)(__RBIT((uint32_t)value) >> 16);
|
|
}
|
|
|
|
static int nxp_s32_gpio_configure(const struct device *dev, gpio_pin_t pin,
|
|
gpio_flags_t flags)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = dev->config;
|
|
uint32_t mscr_val;
|
|
uint32_t pgpdo_val;
|
|
|
|
if ((flags & GPIO_SINGLE_ENDED) != 0) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
#if defined(CONFIG_NXP_S32_WKPU)
|
|
struct gpio_nxp_s32_data *data = dev->data;
|
|
|
|
WRITE_BIT(data->pin_wkpu_mask, pin, (flags & NXP_S32_GPIO_INT_WKPU));
|
|
#else
|
|
if (flags & NXP_S32_GPIO_INT_WKPU) {
|
|
return -ENOTSUP;
|
|
}
|
|
#endif
|
|
|
|
mscr_val = PORT_READ(pin);
|
|
mscr_val &= ~(SIUL2_MSCR_SSS_MASK | SIUL2_MSCR_OBE_MASK | SIUL2_MSCR_IBE_MASK |
|
|
SIUL2_MSCR_PUE_MASK | SIUL2_MSCR_PUS_MASK);
|
|
|
|
if (flags & GPIO_OUTPUT) {
|
|
mscr_val |= SIUL2_MSCR_OBE(1U);
|
|
|
|
pgpdo_val = GPIO_READ(SIUL2_PGPDO);
|
|
if (flags & GPIO_OUTPUT_INIT_HIGH) {
|
|
pgpdo_val |= BIT(15 - pin);
|
|
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
|
|
pgpdo_val &= ~BIT(15 - pin);
|
|
}
|
|
GPIO_WRITE(SIUL2_PGPDO, pgpdo_val);
|
|
}
|
|
if (flags & GPIO_INPUT) {
|
|
mscr_val |= SIUL2_MSCR_IBE(1U);
|
|
}
|
|
if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) {
|
|
mscr_val |= SIUL2_MSCR_PUE(1U);
|
|
if (flags & GPIO_PULL_UP) {
|
|
mscr_val |= SIUL2_MSCR_PUS(1U);
|
|
}
|
|
}
|
|
PORT_WRITE(pin, mscr_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_port_get_raw(const struct device *port, uint32_t *value)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = port->config;
|
|
|
|
*value = reverse_bits_16(GPIO_READ(SIUL2_PGPDI));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_port_set_masked_raw(const struct device *port,
|
|
gpio_port_pins_t mask,
|
|
gpio_port_value_t value)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = port->config;
|
|
gpio_port_pins_t pins_value;
|
|
|
|
pins_value = reverse_bits_16(GPIO_READ(SIUL2_PGPDO));
|
|
pins_value = (pins_value & ~mask) | (mask & value);
|
|
GPIO_WRITE(SIUL2_PGPDO, reverse_bits_16(pins_value));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_port_set_bits_raw(const struct device *port,
|
|
gpio_port_pins_t pins)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = port->config;
|
|
uint16_t reg_val;
|
|
|
|
reg_val = GPIO_READ(SIUL2_PGPDO);
|
|
reg_val |= reverse_bits_16(pins);
|
|
GPIO_WRITE(SIUL2_PGPDO, reg_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_port_clear_bits_raw(const struct device *port,
|
|
gpio_port_pins_t pins)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = port->config;
|
|
uint16_t reg_val;
|
|
|
|
reg_val = GPIO_READ(SIUL2_PGPDO);
|
|
reg_val &= ~reverse_bits_16(pins);
|
|
GPIO_WRITE(SIUL2_PGPDO, reg_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_port_toggle_bits(const struct device *port,
|
|
gpio_port_pins_t pins)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = port->config;
|
|
uint16_t reg_val;
|
|
|
|
reg_val = GPIO_READ(SIUL2_PGPDO);
|
|
reg_val ^= reverse_bits_16(pins);
|
|
GPIO_WRITE(SIUL2_PGPDO, reg_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_NXP_S32_EIRQ) || defined(CONFIG_NXP_S32_WKPU)
|
|
|
|
static uint8_t nxp_s32_gpio_pin_to_line(const struct gpio_nxp_s32_irq_config *irq_cfg,
|
|
uint8_t pin)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < irq_cfg->map_cnt; i++) {
|
|
if (irq_cfg->map[i].pin == pin) {
|
|
return irq_cfg->map[i].line;
|
|
}
|
|
}
|
|
|
|
return NXP_S32_GPIO_LINE_NOT_FOUND;
|
|
}
|
|
|
|
static void nxp_s32_gpio_isr(uint8_t pin, void *arg)
|
|
{
|
|
const struct device *dev = (struct device *)arg;
|
|
struct gpio_nxp_s32_data *data = dev->data;
|
|
|
|
gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
|
|
}
|
|
|
|
#if defined(CONFIG_NXP_S32_EIRQ)
|
|
static int nxp_s32_gpio_eirq_get_trigger(enum eirq_nxp_s32_trigger *eirq_trigger,
|
|
enum gpio_int_trig trigger)
|
|
{
|
|
switch (trigger) {
|
|
case GPIO_INT_TRIG_LOW:
|
|
*eirq_trigger = EIRQ_NXP_S32_FALLING_EDGE;
|
|
break;
|
|
case GPIO_INT_TRIG_HIGH:
|
|
*eirq_trigger = EIRQ_NXP_S32_RISING_EDGE;
|
|
break;
|
|
case GPIO_INT_TRIG_BOTH:
|
|
*eirq_trigger = EIRQ_NXP_S32_BOTH_EDGES;
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_config_eirq(const struct device *dev,
|
|
gpio_pin_t pin,
|
|
enum gpio_int_mode mode,
|
|
enum gpio_int_trig trig)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = dev->config;
|
|
const struct gpio_nxp_s32_irq_config *irq_cfg = config->eirq_info;
|
|
uint8_t irq_line;
|
|
enum eirq_nxp_s32_trigger eirq_trigger;
|
|
|
|
if (irq_cfg == NULL) {
|
|
LOG_ERR("external interrupt controller not available or enabled");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (mode == GPIO_INT_MODE_LEVEL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
irq_line = nxp_s32_gpio_pin_to_line(irq_cfg, pin);
|
|
if (irq_line == NXP_S32_GPIO_LINE_NOT_FOUND) {
|
|
if (mode == GPIO_INT_MODE_DISABLED) {
|
|
return 0;
|
|
}
|
|
LOG_ERR("pin %d cannot be used for external interrupt", pin);
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (mode == GPIO_INT_MODE_DISABLED) {
|
|
eirq_nxp_s32_disable_interrupt(irq_cfg->ctrl, irq_line);
|
|
eirq_nxp_s32_unset_callback(irq_cfg->ctrl, irq_line);
|
|
} else {
|
|
if (nxp_s32_gpio_eirq_get_trigger(&eirq_trigger, trig)) {
|
|
return -ENOTSUP;
|
|
}
|
|
if (eirq_nxp_s32_set_callback(irq_cfg->ctrl, irq_line, pin,
|
|
nxp_s32_gpio_isr, (void *)dev)) {
|
|
LOG_ERR("pin %d is already in use", pin);
|
|
return -EBUSY;
|
|
}
|
|
eirq_nxp_s32_enable_interrupt(irq_cfg->ctrl, irq_line, eirq_trigger);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_NXP_S32_EIRQ */
|
|
|
|
#if defined(CONFIG_NXP_S32_WKPU)
|
|
static int nxp_s32_gpio_wkpu_get_trigger(enum wkpu_nxp_s32_trigger *wkpu_trigger,
|
|
enum gpio_int_trig trigger)
|
|
{
|
|
switch (trigger) {
|
|
case GPIO_INT_TRIG_LOW:
|
|
*wkpu_trigger = WKPU_NXP_S32_FALLING_EDGE;
|
|
break;
|
|
case GPIO_INT_TRIG_HIGH:
|
|
*wkpu_trigger = WKPU_NXP_S32_RISING_EDGE;
|
|
break;
|
|
case GPIO_INT_TRIG_BOTH:
|
|
*wkpu_trigger = WKPU_NXP_S32_BOTH_EDGES;
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_s32_gpio_config_wkpu(const struct device *dev,
|
|
gpio_pin_t pin,
|
|
enum gpio_int_mode mode,
|
|
enum gpio_int_trig trig)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = dev->config;
|
|
const struct gpio_nxp_s32_irq_config *irq_cfg = config->wkpu_info;
|
|
uint8_t irq_line;
|
|
enum wkpu_nxp_s32_trigger wkpu_trigger;
|
|
|
|
if (irq_cfg == NULL) {
|
|
LOG_ERR("WKPU controller not available or enabled");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (mode == GPIO_INT_MODE_LEVEL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
irq_line = nxp_s32_gpio_pin_to_line(irq_cfg, pin);
|
|
if (irq_line == NXP_S32_GPIO_LINE_NOT_FOUND) {
|
|
if (mode == GPIO_INT_MODE_DISABLED) {
|
|
return 0;
|
|
}
|
|
LOG_ERR("pin %d cannot be used for external interrupt", pin);
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (mode == GPIO_INT_MODE_DISABLED) {
|
|
wkpu_nxp_s32_disable_interrupt(irq_cfg->ctrl, irq_line);
|
|
wkpu_nxp_s32_unset_callback(irq_cfg->ctrl, irq_line);
|
|
} else {
|
|
if (nxp_s32_gpio_wkpu_get_trigger(&wkpu_trigger, trig)) {
|
|
return -ENOTSUP;
|
|
}
|
|
if (wkpu_nxp_s32_set_callback(irq_cfg->ctrl, irq_line, pin,
|
|
nxp_s32_gpio_isr, (void *)dev)) {
|
|
LOG_ERR("pin %d is already in use", pin);
|
|
return -EBUSY;
|
|
}
|
|
wkpu_nxp_s32_enable_interrupt(irq_cfg->ctrl, irq_line, wkpu_trigger);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_NXP_S32_WKPU */
|
|
|
|
static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev,
|
|
gpio_pin_t pin,
|
|
enum gpio_int_mode mode,
|
|
enum gpio_int_trig trig)
|
|
{
|
|
#if defined(CONFIG_NXP_S32_WKPU)
|
|
struct gpio_nxp_s32_data *data = dev->data;
|
|
|
|
if (data->pin_wkpu_mask & BIT(pin)) {
|
|
return nxp_s32_gpio_config_wkpu(dev, pin, mode, trig);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_NXP_S32_EIRQ)
|
|
return nxp_s32_gpio_config_eirq(dev, pin, mode, trig);
|
|
#endif
|
|
}
|
|
|
|
static int nxp_s32_gpio_manage_callback(const struct device *dev,
|
|
struct gpio_callback *cb, bool set)
|
|
{
|
|
struct gpio_nxp_s32_data *data = dev->data;
|
|
|
|
return gpio_manage_callback(&data->callbacks, cb, set);
|
|
}
|
|
#endif /* defined(CONFIG_NXP_S32_EIRQ) || defined(CONFIG_NXP_S32_WKPU) */
|
|
|
|
#ifdef CONFIG_GPIO_GET_CONFIG
|
|
static int nxp_s32_gpio_pin_get_config(const struct device *dev,
|
|
gpio_pin_t pin,
|
|
gpio_flags_t *out_flags)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = dev->config;
|
|
uint16_t pins_output;
|
|
uint32_t mscr_val;
|
|
gpio_flags_t flags = 0;
|
|
|
|
mscr_val = PORT_READ(pin);
|
|
if ((mscr_val & SIUL2_MSCR_IBE_MASK) != 0) {
|
|
flags |= GPIO_INPUT;
|
|
}
|
|
|
|
if ((mscr_val & SIUL2_MSCR_OBE_MASK) != 0) {
|
|
flags |= GPIO_OUTPUT;
|
|
|
|
pins_output = GPIO_READ(SIUL2_PGPDO);
|
|
if ((pins_output & BIT(15 - pin)) != 0) {
|
|
flags |= GPIO_OUTPUT_HIGH;
|
|
} else {
|
|
flags |= GPIO_OUTPUT_LOW;
|
|
}
|
|
|
|
#if defined(SIUL2_MSCR_ODE_MASK)
|
|
if ((mscr_val & SIUL2_MSCR_ODE_MASK) != 0) {
|
|
flags |= GPIO_OPEN_DRAIN;
|
|
}
|
|
#endif /* SIUL2_MSCR_ODE_MASK */
|
|
}
|
|
|
|
if ((mscr_val & SIUL2_MSCR_PUE_MASK) != 0) {
|
|
if ((mscr_val & SIUL2_MSCR_PUS_MASK) != 0) {
|
|
flags |= GPIO_PULL_UP;
|
|
} else {
|
|
flags |= GPIO_PULL_DOWN;
|
|
}
|
|
}
|
|
|
|
*out_flags = flags;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_GPIO_GET_CONFIG */
|
|
|
|
#ifdef CONFIG_GPIO_GET_DIRECTION
|
|
static int nxp_s32_gpio_port_get_direction(const struct device *dev,
|
|
gpio_port_pins_t map,
|
|
gpio_port_pins_t *inputs,
|
|
gpio_port_pins_t *outputs)
|
|
{
|
|
const struct gpio_nxp_s32_config *config = dev->config;
|
|
gpio_port_pins_t ip = 0;
|
|
gpio_port_pins_t op = 0;
|
|
uint32_t pin;
|
|
|
|
map &= config->common.port_pin_mask;
|
|
|
|
if (inputs != NULL) {
|
|
while (map) {
|
|
pin = find_lsb_set(map) - 1;
|
|
ip |= (!!(PORT_READ(pin) & SIUL2_MSCR_IBE_MASK)) * BIT(pin);
|
|
map &= ~BIT(pin);
|
|
}
|
|
|
|
*inputs = ip;
|
|
}
|
|
|
|
if (outputs != NULL) {
|
|
while (map) {
|
|
pin = find_lsb_set(map) - 1;
|
|
op |= (!!(PORT_READ(pin) & SIUL2_MSCR_OBE_MASK)) * BIT(pin);
|
|
map &= ~BIT(pin);
|
|
}
|
|
|
|
*outputs = op;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_GPIO_GET_DIRECTION */
|
|
|
|
static const struct gpio_driver_api gpio_nxp_s32_driver_api = {
|
|
.pin_configure = nxp_s32_gpio_configure,
|
|
.port_get_raw = nxp_s32_gpio_port_get_raw,
|
|
.port_set_masked_raw = nxp_s32_gpio_port_set_masked_raw,
|
|
.port_set_bits_raw = nxp_s32_gpio_port_set_bits_raw,
|
|
.port_clear_bits_raw = nxp_s32_gpio_port_clear_bits_raw,
|
|
.port_toggle_bits = nxp_s32_gpio_port_toggle_bits,
|
|
#if defined(CONFIG_NXP_S32_EIRQ) || defined(CONFIG_NXP_S32_WKPU)
|
|
.pin_interrupt_configure = nxp_s32_gpio_pin_interrupt_configure,
|
|
.manage_callback = nxp_s32_gpio_manage_callback,
|
|
#endif
|
|
#ifdef CONFIG_GPIO_GET_CONFIG
|
|
.pin_get_config = nxp_s32_gpio_pin_get_config,
|
|
#endif
|
|
#ifdef CONFIG_GPIO_GET_DIRECTION
|
|
.port_get_direction = nxp_s32_gpio_port_get_direction,
|
|
#endif
|
|
};
|
|
|
|
/* Calculate the port pin mask based on ngpios and gpio-reserved-ranges node
|
|
* properties. Multiple reserved ranges are not supported.
|
|
*
|
|
* For example, for the following gpio node definition:
|
|
*
|
|
* gpioo: gpio@40521716 {
|
|
* ...
|
|
* ngpios = <14>;
|
|
* gpio-reserved-ranges = <0 10>;
|
|
* };
|
|
*
|
|
* the generated mask will be will be 0x3C00.
|
|
*/
|
|
#define GPIO_NXP_S32_RESERVED_PIN_MASK(n) \
|
|
(GENMASK(DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 0) + \
|
|
DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 1) - 1, \
|
|
DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 0) \
|
|
))
|
|
|
|
#define GPIO_NXP_S32_PORT_PIN_MASK(n) \
|
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpio_reserved_ranges), \
|
|
(GPIO_PORT_PIN_MASK_FROM_DT_INST(n) \
|
|
& ~(GPIO_NXP_S32_RESERVED_PIN_MASK(n))), \
|
|
(GPIO_PORT_PIN_MASK_FROM_DT_INST(n)))
|
|
|
|
#ifdef CONFIG_NXP_S32_EIRQ
|
|
#define GPIO_NXP_S32_EIRQ_NODE(n) \
|
|
DT_INST_PHANDLE(n, interrupt_parent)
|
|
|
|
#define GPIO_NXP_S32_EIRQ_PIN_LINE(idx, n) \
|
|
DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \
|
|
DT_INST_IRQ_BY_IDX(n, idx, eirq_line) \
|
|
|
|
#define GPIO_NXP_S32_SET_EIRQ_INFO(n) \
|
|
BUILD_ASSERT((DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupt_parent) == \
|
|
DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupts)), \
|
|
"interrupts and interrupt-parent must be set when " \
|
|
"using external interrupts"); \
|
|
IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(GPIO_NXP_S32_EIRQ_NODE(n)), ( \
|
|
static uint8_t gpio_nxp_s32_eirq_data_##n[] = { \
|
|
LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \
|
|
GPIO_NXP_S32_EIRQ_PIN_LINE, (,), n) \
|
|
}; \
|
|
static struct gpio_nxp_s32_irq_config gpio_nxp_s32_eirq_##n = { \
|
|
.ctrl = DEVICE_DT_GET(GPIO_NXP_S32_EIRQ_NODE(n)), \
|
|
.map_cnt = DT_NUM_IRQS(DT_DRV_INST(n)), \
|
|
.map = (struct gpio_nxp_s32_irq_map *) \
|
|
gpio_nxp_s32_eirq_data_##n, \
|
|
}; \
|
|
))
|
|
|
|
#define GPIO_NXP_S32_GET_EIRQ_INFO(n) \
|
|
.eirq_info = UTIL_AND(DT_NODE_HAS_STATUS_OKAY(GPIO_NXP_S32_EIRQ_NODE(n)),\
|
|
&gpio_nxp_s32_eirq_##n),
|
|
#else
|
|
#define GPIO_NXP_S32_SET_EIRQ_INFO(n)
|
|
#define GPIO_NXP_S32_GET_EIRQ_INFO(n)
|
|
#endif /* CONFIG_NXP_S32_EIRQ */
|
|
|
|
#ifdef CONFIG_NXP_S32_WKPU
|
|
#define GPIO_NXP_S32_WKPU_NODE(n) DT_INST_PHANDLE(n, nxp_wkpu)
|
|
|
|
#define GPIO_NXP_S32_SET_WKPU_INFO(n) \
|
|
BUILD_ASSERT((DT_INST_NODE_HAS_PROP(n, nxp_wkpu) == \
|
|
DT_INST_NODE_HAS_PROP(n, nxp_wkpu_interrupts)), \
|
|
"nxp,wkpu and nxp,wkpu-interrupts must be provided"); \
|
|
IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(GPIO_NXP_S32_WKPU_NODE(n)), ( \
|
|
static uint8_t gpio_nxp_s32_wkpu_data_##n[] = \
|
|
DT_INST_PROP(n, nxp_wkpu_interrupts); \
|
|
static struct gpio_nxp_s32_irq_config gpio_nxp_s32_wkpu_##n = { \
|
|
.ctrl = DEVICE_DT_GET(GPIO_NXP_S32_WKPU_NODE(n)), \
|
|
.map_cnt = sizeof(gpio_nxp_s32_wkpu_data_##n) / \
|
|
sizeof(struct gpio_nxp_s32_irq_map), \
|
|
.map = (struct gpio_nxp_s32_irq_map *) \
|
|
gpio_nxp_s32_wkpu_data_##n, \
|
|
}; \
|
|
))
|
|
|
|
#define GPIO_NXP_S32_GET_WKPU_INFO(n) \
|
|
.wkpu_info = UTIL_AND(DT_NODE_HAS_STATUS_OKAY(GPIO_NXP_S32_WKPU_NODE(n)),\
|
|
&gpio_nxp_s32_wkpu_##n)
|
|
#else
|
|
#define GPIO_NXP_S32_SET_WKPU_INFO(n)
|
|
#define GPIO_NXP_S32_GET_WKPU_INFO(n)
|
|
#endif /* CONFIG_NXP_S32_WKPU */
|
|
|
|
#define GPIO_NXP_S32_DEVICE_INIT(n) \
|
|
GPIO_NXP_S32_SET_EIRQ_INFO(n) \
|
|
GPIO_NXP_S32_SET_WKPU_INFO(n) \
|
|
static const struct gpio_nxp_s32_config gpio_nxp_s32_config_##n = { \
|
|
.common = { \
|
|
.port_pin_mask = GPIO_NXP_S32_PORT_PIN_MASK(n), \
|
|
}, \
|
|
.gpio_base = DT_INST_REG_ADDR_BY_NAME(n, pgpdo), \
|
|
.port_base = DT_INST_REG_ADDR_BY_NAME(n, mscr), \
|
|
GPIO_NXP_S32_GET_EIRQ_INFO(n) \
|
|
GPIO_NXP_S32_GET_WKPU_INFO(n) \
|
|
}; \
|
|
static struct gpio_nxp_s32_data gpio_nxp_s32_data_##n; \
|
|
static int gpio_nxp_s32_init_##n(const struct device *dev) \
|
|
{ \
|
|
return 0; \
|
|
} \
|
|
DEVICE_DT_INST_DEFINE(n, \
|
|
gpio_nxp_s32_init_##n, \
|
|
NULL, \
|
|
&gpio_nxp_s32_data_##n, \
|
|
&gpio_nxp_s32_config_##n, \
|
|
POST_KERNEL, \
|
|
CONFIG_GPIO_INIT_PRIORITY, \
|
|
&gpio_nxp_s32_driver_api);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(GPIO_NXP_S32_DEVICE_INIT)
|