diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 03c5aa211ba..2ba21ce57f7 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -75,6 +75,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_PSOC6 gpio_psoc6.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RA_IOPORT gpio_renesas_ra_ioport.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RCAR gpio_rcar.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RENESAS_RA gpio_renesas_ra.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RENESAS_RZ gpio_renesas_rz.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RP1 gpio_rp1.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RPI_PICO gpio_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 331e34aac2c..f93e9bbd3bf 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -161,6 +161,7 @@ source "drivers/gpio/Kconfig.psoc6" source "drivers/gpio/Kconfig.rcar" source "drivers/gpio/Kconfig.renesas_ra" source "drivers/gpio/Kconfig.renesas_ra_ioport" +source "drivers/gpio/Kconfig.renesas_rz" source "drivers/gpio/Kconfig.rp1" source "drivers/gpio/Kconfig.rpi_pico" source "drivers/gpio/Kconfig.rt1718s" diff --git a/drivers/gpio/Kconfig.renesas_rz b/drivers/gpio/Kconfig.renesas_rz new file mode 100644 index 00000000000..ae2e08c85de --- /dev/null +++ b/drivers/gpio/Kconfig.renesas_rz @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_RENESAS_RZ + bool "Renesas RZ series gpio driver" + default y + depends on DT_HAS_RENESAS_RZ_GPIO_ENABLED + select USE_RZ_FSP_IOPORT + help + Enable Renesas RZ series gpio driver. diff --git a/drivers/gpio/gpio_renesas_rz.c b/drivers/gpio/gpio_renesas_rz.c new file mode 100644 index 00000000000..7728b59cfeb --- /dev/null +++ b/drivers/gpio/gpio_renesas_rz.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rz_gpio + +#include +#include +#include +#include +#include "r_ioport.h" +#include +#include +#include "gpio_renesas_rz.h" +#include +LOG_MODULE_REGISTER(rz_gpio, CONFIG_GPIO_LOG_LEVEL); + +#define LOG_DEV_ERR(dev, format, ...) LOG_ERR("%s:" #format, (dev)->name, ##__VA_ARGS__) +#define LOG_DEV_DBG(dev, format, ...) LOG_DBG("%s:" #format, (dev)->name, ##__VA_ARGS__) + +struct gpio_rz_config { + struct gpio_driver_config common; + uint8_t ngpios; + uint8_t port_num; + bsp_io_port_t fsp_port; + const ioport_cfg_t *fsp_cfg; + const ioport_api_t *fsp_api; + const struct device *int_dev; + uint8_t tint_num[GPIO_RZ_MAX_TINT_NUM]; +}; + +struct gpio_rz_data { + struct gpio_driver_data common; + sys_slist_t cb; + ioport_instance_ctrl_t *fsp_ctrl; + struct k_spinlock lock; +}; + +struct gpio_rz_tint_isr_data { + const struct device *gpio_dev; + gpio_pin_t pin; +}; + +struct gpio_rz_tint_data { + struct gpio_rz_tint_isr_data tint_data[GPIO_RZ_MAX_TINT_NUM]; + uint32_t irq_set_edge; +}; + +struct gpio_rz_tint_config { + void (*gpio_int_init)(void); +}; + +static int gpio_rz_pin_config_get_raw(bsp_io_port_pin_t port_pin, uint32_t *flags); + +#ifdef CONFIG_GPIO_GET_CONFIG +static int gpio_rz_pin_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags) +{ + const struct gpio_rz_config *config = dev->config; + bsp_io_port_pin_t port_pin = config->fsp_port | pin; + + gpio_rz_pin_config_get_raw(port_pin, flags); + return 0; +} +#endif + +/* Get previous pin's configuration, used by pin_configure/pin_interrupt_configure api */ +static int gpio_rz_pin_config_get_raw(bsp_io_port_pin_t port_pin, uint32_t *flags) +{ + bsp_io_port_t port = (port_pin >> 8U) & 0xFF; + gpio_pin_t pin = port_pin & 0xFF; + volatile uint8_t *p_p = GPIO_RZ_IOPORT_P_REG_BASE_GET; + volatile uint16_t *p_pm = GPIO_RZ_IOPORT_PM_REG_BASE_GET; + + uint8_t adr_offset; + uint8_t p_value; + uint16_t pm_value; + + adr_offset = (uint8_t)GPIO_RZ_REG_OFFSET(port, pin); + + p_p = &p_p[adr_offset]; + p_pm = &p_pm[adr_offset]; + + p_value = GPIO_RZ_P_VALUE_GET(*p_p, pin); + pm_value = GPIO_RZ_PM_VALUE_GET(*p_pm, pin); + + if (p_value) { + *flags |= GPIO_OUTPUT_INIT_HIGH; + } else { + *flags |= GPIO_OUTPUT_INIT_LOW; + } + + *flags |= ((pm_value << 16)); + return 0; +} + +static int gpio_rz_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + bsp_io_port_pin_t port_pin = config->fsp_port | pin; + uint32_t ioport_config_data = 0; + gpio_flags_t pre_flags; + fsp_err_t err; + + gpio_rz_pin_config_get_raw(port_pin, &pre_flags); + + if (!flags) { + /* Disconnect mode */ + ioport_config_data = 0; + } else if (!(flags & GPIO_OPEN_DRAIN)) { + /* PM register */ + ioport_config_data &= GPIO_RZ_PIN_CONFIGURE_INPUT_OUTPUT_RESET; + if (flags & GPIO_INPUT) { + if (flags & GPIO_OUTPUT) { + ioport_config_data |= IOPORT_CFG_PORT_DIRECTION_OUTPUT_INPUT; + } else { + ioport_config_data |= IOPORT_CFG_PORT_DIRECTION_INPUT; + } + } else if (flags & GPIO_OUTPUT) { + ioport_config_data &= GPIO_RZ_PIN_CONFIGURE_INPUT_OUTPUT_RESET; + ioport_config_data |= IOPORT_CFG_PORT_DIRECTION_OUTPUT; + } + /* P register */ + if (!(flags & (GPIO_OUTPUT_INIT_HIGH | GPIO_OUTPUT_INIT_LOW))) { + flags |= pre_flags & (GPIO_OUTPUT_INIT_HIGH | GPIO_OUTPUT_INIT_LOW); + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + ioport_config_data |= IOPORT_CFG_PORT_OUTPUT_HIGH; + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + ioport_config_data &= ~(IOPORT_CFG_PORT_OUTPUT_HIGH); + } + /* PUPD register */ + if (flags & GPIO_PULL_UP) { + ioport_config_data |= IOPORT_CFG_PULLUP_ENABLE; + } else if (flags & GPIO_PULL_DOWN) { + ioport_config_data |= IOPORT_CFG_PULLUP_ENABLE; + } + + /* ISEL register */ + if (flags & GPIO_INT_ENABLE) { + ioport_config_data |= GPIO_RZ_PIN_CONFIGURE_INT_ENABLE; + } else if (flags & GPIO_INT_DISABLE) { + ioport_config_data &= GPIO_RZ_PIN_CONFIGURE_INT_DISABLE; + } + + /* Drive Ability register */ + ioport_config_data |= GPIO_RZ_PIN_CONFIGURE_GET_DRIVE_ABILITY(flags); + + /* Filter register, see in renesas-rz-gpio-ioport.h */ + ioport_config_data |= GPIO_RZ_PIN_CONFIGURE_GET_FILTER(flags); + } else { + return -ENOTSUP; + } + + err = config->fsp_api->pinCfg(data->fsp_ctrl, port_pin, ioport_config_data); + if (err != FSP_SUCCESS) { + return -EIO; + } + return 0; +} + +static int gpio_rz_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + fsp_err_t err; + ioport_size_t port_value; + + err = config->fsp_api->portRead(data->fsp_ctrl, config->fsp_port, &port_value); + if (err != FSP_SUCCESS) { + return -EIO; + } + *value = (gpio_port_value_t)port_value; + return 0; +} + +static int gpio_rz_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + ioport_size_t port_mask = (ioport_size_t)mask; + ioport_size_t port_value = (ioport_size_t)value; + fsp_err_t err; + + err = config->fsp_api->portWrite(data->fsp_ctrl, config->fsp_port, port_value, port_mask); + if (err != FSP_SUCCESS) { + return -EIO; + } + return 0; +} + +static int gpio_rz_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + ioport_size_t mask = (ioport_size_t)pins; + ioport_size_t value = (ioport_size_t)pins; + fsp_err_t err; + + err = config->fsp_api->portWrite(data->fsp_ctrl, config->fsp_port, value, mask); + if (err != FSP_SUCCESS) { + return -EIO; + } + return 0; +} + +static int gpio_rz_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + ioport_size_t mask = (ioport_size_t)pins; + ioport_size_t value = 0x00; + fsp_err_t err; + + err = config->fsp_api->portWrite(data->fsp_ctrl, config->fsp_port, value, mask); + if (err != FSP_SUCCESS) { + return -EIO; + } + return 0; +} + +static int gpio_rz_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + bsp_io_port_pin_t port_pin; + gpio_flags_t pre_flags; + ioport_size_t value = 0; + fsp_err_t err; + + for (uint8_t idx = 0; idx < config->ngpios; idx++) { + if (pins & (1U << idx)) { + port_pin = config->fsp_port | idx; + gpio_rz_pin_config_get_raw(port_pin, &pre_flags); + if (pre_flags & GPIO_OUTPUT_INIT_HIGH) { + value &= (1U << idx); + } else if (pre_flags & GPIO_OUTPUT_INIT_LOW) { + value |= (1U << idx); + } + } + } + err = config->fsp_api->portWrite(data->fsp_ctrl, config->fsp_port, value, + (ioport_size_t)pins); + if (err != FSP_SUCCESS) { + return -EIO; + } + return 0; +} + +#define GPIO_RZ_HAS_INTERRUPT DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_gpio_int) + +#if GPIO_RZ_HAS_INTERRUPT +static int gpio_rz_int_disable(const struct device *dev, uint8_t tint_num) +{ + struct gpio_rz_tint_data *data = dev->data; + volatile uint32_t *tssr = &R_INTC_IM33->TSSR0; + volatile uint32_t *titsr = &R_INTC_IM33->TITSR0; + volatile uint32_t *tscr = &R_INTC_IM33->TSCR; + + /* Get register offset base on interrupt number. */ + tssr = &tssr[tint_num / 4]; + titsr = &titsr[tint_num / 16]; + + irq_disable(GPIO_RZ_TINT_IRQ_GET(tint_num)); + /* Disable interrupt and clear interrupt source. */ + *tssr &= ~(0xFF << GPIO_RZ_TSSR_OFFSET(tint_num)); + /* Reset interrupt dectect type to default. */ + *titsr &= ~(0x3 << GPIO_RZ_TITSR_OFFSET(tint_num)); + + /* Clear interrupt detection status. */ + if (data->irq_set_edge & BIT(tint_num)) { + *tscr &= ~BIT(tint_num); + data->irq_set_edge &= ~BIT(tint_num); + } + data->tint_data[tint_num].gpio_dev = NULL; + data->tint_data[tint_num].pin = UINT8_MAX; + + return 0; +} + +static int gpio_rz_int_enable(const struct device *int_dev, const struct device *gpio_dev, + uint8_t tint_num, uint8_t irq_type, gpio_pin_t pin) +{ + struct gpio_rz_tint_data *int_data = int_dev->data; + const struct gpio_rz_config *gpio_config = gpio_dev->config; + volatile uint32_t *tssr = &R_INTC_IM33->TSSR0; + volatile uint32_t *titsr = &R_INTC_IM33->TITSR0; + + tssr = &tssr[tint_num / 4]; + titsr = &titsr[tint_num / 16]; + /* Select interrupt detect type. */ + *titsr |= (irq_type << GPIO_RZ_TITSR_OFFSET(tint_num)); + /* Select interrupt source base on port and pin number.*/ + *tssr |= (GPIO_RZ_TSSR_VAL(gpio_config->port_num, pin)) << GPIO_RZ_TSSR_OFFSET(tint_num); + + if (irq_type == GPIO_RZ_TINT_EDGE_RISING || irq_type == GPIO_RZ_TINT_EDGE_FALLING) { + int_data->irq_set_edge |= BIT(tint_num); + /* Clear interrupt status. */ + R_INTC_IM33->TSCR &= ~BIT(tint_num); + } + int_data->tint_data[tint_num].gpio_dev = gpio_dev; + int_data->tint_data[tint_num].pin = pin; + irq_enable(GPIO_RZ_TINT_IRQ_GET(tint_num)); + + return 0; +} + +static int gpio_rz_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct gpio_rz_config *config = dev->config; + struct gpio_rz_data *data = dev->data; + bsp_io_port_pin_t port_pin = config->fsp_port | pin; + uint8_t tint_num = config->tint_num[pin]; + uint8_t irq_type = 0; + gpio_flags_t pre_flags = 0; + k_spinlock_key_t key; + + if (tint_num >= GPIO_RZ_MAX_TINT_NUM) { + LOG_DEV_ERR(dev, "Invalid TINT interrupt:%d >= %d", tint_num, GPIO_RZ_MAX_TINT_NUM); + } + + if (pin > config->ngpios) { + return -EINVAL; + } + + if (trig == GPIO_INT_TRIG_BOTH) { + return -ENOTSUP; + } + + key = k_spin_lock(&data->lock); + + if (mode == GPIO_INT_MODE_DISABLED) { + gpio_rz_pin_config_get_raw(port_pin, &pre_flags); + pre_flags |= GPIO_INT_DISABLE; + gpio_rz_pin_configure(dev, pin, pre_flags); + gpio_rz_int_disable(config->int_dev, tint_num); + goto exit_unlock; + } + + if (mode == GPIO_INT_MODE_EDGE) { + irq_type = GPIO_RZ_TINT_EDGE_RISING; + if (trig == GPIO_INT_TRIG_LOW) { + irq_type = GPIO_RZ_TINT_EDGE_FALLING; + } + } else { + irq_type = GPIO_RZ_TINT_LEVEL_HIGH; + if (trig == GPIO_INT_TRIG_LOW) { + irq_type = GPIO_RZ_TINT_LEVEL_LOW; + } + } + + /* Set register ISEL */ + gpio_rz_pin_config_get_raw(port_pin, &pre_flags); + pre_flags |= GPIO_INT_ENABLE; + gpio_rz_pin_configure(dev, pin, pre_flags); + gpio_rz_int_enable(config->int_dev, dev, tint_num, irq_type, pin); + +exit_unlock: + k_spin_unlock(&data->lock, key); + return 0; +} + +static int gpio_rz_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct gpio_rz_data *data = dev->data; + + return gpio_manage_callback(&data->cb, callback, set); +} + +static void gpio_rz_isr(const struct device *dev, uint8_t pin) +{ + struct gpio_rz_data *data = dev->data; + + gpio_fire_callbacks(&data->cb, dev, BIT(pin)); +} + +static void gpio_rz_tint_isr(uint16_t irq, const struct device *dev) +{ + struct gpio_rz_tint_data *data = dev->data; + volatile uint32_t *tscr = &R_INTC_IM33->TSCR; + uint8_t tint_num; + + tint_num = irq - GPIO_RZ_TINT_IRQ_OFFSET; + + if (!(*tscr & BIT(tint_num))) { + LOG_DEV_DBG(dev, "tint:%u spurious irq, status 0", tint_num); + return; + } + + if (data->irq_set_edge & BIT(tint_num)) { + *tscr &= ~BIT(tint_num); + } + + gpio_rz_isr(data->tint_data[tint_num].gpio_dev, data->tint_data[tint_num].pin); +} + +static int gpio_rz_int_init(const struct device *dev) +{ + const struct gpio_rz_tint_config *config = dev->config; + + config->gpio_int_init(); + return 0; +} +#endif + +static const struct gpio_driver_api gpio_rz_driver_api = { + .pin_configure = gpio_rz_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_rz_pin_get_config, +#endif + .port_get_raw = gpio_rz_port_get_raw, + .port_set_masked_raw = gpio_rz_port_set_masked_raw, + .port_set_bits_raw = gpio_rz_port_set_bits_raw, + .port_clear_bits_raw = gpio_rz_port_clear_bits_raw, + .port_toggle_bits = gpio_rz_port_toggle_bits, +#if GPIO_RZ_HAS_INTERRUPT + .pin_interrupt_configure = gpio_rz_pin_interrupt_configure, + .manage_callback = gpio_rz_manage_callback, +#endif +}; + +/*Initialize GPIO interrupt device*/ +#define GPIO_RZ_TINT_ISR_DECLARE(irq_num, node_id) \ + static void rz_gpio_isr_##irq_num(void *param) \ + { \ + gpio_rz_tint_isr(DT_IRQ_BY_IDX(node_id, irq_num, irq), param); \ + } + +#define GPIO_RZ_TINT_ISR_INIT(node_id, irq_num) LISTIFY(irq_num, \ + GPIO_RZ_TINT_ISR_DECLARE, (), node_id) + +#define GPIO_RZ_TINT_CONNECT(irq_num, node_id) \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, irq_num, irq), \ + DT_IRQ_BY_IDX(node_id, irq_num, priority), rz_gpio_isr_##irq_num, \ + DEVICE_DT_GET(node_id), 0); + +#define GPIO_RZ_TINT_CONNECT_FUNC(node_id) \ + static void rz_gpio_tint_connect_func##node_id(void) \ + { \ + LISTIFY(DT_NUM_IRQS(node_id), \ + GPIO_RZ_TINT_CONNECT, (;), \ + node_id) \ + } +/* Initialize GPIO device*/ +#define GPIO_RZ_INT_INIT(node_id) \ + GPIO_RZ_TINT_ISR_INIT(node_id, DT_NUM_IRQS(node_id)) \ + GPIO_RZ_TINT_CONNECT_FUNC(node_id) \ + static const struct gpio_rz_tint_config rz_gpio_tint_cfg_##node_id = { \ + .gpio_int_init = rz_gpio_tint_connect_func##node_id, \ + }; \ + static struct gpio_rz_tint_data rz_gpio_tint_data_##node_id = {}; \ + DEVICE_DT_DEFINE(node_id, gpio_rz_int_init, NULL, &rz_gpio_tint_data_##node_id, \ + &rz_gpio_tint_cfg_##node_id, POST_KERNEL, \ + UTIL_DEC(CONFIG_GPIO_INIT_PRIORITY), NULL); + +DT_FOREACH_STATUS_OKAY(renesas_rz_gpio_int, GPIO_RZ_INT_INIT) + +#define VALUE_2X(i, _) UTIL_X2(i) +#define PIN_IRQ_GET(idx, inst) \ + COND_CODE_1(DT_INST_PROP_HAS_IDX(inst, irqs, idx), \ + ([DT_INST_PROP_BY_IDX(inst, irqs, idx)] = \ + DT_INST_PROP_BY_IDX(inst, irqs, UTIL_INC(idx)),), \ + ()) + +#define PIN_IRQS_GET(inst) \ + FOR_EACH_FIXED_ARG(PIN_IRQ_GET, (), inst, \ + LISTIFY(DT_INST_PROP_LEN_OR(inst, irqs, 0), VALUE_2X, (,))) + +#define RZG_GPIO_PORT_INIT(inst) \ + static ioport_cfg_t g_ioport_##inst##_cfg = { \ + .number_of_pins = 0, \ + .p_pin_cfg_data = NULL, \ + .p_extend = NULL, \ + }; \ + static const struct gpio_rz_config gpio_rz_##inst##_config = { \ + .common = \ + { \ + .port_pin_mask = \ + (gpio_port_pins_t)GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ + }, \ + .fsp_port = (uint32_t)DT_INST_REG_ADDR(inst), \ + .port_num = (uint8_t)DT_NODE_CHILD_IDX(DT_DRV_INST(inst)), \ + .ngpios = (uint8_t)DT_INST_PROP(inst, ngpios), \ + .fsp_cfg = &g_ioport_##inst##_cfg, \ + .fsp_api = &g_ioport_on_ioport, \ + .int_dev = DEVICE_DT_GET_OR_NULL(DT_INST(0, renesas_rz_gpio_int)), \ + .tint_num = {PIN_IRQS_GET(inst)}, \ + }; \ + static ioport_instance_ctrl_t g_ioport_##inst##_ctrl; \ + static struct gpio_rz_data gpio_rz_##inst##_data = { \ + .fsp_ctrl = &g_ioport_##inst##_ctrl, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &gpio_rz_##inst##_data, &gpio_rz_##inst##_config, \ + POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, &gpio_rz_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RZG_GPIO_PORT_INIT) diff --git a/drivers/gpio/gpio_renesas_rz.h b/drivers/gpio/gpio_renesas_rz.h new file mode 100644 index 00000000000..6980450f40c --- /dev/null +++ b/drivers/gpio/gpio_renesas_rz.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_GPIO_RENESAS_RZ_H_ +#define ZEPHYR_DRIVERS_GPIO_RENESAS_RZ_H_ + +#include +#include "r_ioport.h" + +#define GPIO_RZ_IOPORT_P_REG_BASE_GET (&R_GPIO->P_20) +#define GPIO_RZ_IOPORT_PM_REG_BASE_GET (&R_GPIO->PM_20) + +#define GPIO_RZ_REG_OFFSET(port, pin) (port + (pin / 4)) + +#define GPIO_RZ_P_VALUE_GET(value, pin) ((value >> pin) & 1U) +#define GPIO_RZ_PM_VALUE_GET(value, pin) ((value >> (pin * 2)) & 3U) + +#define GPIO_RZ_MAX_PORT_NUM 19 +#define GPIO_RZ_MAX_TINT_NUM 32 + +#define GPIO_RZ_TINT_IRQ_OFFSET 429 +#define GPIO_RZ_TINT_IRQ_GET(tint_num) (tint_num + GPIO_RZ_TINT_IRQ_OFFSET) + +#define GPIO_RZ_TINT_EDGE_RISING 0x0 +#define GPIO_RZ_TINT_EDGE_FALLING 0x1 +#define GPIO_RZ_TINT_LEVEL_HIGH 0x2 +#define GPIO_RZ_TINT_LEVEL_LOW 0x3 + +#define GPIO_RZ_TSSR_VAL(port, pin) (0x80 | (gpio_rz_int[port] + pin)) +#define GPIO_RZ_TSSR_OFFSET(irq) ((irq % 4) * 8) +#define GPIO_RZ_TITSR_OFFSET(irq) ((irq % 16) * 2) + +#define GPIO_RZ_PIN_CONFIGURE_GET_FILTER(flag) (((flags >> RZG3S_GPIO_FILTER_SHIFT) & 0x1F) << 19U) +#define GPIO_RZ_PIN_CONFIGURE_GET_DRIVE_ABILITY(flag) \ + (((flag >> RZG3S_GPIO_IOLH_SHIFT) & 0x3) << 10U) + +#define GPIO_RZ_PIN_CONFIGURE_INT_ENABLE IOPORT_CFG_TINT_ENABLE +#define GPIO_RZ_PIN_CONFIGURE_INT_DISABLE (~(IOPORT_CFG_TINT_ENABLE)) +#define GPIO_RZ_PIN_CONFIGURE_INPUT_OUTPUT_RESET (~(0x3 << 2)) + +static const uint8_t gpio_rz_int[GPIO_RZ_MAX_PORT_NUM] = {0, 4, 9, 13, 17, 23, 28, 33, 38, 43, + 47, 52, 56, 58, 63, 66, 70, 72, 76}; +#endif /* ZEPHYR_DRIVERS_GPIO_RENESAS_RZ_H_ */ diff --git a/dts/arm/renesas/rz/rzg/r9a08g045.dtsi b/dts/arm/renesas/rz/rzg/r9a08g045.dtsi index e7882aef751..2bbb5573b15 100644 --- a/dts/arm/renesas/rz/rzg/r9a08g045.dtsi +++ b/dts/arm/renesas/rz/rzg/r9a08g045.dtsi @@ -36,6 +36,193 @@ compatible = "renesas,rzg-pinctrl"; reg = <0x41030000 DT_SIZE_K(64)>; reg-names = "pinctrl"; + + gpio: gpio-common { + compatible = "renesas,rz-gpio-int"; + interrupts = + <429 10>, <430 10>, <431 10>, <432 10>, + <433 10>, <434 10>, <435 10>, <436 10>, + <437 10>, <438 10>, <439 10>, <440 10>, + <441 10>, <442 10>, <443 10>, <444 10>, + <445 10>, <446 10>, <447 10>, <448 10>, + <449 10>, <450 10>, <451 10>, <452 10>, + <453 10>, <454 10>, <455 10>, <456 10>, + <457 10>, <458 10>, <459 10>, <460 10>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + gpio0: gpio@0 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <4>; + reg = <0x0>; + status = "disabled"; + }; + + gpio1: gpio@1000 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x1000>; + status = "disabled"; + }; + + gpio2: gpio@1100 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <4>; + reg = <0x1100>; + status = "disabled"; + }; + + gpio3: gpio@1200 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <4>; + reg = <0x1200>; + status = "disabled"; + }; + + gpio4: gpio@1300 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <6>; + reg = <0x1300>; + status = "disabled"; + }; + + gpio5: gpio@100 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x100>; + status = "disabled"; + }; + + gpio6: gpio@200 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x200>; + status = "disabled"; + }; + + gpio7: gpio@1400 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x1400>; + status = "disabled"; + }; + + gpio8: gpio@1500 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x1500>; + status = "disabled"; + }; + + gpio9: gpio@1600 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <4>; + reg = <0x1600>; + status = "disabled"; + }; + + gpio10: gpio@1700 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x1700>; + status = "disabled"; + }; + + gpio11: gpio@300 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <4>; + reg = <0x300>; + status = "disabled"; + }; + + gpio12: gpio@400 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <2>; + reg = <0x400>; + status = "disabled"; + }; + + gpio13: gpio@500 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <5>; + reg = <0x500>; + status = "disabled"; + }; + + gpio14: gpio@600 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <3>; + reg = <0x600>; + status = "disabled"; + }; + + gpio15: gpio@700 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <4>; + reg = <0x700>; + status = "disabled"; + }; + + gpio16: gpio@800 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <2>; + reg = <0x800>; + status = "disabled"; + }; + + gpio17: gpio@900 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells= <2>; + ngpios = <4>; + reg = <0x900>; + status = "disabled"; + }; + + gpio18: gpio@A00 { + compatible = "renesas,rz-gpio"; + gpio-controller; + #gpio-cells=<2>; + ngpios = <6>; + reg = <0xA00>; + status = "disabled"; + }; + }; }; scif0: serial@4004b800 { diff --git a/dts/bindings/gpio/renesas,rz-gpio-int.yaml b/dts/bindings/gpio/renesas,rz-gpio-int.yaml new file mode 100644 index 00000000000..bffe75c2d7b --- /dev/null +++ b/dts/bindings/gpio/renesas,rz-gpio-int.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RZ GPIO Interrupt + +compatible: "renesas,rz-gpio-int" + +include: base.yaml + +properties: + interrupts: + required: true + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 diff --git a/dts/bindings/gpio/renesas,rz-gpio.yaml b/dts/bindings/gpio/renesas,rz-gpio.yaml new file mode 100644 index 00000000000..9b4a37e6c17 --- /dev/null +++ b/dts/bindings/gpio/renesas,rz-gpio.yaml @@ -0,0 +1,43 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + Reneses RZ GPIO controller node. + Sample of usage: + gpio-consumer{ + out-gpio = <&gpio8 2 (GPIO_PULL_UP); + }; + &gpio8{ + irq = <2 10>, <9 1>; + status = "okay"; + }; + Example above will configure pin 2 port 8: + - Using interrupt TINT10 + - Set Pullup + + +compatible: "renesas,rz-gpio" + +include: +- name: base.yaml + property-allowlist: + - status + - reg + - label +- name: gpio-controller.yaml + +properties: + reg: + required: true + description: GPIO port number + + irqs: + type: array + description: pin-irq pairs + + "#gpio-cells": + const: 2 + +gpio-cells: +- pin +- flags diff --git a/include/zephyr/dt-bindings/gpio/renesas-rz-gpio.h b/include/zephyr/dt-bindings/gpio/renesas-rz-gpio.h new file mode 100644 index 00000000000..30729af98bd --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/renesas-rz-gpio.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZ_GPIO_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZ_GPIO_H_ + +/*********************************RZG3S*****************************************/ + +/** + * @brief RZ G3S specific GPIO Flags + * The pin driving ability flags are encoded in the 8 upper bits of @ref gpio_dt_flags_t as + * follows: + * - Bit 9..8: Pin driving ability value + * - Bit 11..10: Digital Noise Filter Clock Selection value + * - Bit 13..12: Digital Noise Filter Number value + * - Bit 14: Digital Noise Filter ON/OFF + * example: + * gpio-consumer { + * out-gpios = <&port8 2 (GPIO_PULL_UP | RZG3S_GPIO_FILTER_SET(1, 3, 3))>; + * }; + * gpio-consumer { + * out-gpios = <&port8 2 (GPIO_PULL_UP | RZG3S_GPIO_IOLH_SET(2))>; + * }; + */ + +/* GPIO drive IOLH */ +#define RZG3S_GPIO_IOLH_SHIFT 7U +#define RZG3S_GPIO_IOLH_SET(iolh_val) (iolh_val << RZG3S_GPIO_IOLH_SHIFT) + +/* GPIO filter */ +#define RZG3S_GPIO_FILTER_SHIFT 9U +#define RZG3S_GPIO_FILNUM_SHIFT 1U +#define RZG3S_GPIO_FILCLKSEL_SHIFT 3U +#define RZG3S_GPIO_FILTER_SET(fillonoff, filnum, filclksel) \ + (((fillonoff) | ((filnum) << RZG3S_GPIO_FILNUM_SHIFT) | \ + ((filclksel) << RZG3S_GPIO_FILCLKSEL_SHIFT)) \ + << RZG3S_GPIO_FILTER_SHIFT) + +/*******************************************************************************/ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZ_GPIO_H_ */ diff --git a/samples/basic/button/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay b/samples/basic/button/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay new file mode 100644 index 00000000000..3c8c3537e39 --- /dev/null +++ b/samples/basic/button/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&gpio{ + status = "okay"; +}; + +&gpio18{ + irqs = <0 16>; +}; diff --git a/tests/drivers/gpio/gpio_api_1pin/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay b/tests/drivers/gpio/gpio_api_1pin/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay new file mode 100644 index 00000000000..7ab7cc70492 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + led0 = &led_0; + }; + + gpio-led { + compatible = "gpio-leds"; + led_0: led_0 { + gpios = <&gpio13 1 0>; + }; + }; +}; + +&gpio{ + status = "okay"; +}; + +&gpio13 { + irqs = <1 1>; + status = "okay"; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.conf b/tests/drivers/gpio/gpio_basic_api/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.conf new file mode 100644 index 00000000000..b9d02cf11d5 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.conf @@ -0,0 +1 @@ +CONFIG_SKIP_PULL_TEST=y diff --git a/tests/drivers/gpio/gpio_basic_api/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay b/tests/drivers/gpio/gpio_basic_api/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay new file mode 100644 index 00000000000..58b19b4dc12 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/rzg3s_smarc_r9a08g045s33gbg_cm33.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpio8 2 GPIO_ACTIVE_HIGH>; + in-gpios = <&gpio8 3 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpio{ + status = "okay"; +}; + +&gpio8{ + irqs = <3 20>; + status = "okay"; +};