zephyr/drivers/gpio/gpio_hogs.c

126 lines
3.5 KiB
C

/*
* Copyright (c) 2022-2023 Vestas Wind Systems A/S
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/init.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(gpio_hogs, CONFIG_GPIO_LOG_LEVEL);
struct gpio_hog_dt_spec {
gpio_pin_t pin;
gpio_flags_t flags;
};
struct gpio_hogs {
const struct device *port;
const struct gpio_hog_dt_spec *specs;
size_t num_specs;
};
/* Static initializer for a struct gpio_hog_dt_spec */
#define GPIO_HOG_DT_SPEC_GET_BY_IDX(node_id, idx) \
{ \
.pin = DT_GPIO_HOG_PIN_BY_IDX(node_id, idx), \
.flags = DT_GPIO_HOG_FLAGS_BY_IDX(node_id, idx) | \
COND_CODE_1(DT_PROP(node_id, input), (GPIO_INPUT), \
(COND_CODE_1(DT_PROP(node_id, output_low), \
(GPIO_OUTPUT_INACTIVE), \
(COND_CODE_1(DT_PROP(node_id, output_high), \
(GPIO_OUTPUT_ACTIVE), (0)))))), \
}
/* Expands to 1 if node_id is a GPIO controller, 0 otherwise */
#define GPIO_HOGS_NODE_IS_GPIO_CTLR(node_id) \
DT_PROP_OR(node_id, gpio_controller, 0)
/* Expands to to 1 if node_id is a GPIO hog, empty otherwise */
#define GPIO_HOGS_NODE_IS_GPIO_HOG(node_id) \
IF_ENABLED(DT_PROP_OR(node_id, gpio_hog, 0), 1)
/* Expands to 1 if GPIO controller node_id has GPIO hog children, 0 otherwise */
#define GPIO_HOGS_GPIO_CTLR_HAS_HOGS(node_id) \
COND_CODE_0( \
IS_EMPTY(DT_FOREACH_CHILD_STATUS_OKAY(node_id, \
GPIO_HOGS_NODE_IS_GPIO_HOG)), \
(1), (0))
/* Called for GPIO hog indexes */
#define GPIO_HOGS_INIT_GPIO_HOG_BY_IDX(idx, node_id) \
GPIO_HOG_DT_SPEC_GET_BY_IDX(node_id, idx)
/* Called for GPIO hog dts nodes */
#define GPIO_HOGS_INIT_GPIO_HOGS(node_id) \
LISTIFY(DT_NUM_GPIO_HOGS(node_id), \
GPIO_HOGS_INIT_GPIO_HOG_BY_IDX, (,), node_id),
/* Called for GPIO controller dts node children */
#define GPIO_HOGS_COND_INIT_GPIO_HOGS(node_id) \
COND_CODE_0(IS_EMPTY(GPIO_HOGS_NODE_IS_GPIO_HOG(node_id)), \
(GPIO_HOGS_INIT_GPIO_HOGS(node_id)), ())
/* Called for each GPIO controller dts node which has GPIO hog children */
#define GPIO_HOGS_INIT_GPIO_CTLR(node_id) \
{ \
.port = DEVICE_DT_GET(node_id), \
.specs = (const struct gpio_hog_dt_spec []) { \
DT_FOREACH_CHILD_STATUS_OKAY(node_id, \
GPIO_HOGS_COND_INIT_GPIO_HOGS) \
}, \
.num_specs = \
DT_FOREACH_CHILD_STATUS_OKAY_SEP(node_id, \
DT_NUM_GPIO_HOGS, (+)), \
},
/* Called for each GPIO controller dts node */
#define GPIO_HOGS_COND_INIT_GPIO_CTLR(node_id) \
IF_ENABLED(GPIO_HOGS_GPIO_CTLR_HAS_HOGS(node_id), \
(GPIO_HOGS_INIT_GPIO_CTLR(node_id)))
/* Called for each dts node */
#define GPIO_HOGS_COND_INIT(node_id) \
IF_ENABLED(GPIO_HOGS_NODE_IS_GPIO_CTLR(node_id), \
(GPIO_HOGS_COND_INIT_GPIO_CTLR(node_id)))
static const struct gpio_hogs gpio_hogs[] = {
DT_FOREACH_STATUS_OKAY_NODE(GPIO_HOGS_COND_INIT)
};
static int gpio_hogs_init(void)
{
const struct gpio_hogs *hogs;
const struct gpio_hog_dt_spec *spec;
int err;
int i;
int j;
for (i = 0; i < ARRAY_SIZE(gpio_hogs); i++) {
hogs = &gpio_hogs[i];
if (!device_is_ready(hogs->port)) {
LOG_ERR("GPIO port %s not ready", hogs->port->name);
return -ENODEV;
}
for (j = 0; j < hogs->num_specs; j++) {
spec = &hogs->specs[j];
err = gpio_pin_configure(hogs->port, spec->pin, spec->flags);
if (err < 0) {
LOG_ERR("failed to configure GPIO hog for port %s pin %u (err %d)",
hogs->port->name, spec->pin, err);
return err;
}
}
}
return 0;
}
SYS_INIT(gpio_hogs_init, POST_KERNEL, CONFIG_GPIO_HOGS_INIT_PRIORITY);