Skip to content

Commit 6973539

Browse files
thenguyenyfkartben
authored andcommitted
drivers: gpio: add support for gpio interrupt on Renesas RA family
First commit to add support for gpio interrupt on Renesas RA - Add support for external interrupt driver - Add support for gpio interrupt config Signed-off-by: The Nguyen <[email protected]>
1 parent ab7fc19 commit 6973539

File tree

9 files changed

+445
-6
lines changed

9 files changed

+445
-6
lines changed

drivers/gpio/gpio_renesas_ra_ioport.c

Lines changed: 123 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,56 @@
99
#include <zephyr/drivers/gpio.h>
1010
#include <zephyr/drivers/pinctrl.h>
1111
#include <zephyr/dt-bindings/gpio/renesas-ra-gpio-ioport.h>
12+
#include <zephyr/drivers/misc/renesas_ra_external_interrupt/renesas_ra_external_interrupt.h>
1213
#include <zephyr/drivers/gpio/gpio_utils.h>
13-
#include <zephyr/irq.h>
1414
#include <soc.h>
1515

16+
struct gpio_ra_irq_info {
17+
const struct device *port_irq;
18+
const uint8_t *const pins;
19+
size_t num;
20+
};
21+
1622
struct gpio_ra_config {
1723
struct gpio_driver_config common;
1824
uint8_t port_num;
1925
R_PORT0_Type *port;
26+
const struct gpio_ra_irq_info *irq_info;
27+
const size_t irq_info_size;
2028
gpio_pin_t vbatt_pins[];
2129
};
2230

2331
struct gpio_ra_data {
2432
struct gpio_driver_data common;
33+
sys_slist_t callbacks;
2534
};
2635

36+
#if CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT
37+
static const struct gpio_ra_irq_info *query_irq_info(const struct device *dev, uint32_t pin)
38+
{
39+
const struct gpio_ra_config *config = dev->config;
40+
41+
for (int i = 0; i < config->irq_info_size; i++) {
42+
const struct gpio_ra_irq_info *info = &config->irq_info[i];
43+
44+
for (int j = 0; j < info->num; j++) {
45+
if (info->pins[j] == pin) {
46+
return info;
47+
}
48+
}
49+
}
50+
51+
return NULL;
52+
}
53+
54+
static void gpio_ra_callback_adapter(const struct device *dev, gpio_pin_t pin)
55+
{
56+
struct gpio_ra_data *data = dev->data;
57+
58+
gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
59+
}
60+
#endif
61+
2762
static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
2863
{
2964
const struct gpio_ra_config *config = dev->config;
@@ -39,7 +74,7 @@ static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_
3974
return -ENOTSUP;
4075
}
4176

42-
if ((flags & GPIO_INT_ENABLE) != 0) {
77+
if (!IS_ENABLED(CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT) && ((flags & GPIO_INT_ENABLE) != 0)) {
4378
return -ENOTSUP;
4479
}
4580

@@ -88,8 +123,54 @@ static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_
88123
WRITE_BIT(pfs_cfg, R_PFS_PORT_PIN_PmnPFS_PCR_Pos, 1);
89124
}
90125

91-
pincfg.cfg = pfs_cfg |
92-
(((flags & RENESAS_GPIO_DS_MSK) >> 8) << R_PFS_PORT_PIN_PmnPFS_DSCR_Pos);
126+
#if CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT
127+
if ((flags & GPIO_INT_ENABLE) != 0) {
128+
const struct gpio_ra_irq_info *irq_info = query_irq_info(dev, pin);
129+
int err = 0;
130+
131+
if (irq_info == NULL) {
132+
return -EINVAL;
133+
}
134+
135+
if (!device_is_ready(irq_info->port_irq)) {
136+
return -EWOULDBLOCK;
137+
}
138+
139+
struct gpio_ra_callback callback = {
140+
.port = (struct device *)dev,
141+
.port_num = config->port_num,
142+
.pin = pin,
143+
.mode = flags & (GPIO_INT_EDGE | GPIO_INT_DISABLE | GPIO_INT_ENABLE),
144+
.trigger = flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1),
145+
.isr = gpio_ra_callback_adapter,
146+
};
147+
148+
err = gpio_ra_interrupt_set(irq_info->port_irq, &callback);
149+
if (err < 0) {
150+
return err;
151+
}
152+
153+
WRITE_BIT(pfs_cfg, R_PFS_PORT_PIN_PmnPFS_ISEL_Pos, 1);
154+
}
155+
156+
if ((flags & GPIO_INT_DISABLE) != 0) {
157+
const struct gpio_ra_irq_info *irq_info = query_irq_info(dev, pin);
158+
159+
if (irq_info == NULL) {
160+
return -EINVAL;
161+
}
162+
163+
if (!device_is_ready(irq_info->port_irq)) {
164+
return -EWOULDBLOCK;
165+
}
166+
167+
gpio_ra_interrupt_unset(irq_info->port_irq, config->port_num, pin);
168+
WRITE_BIT(pfs_cfg, R_PFS_PORT_PIN_PmnPFS_ISEL_Pos, 0);
169+
}
170+
#endif
171+
172+
pincfg.cfg =
173+
pfs_cfg | (((flags & RENESAS_GPIO_DS_MSK) >> 8) << R_PFS_PORT_PIN_PmnPFS_DSCR_Pos);
93174

