Skip to content

Commit 517ff25

Browse files
committed
drivers: comparator: Add comparator driver support for RX
Add comparator support for Renesas RX with LVD Signed-off-by: Quy Tran <[email protected]>
1 parent cb2858f commit 517ff25

File tree

7 files changed

+411
-0
lines changed

7 files changed

+411
-0
lines changed

drivers/comparator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_COMP comparator_nrf_comp.c)
1515
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_LPCOMP comparator_nrf_lpcomp.c)
1616
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_SHELL comparator_shell.c)
1717
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_RENESAS_RA comparator_renesas_ra.c)
18+
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_RENESAS_RX_LVD comparator_renesas_rx_lvd.c)
1819
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_STM32_COMP comparator_stm32_comp.c)

drivers/comparator/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rsource "Kconfig.nrf_comp"
2727
rsource "Kconfig.nrf_lpcomp"
2828
rsource "Kconfig.shell"
2929
rsource "Kconfig.renesas_ra"
30+
rsource "Kconfig.renesas_rx"
3031
rsource "Kconfig.stm32_comp"
3132

3233
endif # COMPARATOR
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2025 Renesas Electronics Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config COMPARATOR_RENESAS_RX_LVD
5+
bool "Renesas RX LVD"
6+
default y
7+
depends on DT_HAS_RENESAS_RX_LVD_ENABLED
8+
select USE_RX_RDP_LVD
9+
select PINCTRL
10+
help
11+
Enable Comparator driver with Low Voltage Detection (LVD) feature for Renesas RX MCUs.
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Copyright (c) 2025 Renesas Electronics Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT renesas_rx_lvd
8+
9+
#include <zephyr/drivers/comparator.h>
10+
#include <zephyr/drivers/pinctrl.h>
11+
#include <zephyr/logging/log.h>
12+
#include <zephyr/sys/atomic.h>
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/irq.h>
15+
#include <soc.h>
16+
#include "r_lvd_rx_if.h"
17+
18+
LOG_MODULE_REGISTER(renesas_rx_lvd, CONFIG_COMPARATOR_LOG_LEVEL);
19+
20+
#define LVD0_NODE DT_NODELABEL(lvd0)
21+
#define LVD1_NODE DT_NODELABEL(lvd1)
22+
#define LVD_RENESAS_RX_FLAG BIT(0)
23+
/*
24+
* The extern functions below are implemented in the r_lvd_rx_hw.c source file.
25+
* For more information, please refer to r_lvd_rx_hw.c in HAL Renesas
26+
*/
27+
extern void lvd_ch1_isr(void);
28+
extern void lvd_ch2_isr(void);
29+
extern void lvd_start_lvd(lvd_channel_t ch, lvd_trigger_t trigger);
30+
extern void lvd_stop_lvd(lvd_channel_t ch);
31+
extern void lvd_start_int(lvd_channel_t ch, void (*p_callback)(void *));
32+
extern void lvd_stop_int(lvd_channel_t ch);
33+
extern void lvd_hw_enable_reset_int(lvd_channel_t ch, bool enable);
34+
extern void lvd_hw_enable_reg_protect(bool enable);
35+
36+
struct lvd_renesas_rx_data {
37+
lvd_config_t lvd_config;
38+
void (*callback)(void *args);
39+
comparator_callback_t user_cb;
40+
void *user_cb_data;
41+
atomic_t flags;
42+
};
43+
44+
struct lvd_renesas_rx_config {
45+
lvd_channel_t channel;
46+
uint8_t vdet_target;
47+
uint8_t lvd_action;
48+
bool lvd_support_cmpa;
49+
};
50+
51+
static int lvd_renesas_rx_get_output(const struct device *dev)
52+
{
53+
const struct lvd_renesas_rx_config *config = dev->config;
54+
lvd_status_position_t status_position;
55+
/* unused variable, just for API compatibility */
56+
lvd_status_cross_t unused_status_cross;
57+
lvd_err_t err;
58+
59+
err = R_LVD_GetStatus(config->channel, &status_position, &unused_status_cross);
60+
if (err != 0) {
61+
LOG_ERR("Failed to get status");
62+
return -EIO;
63+
}
64+
65+
switch (status_position) {
66+
case LVD_STATUS_POSITION_ABOVE:
67+
return 1;
68+
69+
case LVD_STATUS_POSITION_BELOW:
70+
return 0;
71+
72+
default:
73+
LOG_ERR("Invalid status, please check the configuration");
74+
return -EIO;
75+
}
76+
}
77+
78+
static int lvd_renesas_rx_set_trigger(const struct device *dev, enum comparator_trigger trigger)
79+
{
80+
struct lvd_renesas_rx_data *data = dev->data;
81+
const struct lvd_renesas_rx_config *config = dev->config;
82+
83+
lvd_hw_enable_reg_protect(false);
84+
lvd_stop_lvd(config->channel);
85+
lvd_stop_int(config->channel);
86+
87+
switch (trigger) {
88+
case COMPARATOR_TRIGGER_RISING_EDGE:
89+
data->lvd_config.trigger = LVD_TRIGGER_RISE;
90+
break;
91+
92+
case COMPARATOR_TRIGGER_FALLING_EDGE:
93+
data->lvd_config.trigger = LVD_TRIGGER_FALL;
94+
break;
95+
96+
case COMPARATOR_TRIGGER_BOTH_EDGES:
97+
data->lvd_config.trigger = LVD_TRIGGER_BOTH;
98+
break;
99+
100+
case COMPARATOR_TRIGGER_NONE:
101+
LOG_ERR("Trigger NONE is not supported");
102+
return -ENOTSUP;
103+
104+
default:
105+
LOG_ERR("Invalid trigger type.");
106+
return -EINVAL;
107+
}
108+
109+
lvd_start_int(config->channel, data->callback);
110+
lvd_start_lvd(config->channel, data->lvd_config.trigger);
111+
lvd_hw_enable_reg_protect(true);
112+
113+
return 0;
114+
}
115+
116+
static int lvd_renesas_rx_set_trigger_callback(const struct device *dev,
117+
comparator_callback_t callback, void *user_data)
118+
{
119+
struct lvd_renesas_rx_data *data = dev->data;
120+
const struct lvd_renesas_rx_config *config = dev->config;
121+
122+
if ((config->lvd_action == 0) || (config->lvd_action == 3)) {
123+
LOG_ERR("Callback function is not supported with the current action");
124+
return -ENOTSUP;
125+
}
126+
127+
/* Disable interrupt */
128+
lvd_hw_enable_reset_int(config->channel, false);
129+
130+
data->user_cb = callback;
131+
data->user_cb_data = user_data;
132+
133+
/* Enable interrupt */
134+
lvd_hw_enable_reset_int(config->channel, true);
135+
return 0;
136+
}
137+
138+
static int lvd_renesas_rx_trigger_is_pending(const struct device *dev)
139+
{
140+
struct lvd_renesas_rx_data *data = dev->data;
141+
const struct lvd_renesas_rx_config *config = dev->config;
142+
143+
if (data->flags & LVD_RENESAS_RX_FLAG) {
144+
atomic_and(&data->flags, ~LVD_RENESAS_RX_FLAG);
145+
R_LVD_ClearStatus(config->channel);
146+
return 1;
147+
}
148+
149+
return 0;
150+
}
151+
152+
static int renesas_rx_pin_set_cmpa(const struct device *dev)
153+
{
154+
const struct lvd_renesas_rx_config *config = dev->config;
155+
const struct pinctrl_dev_config *pcfg;
156+
int ret;
157+
158+
if (config->channel == 0) {
159+
if (DT_NODE_HAS_PROP(LVD0_NODE, pinctrl_0)) {
160+
PINCTRL_DT_DEFINE(LVD0_NODE);
161+
pcfg = PINCTRL_DT_DEV_CONFIG_GET(LVD0_NODE);
162+
} else {
163+
LOG_ERR("No pinctrl-0 property found in the device tree");
164+
return -EINVAL;
165+
}
166+
} else {
167+
if (DT_NODE_HAS_PROP(LVD1_NODE, pinctrl_0)) {
168+
PINCTRL_DT_DEFINE(LVD1_NODE);
169+
pcfg = PINCTRL_DT_DEV_CONFIG_GET(LVD1_NODE);
170+
} else {
171+
LOG_ERR("No pinctrl_0 property found in the device tree");
172+
return -EINVAL;
173+
}
174+
}
175+
176+
/* In the case of monitoring the CMPA pin, set the CMPA pin. */
177+
ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);
178+
if (ret < 0) {
179+
LOG_ERR("Failed to apply pinctrl state: %d\n", ret);
180+
return -EINVAL;
181+
}
182+
183+
return 0;
184+
}
185+
186+
static inline void lvd_irq_connect(void)
187+
{
188+
#if DT_NODE_HAS_STATUS_OKAY(LVD0_NODE)
189+
IRQ_CONNECT(DT_IRQN(LVD0_NODE), DT_IRQ(LVD0_NODE, priority), lvd_ch1_isr,
190+
DEVICE_DT_GET(LVD0_NODE), 0);
191+
irq_enable(DT_IRQN(LVD0_NODE));
192+
#endif
193+
#if DT_NODE_HAS_STATUS_OKAY(LVD1_NODE)
194+
IRQ_CONNECT(DT_IRQN(LVD1_NODE), DT_IRQ(LVD1_NODE, priority), lvd_ch2_isr,
195+
DEVICE_DT_GET(LVD1_NODE), 0);
196+
irq_enable(DT_IRQN(LVD1_NODE));
197+
#endif
198+
}
199+
200+
static int lvd_renesas_rx_init(const struct device *dev)
201+
{
202+
lvd_err_t err;
203+
204+
lvd_irq_connect();
205+
206+
const struct lvd_renesas_rx_config *config = dev->config;
207+
const struct lvd_renesas_rx_data *data = dev->data;
208+
209+
/* In reset or no-action when LVD is detected, callback will not be triggered. */
210+
err = R_LVD_Open(config->channel, &data->lvd_config, data->callback);
211+
if (err != 0) {
212+
LOG_ERR("Failed to initialize LVD channel %d", config->channel);
213+
return -EIO;
214+
}
215+
216+
/* Set the CMPA pin if the target is CMPA */
217+
/* NOTE: For the RX130 series, CMPA is only used on channel 2. */
218+
if ((config->lvd_support_cmpa) && (config->vdet_target == 1)) {
219+
return renesas_rx_pin_set_cmpa(dev);
220+
}
221+
222+
return 0;
223+
}
224+
225+
static DEVICE_API(comparator, lvd_renesas_rx_api) = {
226+
.get_output = lvd_renesas_rx_get_output,
227+
.set_trigger = lvd_renesas_rx_set_trigger,
228+
.set_trigger_callback = lvd_renesas_rx_set_trigger_callback,
229+
.trigger_is_pending = lvd_renesas_rx_trigger_is_pending,
230+
};
231+
232+
#define LVD_RENESAS_RX_INIT(index) \
233+
\
234+
static const struct lvd_renesas_rx_config lvd_renesas_rx_config_##index = { \
235+
.channel = DT_INST_PROP(index, channel), \
236+
.lvd_action = DT_INST_ENUM_IDX(index, lvd_action), \
237+
.vdet_target = DT_INST_ENUM_IDX(index, vdet_target), \
238+
.lvd_support_cmpa = DT_INST_PROP(index, lvd_support_cmpa), \
239+
}; \
240+
\
241+
void rx_lvd_callback_##index(void *args) \
242+
{ \
243+
ARG_UNUSED(args); \
244+
const struct device *dev = DEVICE_DT_GET(DT_INST(index, renesas_rx_lvd)); \
245+
struct lvd_renesas_rx_data *data = dev->data; \
246+
comparator_callback_t cb = data->user_cb; \
247+
\
248+
/* Call the user's callback function*/ \
249+
if (cb) { \
250+
cb(dev, data->user_cb_data); \
251+
return; \
252+
} \
253+
atomic_or(&data->flags, LVD_RENESAS_RX_FLAG); \
254+
}; \
255+
\
256+
static struct lvd_renesas_rx_data lvd_renesas_rx_data_##index = { \
257+
.lvd_config = \
258+
{ \
259+
.trigger = DT_INST_ENUM_IDX(index, lvd_trigger), \
260+
}, \
261+
.callback = rx_lvd_callback_##index, \
262+
.flags = 0, \
263+
}; \
264+
\
265+
DEVICE_DT_INST_DEFINE(index, lvd_renesas_rx_init, NULL, &lvd_renesas_rx_data_##index, \
266+
&lvd_renesas_rx_config_##index, PRE_KERNEL_1, \
267+
CONFIG_COMPARATOR_INIT_PRIORITY, &lvd_renesas_rx_api);
268+
269+
DT_INST_FOREACH_STATUS_OKAY(LVD_RENESAS_RX_INIT)

0 commit comments

Comments
 (0)