mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-03 13:31:57 +00:00
Usually, we want to operate only on "available" device nodes ("available" means "status is okay and a matching binding is found"), but that's not true in all cases. Sometimes we want to operate on special nodes without matching bindings, such as those describing memory. To handle the distinction, change various additional devicetree APIs making it clear that they operate only on available device nodes, adjusting gen_defines and devicetree.h implementation details accordingly: - emit macros for all existing nodes in gen_defines.py, regardless of status or matching binding - rename DT_NUM_INST to DT_NUM_INST_STATUS_OKAY - rename DT_NODE_HAS_COMPAT to DT_NODE_HAS_COMPAT_STATUS_OKAY - rename DT_INST_FOREACH to DT_INST_FOREACH_STATUS_OKAY - rename DT_ANY_INST_ON_BUS to DT_ANY_INST_ON_BUS_STATUS_OKAY - rewrite DT_HAS_NODE_STATUS_OKAY in terms of a new DT_NODE_HAS_STATUS - resurrect DT_HAS_NODE in the form of DT_NODE_EXISTS - remove DT_COMPAT_ON_BUS as a public API - use the new default_prop_types edtlib parameter Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
243 lines
5.9 KiB
C
243 lines
5.9 KiB
C
/*
|
|
* Copyright (c) 2019 Antmicro <www.antmicro.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT litex_gpio
|
|
|
|
#include <errno.h>
|
|
#include <device.h>
|
|
#include <drivers/gpio.h>
|
|
#include <zephyr/types.h>
|
|
#include <sys/util.h>
|
|
#include <string.h>
|
|
#include <logging/log.h>
|
|
|
|
#define SUPPORTED_FLAGS (GPIO_INPUT | GPIO_OUTPUT | \
|
|
GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH | \
|
|
GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH)
|
|
|
|
#define GPIO_LOW 0
|
|
#define GPIO_HIGH 1
|
|
|
|
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
|
|
LOG_MODULE_REGISTER(gpio_litex);
|
|
|
|
static const char *LITEX_LOG_REG_SIZE_NGPIOS_MISMATCH =
|
|
"Cannot handle all of the gpios with the register of given size\n";
|
|
static const char *LITEX_LOG_CANNOT_CHANGE_DIR =
|
|
"Cannot change port direction selected in device tree\n";
|
|
|
|
struct gpio_litex_cfg {
|
|
volatile u32_t *reg_addr;
|
|
int reg_size;
|
|
int nr_gpios;
|
|
bool port_is_output;
|
|
};
|
|
|
|
struct gpio_litex_data {
|
|
struct gpio_driver_data common;
|
|
};
|
|
|
|
/* Helper macros for GPIO */
|
|
|
|
#define DEV_GPIO_CFG(dev) \
|
|
((const struct gpio_litex_cfg *)(dev)->config_info)
|
|
|
|
/* Helper functions for bit / port access */
|
|
|
|
static inline void set_bit(const struct gpio_litex_cfg *config,
|
|
u32_t bit, bool val)
|
|
{
|
|
int regv, new_regv;
|
|
|
|
regv = litex_read(config->reg_addr, config->reg_size);
|
|
new_regv = (regv & ~BIT(bit)) | (val << bit);
|
|
litex_write(config->reg_addr, config->reg_size, new_regv);
|
|
}
|
|
|
|
static inline u32_t get_bit(const struct gpio_litex_cfg *config, u32_t bit)
|
|
{
|
|
int regv = litex_read(config->reg_addr, config->reg_size);
|
|
|
|
return !!(regv & BIT(bit));
|
|
}
|
|
|
|
static inline void set_port(const struct gpio_litex_cfg *config, u32_t value)
|
|
{
|
|
litex_write(config->reg_addr, config->reg_size, value);
|
|
}
|
|
|
|
static inline u32_t get_port(const struct gpio_litex_cfg *config)
|
|
{
|
|
int regv = litex_read(config->reg_addr, config->reg_size);
|
|
|
|
return (regv & BIT_MASK(config->nr_gpios));
|
|
}
|
|
|
|
/* Driver functions */
|
|
|
|
static int gpio_litex_init(struct device *dev)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
|
|
/* each 4-byte register is able to handle 8 GPIO pins */
|
|
if (gpio_config->nr_gpios > (gpio_config->reg_size / 4) * 8) {
|
|
LOG_ERR("%s", LITEX_LOG_REG_SIZE_NGPIOS_MISMATCH);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_configure(struct device *dev,
|
|
gpio_pin_t pin, gpio_flags_t flags)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
|
|
if (flags & ~SUPPORTED_FLAGS) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) {
|
|
/* Pin cannot be configured as input and output */
|
|
return -ENOTSUP;
|
|
} else if (!(flags & (GPIO_INPUT | GPIO_OUTPUT))) {
|
|
/* Pin has to be configuread as input or output */
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (flags & GPIO_OUTPUT) {
|
|
if (!gpio_config->port_is_output) {
|
|
LOG_ERR("%s", LITEX_LOG_CANNOT_CHANGE_DIR);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (flags & GPIO_OUTPUT_INIT_HIGH) {
|
|
set_bit(gpio_config, pin, GPIO_HIGH);
|
|
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
|
|
set_bit(gpio_config, pin, GPIO_LOW);
|
|
}
|
|
} else {
|
|
if (gpio_config->port_is_output) {
|
|
LOG_ERR("%s", LITEX_LOG_CANNOT_CHANGE_DIR);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_port_get_raw(struct device *dev, gpio_port_value_t *value)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
|
|
*value = get_port(gpio_config);
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_port_set_masked_raw(struct device *dev,
|
|
gpio_port_pins_t mask,
|
|
gpio_port_value_t value)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
u32_t port_val;
|
|
|
|
port_val = get_port(gpio_config);
|
|
port_val = (port_val & ~mask) | (value & mask);
|
|
set_port(gpio_config, port_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_port_set_bits_raw(struct device *dev,
|
|
gpio_port_pins_t pins)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
u32_t port_val;
|
|
|
|
port_val = get_port(gpio_config);
|
|
port_val |= pins;
|
|
set_port(gpio_config, port_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_port_clear_bits_raw(struct device *dev,
|
|
gpio_port_pins_t pins)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
u32_t port_val;
|
|
|
|
port_val = get_port(gpio_config);
|
|
port_val &= ~pins;
|
|
set_port(gpio_config, port_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_port_toggle_bits(struct device *dev,
|
|
gpio_port_pins_t pins)
|
|
{
|
|
const struct gpio_litex_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
|
u32_t port_val;
|
|
|
|
port_val = get_port(gpio_config);
|
|
port_val ^= pins;
|
|
set_port(gpio_config, port_val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_litex_pin_interrupt_configure(struct device *dev,
|
|
gpio_pin_t pin,
|
|
enum gpio_int_mode mode,
|
|
enum gpio_int_trig trig)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (mode != GPIO_INT_MODE_DISABLED) {
|
|
ret = -ENOTSUP;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const struct gpio_driver_api gpio_litex_driver_api = {
|
|
.pin_configure = gpio_litex_configure,
|
|
.port_get_raw = gpio_litex_port_get_raw,
|
|
.port_set_masked_raw = gpio_litex_port_set_masked_raw,
|
|
.port_set_bits_raw = gpio_litex_port_set_bits_raw,
|
|
.port_clear_bits_raw = gpio_litex_port_clear_bits_raw,
|
|
.port_toggle_bits = gpio_litex_port_toggle_bits,
|
|
.pin_interrupt_configure = gpio_litex_pin_interrupt_configure,
|
|
};
|
|
|
|
/* Device Instantiation */
|
|
|
|
#define GPIO_LITEX_INIT(n) \
|
|
BUILD_ASSERT(DT_INST_REG_SIZE(n) != 0 \
|
|
&& DT_INST_REG_SIZE(n) % 4 == 0, \
|
|
"Register size must be a multiple of 4"); \
|
|
\
|
|
static const struct gpio_litex_cfg gpio_litex_cfg_##n = { \
|
|
.reg_addr = \
|
|
(volatile u32_t *) DT_INST_REG_ADDR(n), \
|
|
.reg_size = DT_INST_REG_SIZE(n), \
|
|
.nr_gpios = DT_INST_PROP(n, ngpios), \
|
|
.port_is_output = DT_INST_PROP(n, port_is_output), \
|
|
}; \
|
|
static struct gpio_litex_data gpio_litex_data_##n; \
|
|
\
|
|
DEVICE_AND_API_INIT(litex_gpio_##n, \
|
|
DT_INST_LABEL(n), \
|
|
gpio_litex_init, \
|
|
&gpio_litex_data_##n, \
|
|
&gpio_litex_cfg_##n, \
|
|
POST_KERNEL, \
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
|
&gpio_litex_driver_api \
|
|
);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(GPIO_LITEX_INIT)
|