94175
return pinctrl_configure_pins(&pincfg, 1, PINCTRL_REG_NONE);
95176
}
@@ -145,18 +226,52 @@ static int gpio_ra_port_toggle_bits(const struct device *dev, gpio_port_pins_t p
145226
return 0;
146227
}
147228

229+
#if CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT
230+
static int gpio_ra_pin_interrupt_configure(const struct device *port, gpio_pin_t pin,
231+
enum gpio_int_mode mode, enum gpio_int_trig trig)
232+
{
233+
return gpio_ra_pin_configure(port, pin, (mode | trig));
234+
}
235+
236+
static int gpio_ra_manage_callback(const struct device *dev, struct gpio_callback *callback,
237+
bool set)
238+
{
239+
struct gpio_ra_data *data = dev->data;
240+
241+
return gpio_manage_callback(&data->callbacks, callback, set);
242+
}
243+
#endif
244+
148245
static DEVICE_API(gpio, gpio_ra_drv_api_funcs) = {
149246
.pin_configure = gpio_ra_pin_configure,
150247
.port_get_raw = gpio_ra_port_get_raw,
151248
.port_set_masked_raw = gpio_ra_port_set_masked_raw,
152249
.port_set_bits_raw = gpio_ra_port_set_bits_raw,
153250
.port_clear_bits_raw = gpio_ra_port_clear_bits_raw,
154251
.port_toggle_bits = gpio_ra_port_toggle_bits,
155-
.pin_interrupt_configure = NULL,
156-
.manage_callback = NULL,
252+
#if CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT
253+
.pin_interrupt_configure = gpio_ra_pin_interrupt_configure,
254+
.manage_callback = gpio_ra_manage_callback,
255+
#endif
157256
};
158257

258+
#define GPIO_RA_PINS_NAME(n, p, i) CONCAT(DT_STRING_TOKEN_BY_IDX(n, p, i), _pins)
259+
260+
#define GPIO_RA_DECL_PINS(n, p, i) \
261+
const uint8_t CONCAT(n, ___pins##i[]) = { \
262+
DT_FOREACH_PROP_ELEM_SEP(n, GPIO_RA_PINS_NAME(n, p, i), DT_PROP_BY_IDX, (,))};
263+
264+
#define GPIO_RA_IRQ_INFO(n, p, i) \
265+
{ \
266+
.port_irq = DEVICE_DT_GET_OR_NULL(DT_PHANDLE_BY_IDX(n, port_irqs, i)), \
267+
.pins = CONCAT(n, ___pins##i), \
268+
.num = ARRAY_SIZE(CONCAT(n, ___pins##i)), \
269+
},
270+
159271
#define GPIO_DEVICE_INIT(node, port_number, suffix, addr) \
272+
DT_FOREACH_PROP_ELEM(node, port_irq_names, GPIO_RA_DECL_PINS); \
273+
struct gpio_ra_irq_info gpio_ra_irq_info_##suffix[] = { \
274+
DT_FOREACH_PROP_ELEM(node, port_irq_names, GPIO_RA_IRQ_INFO)}; \
160275
static const struct gpio_ra_config gpio_ra_config_##suffix = { \
161276
.common = \
162277
{ \
@@ -165,6 +280,8 @@ static DEVICE_API(gpio, gpio_ra_drv_api_funcs) = {
165280
.port_num = port_number, \
166281
.port = (R_PORT0_Type *)addr, \
167282
.vbatt_pins = DT_PROP_OR(DT_NODELABEL(ioport##suffix), vbatts_pins, {0xFF}), \
283+
.irq_info = gpio_ra_irq_info_##suffix, \
284+
.irq_info_size = DT_PROP_LEN_OR(DT_NODELABEL(ioport##suffix), port_irq_names, 0), \
168285
}; \
169286
static struct gpio_ra_data gpio_ra_data_##suffix; \
170287
DEVICE_DT_DEFINE(node, NULL, NULL, &gpio_ra_data_##suffix, &gpio_ra_config_##suffix, \

drivers/misc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ add_subdirectory_ifdef(CONFIG_TIMEAWARE_GPIO timeaware_gpio)
99
add_subdirectory_ifdef(CONFIG_DEVMUX devmux)
1010
add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher)
1111
add_subdirectory_ifdef(CONFIG_MCUX_FLEXIO mcux_flexio)
12+
add_subdirectory_ifdef(CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT renesas_ra_external_interrupt)
1213
add_subdirectory(coresight)

drivers/misc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ source "drivers/misc/devmux/Kconfig"
1414
source "drivers/misc/nordic_vpr_launcher/Kconfig"
1515
source "drivers/misc/mcux_flexio/Kconfig"
1616
source "drivers/misc/coresight/Kconfig"
17+
source "drivers/misc/renesas_ra_external_interrupt/Kconfig"
1718

1819
endmenu
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT renesas_ra_external_interrupt.c)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2024 Renesas Electronics Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Renesas RA External Interrupt Option
5+
6+
config RENESAS_RA_EXTERNAL_INTERRUPT
7+
bool "Renesas RA External Interrupt Driver"
8+
depends on DT_HAS_RENESAS_RA_EXTERNAL_INTERRUPT_ENABLED
9+
default y
10+
help
11+
Enable config options for Renesas RA external interrupt
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright (c) 2024 Renesas Electronics Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT renesas_ra_external_interrupt
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/drivers/gpio.h>
11+
#include <zephyr/drivers/gpio/gpio_utils.h>
12+
#include <zephyr/irq.h>
13+
#include <zephyr/drivers/misc/renesas_ra_external_interrupt/renesas_ra_external_interrupt.h>
14+
#include <soc.h>
15+
16+
enum ext_irq_trigger {
17+
EXT_INTERRUPT_EDGE_FALLING = 0,
18+
EXT_INTERRUPT_EDGE_RISING,
19+
EXT_INTERRUPT_EDGE_BOTH,
20+
EXT_INTERRUPT_EDGE_LOW_LEVEL,
21+
};
22+
23+
enum ext_irq_sample_clock {
24+
EXT_INTERRUPT_SAMPLE_CLOCK_DIV_1 = 0,
25+
EXT_INTERRUPT_SAMPLE_CLOCK_DIV_8,
26+
EXT_INTERRUPT_SAMPLE_CLOCK_DIV_32,
27+
EXT_INTERRUPT_SAMPLE_CLOCK_DIV_64,
28+
};
29+
30+
struct gpio_ra_irq_config {
31+
mem_addr_t reg;
32+
unsigned int channel;
33+
enum ext_irq_trigger trigger;
34+
enum ext_irq_sample_clock sample_clock;
35+
bool digital_filter;
36+
unsigned int irq;
37+
};
38+
39+
struct gpio_ra_irq_data {
40+
struct gpio_ra_callback callback;
41+
struct k_sem irq_sem;
42+
};
43+
44+
/**
45+
* @brief setting interrupt for gpio input
46+
*
47+
* @param dev devive instance for gpio interrupt line
48+
* @param callback setting context for the callback
49+
* @retval 0 if success
50+
* @retval -EBUSY if interrupt line is inuse
51+
* @retval -ENOTSUP if interrupt mode is not supported
52+
*/
53+
int gpio_ra_interrupt_set(const struct device *dev, struct gpio_ra_callback *callback)
54+
{
55+
const struct gpio_ra_irq_config *config = dev->config;
56+
struct gpio_ra_irq_data *data = dev->data;
57+
uint8_t irqcr = sys_read8(config->reg) & ~R_ICU_IRQCR_IRQMD_Msk;
58+
59+
irq_disable(config->irq);
60+
61+
if (callback->mode == GPIO_INT_MODE_LEVEL) {
62+
if (callback->trigger != GPIO_INT_TRIG_LOW) {
63+
return -ENOTSUP;
64+
}
65+
66+
irqcr |= (EXT_INTERRUPT_EDGE_LOW_LEVEL & R_ICU_IRQCR_IRQMD_Msk);
67+
} else if (callback->mode == GPIO_INT_MODE_EDGE) {
68+
switch (callback->trigger) {
69+
case GPIO_INT_TRIG_LOW:
70+
irqcr |= (EXT_INTERRUPT_EDGE_FALLING & R_ICU_IRQCR_IRQMD_Msk);
71+
break;
72+
case GPIO_INT_TRIG_HIGH:
73+
irqcr |= (EXT_INTERRUPT_EDGE_RISING & R_ICU_IRQCR_IRQMD_Msk);
74+
break;
75+
case GPIO_INT_TRIG_BOTH:
76+
irqcr |= (EXT_INTERRUPT_EDGE_BOTH & R_ICU_IRQCR_IRQMD_Msk);
77+
break;
78+
default:
79+
return -ENOTSUP;
80+
}
81+
} else {
82+
return -ENOTSUP;
83+
}
84+
85+
if (data->callback.port_num != callback->port_num || data->callback.pin != callback->pin) {
86+
if (0 != k_sem_take(&data->irq_sem, K_NO_WAIT)) {
87+
return -EBUSY;
88+
}
89+
}
90+
91+
sys_write8(irqcr, config->reg);
92+
data->callback = *callback;
93+
irq_enable(config->irq);
94+
95+
return 0;
96+
}
97+
98+
/**
99+
* @brief unset interrupt configuration for the gpio interrupt
100+
*
101+
* @param dev device instance for port irq line
102+
* @param port_num gpio port number
103+
* @param pin the pin to disable interrupt
104+
*/
105+
void gpio_ra_interrupt_unset(const struct device *dev, uint8_t port_num, uint8_t pin)
106+
{
107+
const struct gpio_ra_irq_config *config = dev->config;
108+
struct gpio_ra_irq_data *data = dev->data;
109+
110+
if ((port_num != data->callback.port_num) && (pin != data->callback.pin)) {
111+
return;
112+
}
113+
114+
irq_disable(config->irq);
115+
k_sem_give(&data->irq_sem);
116+
}
117+
118+
void gpio_ra_isr(const struct device *dev)
119+
{
120+
const struct gpio_ra_irq_data *data = dev->data;
121+
const struct gpio_ra_irq_config *config = dev->config;
122+
123+
data->callback.isr(data->callback.port, data->callback.pin);
124+
R_BSP_IrqStatusClear(config->irq);
125+
}
126+
127+
static int gpio_ra_interrupt_init(const struct device *dev)
128+
{
129+
const struct gpio_ra_irq_config *config = dev->config;
130+
struct gpio_ra_irq_data *data = dev->data;
131+
uint8_t irqcr = ((config->trigger << R_ICU_IRQCR_IRQMD_Pos));
132+
133+
WRITE_BIT(irqcr, R_ICU_IRQCR_FLTEN_Pos, config->digital_filter);
134+
sys_write8(irqcr, config->reg);
135+
k_sem_init(&data->irq_sem, 1, 1);
136+
137+
return 0;
138+
}
139+
140+
#define GPIO_INTERRUPT_INIT(index) \
141+
static const struct gpio_ra_irq_config gpio_ra_irq_config##index = { \
142+
.reg = DT_INST_REG_ADDR(index), \
143+
.channel = DT_INST_PROP(index, channel), \
144+
.trigger = \
145+
DT_INST_ENUM_IDX_OR(index, renesas_trigger, EXT_INTERRUPT_EDGE_FALLING), \
146+
.digital_filter = DT_INST_PROP_OR(index, renesas_digital_filtering, false), \
147+
.sample_clock = UTIL_CAT(EXT_INTERRUPT_SAMPLE_CLOCK_DIV_, \
148+
DT_INST_PROP_OR(index, renesas_sample_clock_div, 1)), \
149+
.irq = DT_INST_IRQ(index, irq), \
150+
}; \
151+
static struct gpio_ra_irq_data gpio_ra_irq_data##index; \
152+
static int gpio_ra_irq_init##index(const struct device *dev) \
153+
{ \
154+
R_ICU->IELSR[DT_INST_IRQ(index, irq)] = \
155+
UTIL_CAT(ELC_EVENT_ICU_IRQ, DT_INST_PROP(index, channel)); \
156+
IRQ_CONNECT(DT_INST_IRQ(index, irq), DT_INST_IRQ(index, priority), gpio_ra_isr, \
157+
DEVICE_DT_INST_GET(index), 0); \
158+
return gpio_ra_interrupt_init(dev); \
159+
}; \
160+
DEVICE_DT_INST_DEFINE(index, gpio_ra_irq_init##index, NULL, &gpio_ra_irq_data##index, \
161+
&gpio_ra_irq_config##index, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
162+
NULL);
163+
164+
DT_INST_FOREACH_STATUS_OKAY(GPIO_INTERRUPT_INIT)

0 commit comments

Comments
 (0)