Skip to content

Commit 22137fd

Browse files
Minh Tangthenguyenyf
authored andcommitted
drivers: comparator: Add comparator LVD driver support for RA
Add comparator support for RA with LVD module Signed-off-by: Minh Tang <[email protected]>
1 parent b91b079 commit 22137fd

File tree

5 files changed

+426
-0
lines changed

5 files changed

+426
-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_RA_LVD comparator_renesas_ra_lvd.c)
1819
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_STM32_COMP comparator_stm32_comp.c)

drivers/comparator/Kconfig.renesas_ra

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,12 @@ config COMPARATOR_RENESAS_RA
99
select PINCTRL
1010
help
1111
Enable Renesas RA ACMPHS Driver.
12+
13+
config COMPARATOR_RENESAS_RA_LVD
14+
bool "Renesas RA LVD"
15+
default y
16+
depends on DT_HAS_RENESAS_RA_LVD_ENABLED
17+
select USE_RA_FSP_LVD
18+
select RUNTIME_NMI
19+
help
20+
Enable Renesas RA LVD Driver.
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/*
2+
* Copyright (c) 2025 Renesas Electronics Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT renesas_ra_lvd
8+
9+
#include <soc.h>
10+
#include <zephyr/drivers/comparator.h>
11+
#include <zephyr/irq.h>
12+
#include <zephyr/kernel.h>
13+
#include <zephyr/logging/log.h>
14+
#include <zephyr/sys/atomic.h>
15+
16+
#include <r_lvd.h>
17+
#include <rp_lvd.h>
18+
19+
LOG_MODULE_REGISTER(renesas_ra_lvd, CONFIG_COMPARATOR_LOG_LEVEL);
20+
21+
#define LVD_RENESAS_RA_EVT_PENDING BIT(0)
22+
23+
enum lvd_action {
24+
LVD_ACTION_NMI,
25+
LVD_ACTION_MI,
26+
LVD_ACTION_RESET,
27+
LVD_ACTION_NONE,
28+
};
29+
30+
extern void lvd_lvd_isr(void);
31+
32+
struct lvd_renesas_ra_data {
33+
lvd_instance_ctrl_t lvd_ctrl;
34+
lvd_cfg_t lvd_config;
35+
comparator_callback_t user_cb;
36+
void *user_cb_data;
37+
atomic_t flags;
38+
};
39+
40+
struct lvd_renesas_ra_config {
41+
bool reset_only;
42+
enum lvd_action action;
43+
void (*irq_config_func)(void);
44+
};
45+
46+
static int lvd_renesas_ra_get_output(const struct device *dev)
47+
{
48+
struct lvd_renesas_ra_data *data = dev->data;
49+
const struct lvd_renesas_ra_config *config = dev->config;
50+
lvd_status_t status;
51+
fsp_err_t err;
52+
53+
if (config->reset_only) {
54+
LOG_ERR("Get output is not supported on this LVD channel");
55+
return -ENOTSUP;
56+
}
57+
58+
err = R_LVD_StatusGet(&data->lvd_ctrl, &status);
59+
if (err != FSP_SUCCESS) {
60+
LOG_ERR("Failed to get LVD status");
61+
return -EIO;
62+
}
63+
64+
return status.current_state;
65+
}
66+
67+
static int lvd_renesas_ra_set_trigger(const struct device *dev, enum comparator_trigger trigger)
68+
{
69+
const struct lvd_renesas_ra_config *config = dev->config;
70+
struct lvd_renesas_ra_data *data = dev->data;
71+
bool trigger_set = trigger != COMPARATOR_TRIGGER_NONE;
72+
bool reset = config->action == LVD_ACTION_RESET;
73+
lvd_voltage_slope_t voltage_slope;
74+
fsp_err_t fsp_err;
75+
76+
if (config->action == LVD_ACTION_NONE) {
77+
LOG_WRN("TRIGGER do not take effect when action is no action");
78+
return 0;
79+
}
80+
81+
if (reset && trigger == COMPARATOR_TRIGGER_BOTH_EDGES) {
82+
LOG_ERR("Could not set both edges trigger when action is reset");
83+
return -EINVAL;
84+
}
85+
86+
if (trigger_set) {
87+
switch (trigger) {
88+
case COMPARATOR_TRIGGER_RISING_EDGE:
89+
voltage_slope = LVD_VOLTAGE_SLOPE_RISING;
90+
break;
91+
case COMPARATOR_TRIGGER_FALLING_EDGE:
92+
voltage_slope = LVD_VOLTAGE_SLOPE_FALLING;
93+
break;
94+
case COMPARATOR_TRIGGER_BOTH_EDGES:
95+
voltage_slope = LVD_VOLTAGE_SLOPE_BOTH;
96+
break;
97+
default:
98+
return -EINVAL;
99+
}
100+
}
101+
102+
fsp_err = RP_LVD_Enable(&data->lvd_ctrl, trigger_set);
103+
if (fsp_err != FSP_SUCCESS) {
104+
return -EIO;
105+
}
106+
107+
if (trigger_set) {
108+
fsp_err = RP_LVD_TriggerSet(&data->lvd_ctrl, reset, voltage_slope);
109+
if (fsp_err != FSP_SUCCESS) {
110+
return -EIO;
111+
}
112+
}
113+
114+
return 0;
115+
}
116+
117+
static int lvd_renesas_ra_set_trigger_callback(const struct device *dev,
118+
comparator_callback_t callback, void *user_data)
119+
{
120+
struct lvd_renesas_ra_data *data = dev->data;
121+
const struct lvd_renesas_ra_config *config = dev->config;
122+
fsp_err_t fsp_err;
123+
bool enabled_status;
124+
125+
if (config->action == LVD_ACTION_NONE || config->action == LVD_ACTION_RESET) {
126+
LOG_ERR("Could not set callback for when action is not interrupt");
127+
return -ENOTSUP;
128+
}
129+
130+
fsp_err = RP_LVD_IsEnable(&data->lvd_ctrl, &enabled_status);
131+
if (fsp_err != FSP_SUCCESS) {
132+
return -EIO;
133+
}
134+
135+
fsp_err = RP_LVD_Enable(&data->lvd_ctrl, false);
136+
if (fsp_err != FSP_SUCCESS) {
137+
return -EIO;
138+
}
139+
140+
data->user_cb = callback;
141+
data->user_cb_data = user_data;
142+
143+
fsp_err = RP_LVD_Enable(&data->lvd_ctrl, enabled_status);
144+
if (fsp_err != FSP_SUCCESS) {
145+
return -EIO;
146+
}
147+
148+
return 0;
149+
}
150+
151+
static int lvd_renesas_ra_trigger_is_pending(const struct device *dev)
152+
{
153+
struct lvd_renesas_ra_data *data = dev->data;
154+
const struct lvd_renesas_ra_config *config = dev->config;
155+
fsp_err_t fsp_err;
156+
157+
if (config->reset_only) {
158+
LOG_ERR("Get output is not supported on this LVD channel");
159+
return -ENOTSUP;
160+
}
161+
162+
if (atomic_cas(&data->flags, LVD_RENESAS_RA_EVT_PENDING, 0)) {
163+
fsp_err = R_LVD_StatusClear(&data->lvd_ctrl);
164+
if (fsp_err != FSP_SUCCESS) {
165+
return -EIO;
166+
}
167+
168+
return 1;
169+
}
170+
171+
return 0;
172+
}
173+
174+
static DEVICE_API(comparator, lvd_renesas_ra_api) = {
175+
.get_output = lvd_renesas_ra_get_output,
176+
.set_trigger = lvd_renesas_ra_set_trigger,
177+
.set_trigger_callback = lvd_renesas_ra_set_trigger_callback,
178+
.trigger_is_pending = lvd_renesas_ra_trigger_is_pending,
179+
};
180+
181+
static int lvd_renesas_ra_init(const struct device *dev)
182+
{
183+
fsp_err_t err;
184+
struct lvd_renesas_ra_data *data = dev->data;
185+
const struct lvd_renesas_ra_config *config = dev->config;
186+
187+
if (config->reset_only == true) {
188+
if (data->lvd_config.voltage_slope == LVD_VOLTAGE_SLOPE_RISING) {
189+
data->lvd_config.detection_response = LVD_RESPONSE_RESET_ON_RISING;
190+
} else {
191+
data->lvd_config.detection_response = LVD_RESPONSE_RESET;
192+
}
193+
} else {
194+
switch (config->action) {
195+
case LVD_ACTION_RESET:
196+
if (data->lvd_config.voltage_slope == LVD_VOLTAGE_SLOPE_RISING) {
197+
data->lvd_config.detection_response = LVD_RESPONSE_RESET_ON_RISING;
198+
} else {
199+
data->lvd_config.detection_response = LVD_RESPONSE_RESET;
200+
}
201+
break;
202+
case LVD_ACTION_NMI:
203+
data->lvd_config.detection_response = LVD_RESPONSE_NMI;
204+
break;
205+
case LVD_ACTION_MI:
206+
data->lvd_config.detection_response = LVD_RESPONSE_INTERRUPT;
207+
break;
208+
case LVD_ACTION_NONE:
209+
data->lvd_config.detection_response = LVD_RESPONSE_NONE;
210+
break;
211+
default:
212+
return -EINVAL;
213+
}
214+
}
215+
216+
err = R_LVD_Open(&data->lvd_ctrl, &data->lvd_config);
217+
if (err != 0) {
218+
LOG_ERR("Failed to initialize LVD channel %d", data->lvd_config.monitor_number);
219+
return -EIO;
220+
}
221+
222+
config->irq_config_func();
223+
224+
return 0;
225+
}
226+
227+
static void ra_lvd_callback(lvd_callback_args_t *p_args)
228+
{
229+
const struct device *dev = (const struct device *)(p_args->p_context);
230+
struct lvd_renesas_ra_data *data = dev->data;
231+
comparator_callback_t user_cb = data->user_cb;
232+
void *user_cb_data = data->user_cb_data;
233+
234+
if (user_cb) {
235+
user_cb(dev, user_cb_data);
236+
return;
237+
}
238+
239+
atomic_set(&data->flags, LVD_RENESAS_RA_EVT_PENDING);
240+
}
241+
242+
#define EVENT_LVD_INT(channel) BSP_PRV_IELS_ENUM(CONCAT(EVENT_LVD_LVD, channel))
243+
244+
#define LVD_RENESAS_RA_IRQ_INIT_FUNC_DEFINE(index) \
245+
IF_ENABLED(DT_INST_NODE_HAS_PROP(index, interrupts), \
246+
(R_ICU->IELSR_b[DT_INST_IRQN(index)].IELS = \
247+
EVENT_LVD_INT(DT_INST_PROP(index, channel)); \
248+
\
249+
BSP_ASSIGN_EVENT_TO_CURRENT_CORE(EVENT_LVD_INT(DT_INST_PROP(index, channel))); \
250+
\
251+
IRQ_CONNECT(DT_INST_IRQ(index, irq), DT_INST_IRQ(index, priority), \
252+
lvd_lvd_isr, DEVICE_DT_INST_GET(index), 0); \
253+
\
254+
irq_enable(DT_INST_IRQ(index, irq));))
255+
256+
#define DIGITAL_FILTER_GET(index) \
257+
COND_CODE_1(IS_EQ(DT_INST_PROP(index, noise_filter), 1), (LVD_SAMPLE_CLOCK_DISABLED), \
258+
(UTIL_CAT(LVD_SAMPLE_CLOCK_LOCO_DIV_, DT_INST_PROP(index, noise_filter))))
259+
260+
#define IRQ_PARAMETER(index) \
261+
COND_CODE_1(DT_INST_NODE_HAS_PROP(index, interrupts), (DT_INST_IRQ(index, irq)), \
262+
(FSP_INVALID_VECTOR))
263+
264+
#define IPL_PARAMETER(index) \
265+
COND_CODE_1(DT_INST_NODE_HAS_PROP(index, interrupts), (DT_INST_IRQ(index, priority)), \
266+
(BSP_IRQ_DISABLED))
267+
268+
#define LVD_RENESAS_RA_INIT(index) \
269+
\
270+
void lvd_renesas_ra_irq_config_func_##index(void) \
271+
{ \
272+
LVD_RENESAS_RA_IRQ_INIT_FUNC_DEFINE(index) \
273+
} \
274+
\
275+
static const struct lvd_renesas_ra_config lvd_renesas_ra_config_##index = { \
276+
.reset_only = DT_INST_PROP(index, reset_only), \
277+
.action = DT_INST_ENUM_IDX(index, lvd_action), \
278+
.irq_config_func = lvd_renesas_ra_irq_config_func_##index, \
279+
}; \
280+
\
281+
static struct lvd_renesas_ra_data lvd_renesas_ra_data_##index = { \
282+
.lvd_config = \
283+
{ \
284+
.monitor_number = DT_INST_PROP(index, channel), \
285+
.voltage_threshold = DT_INST_PROP(index, voltage_level), \
286+
.detection_response = LVD_RESPONSE_NONE, \
287+
.voltage_slope = DT_INST_ENUM_IDX(index, lvd_trigger), \
288+
.negation_delay = DT_INST_PROP(index, reset_negation_timing), \
289+
.sample_clock_divisor = DIGITAL_FILTER_GET(index), \
290+
.irq = IRQ_PARAMETER(index), \
291+
.monitor_ipl = IPL_PARAMETER(index), \
292+
.p_callback = ra_lvd_callback, \
293+
.p_context = (void *)DEVICE_DT_INST_GET(index), \
294+
.p_extend = NULL, \
295+
}, \
296+
.flags = ATOMIC_INIT(0), \
297+
.user_cb = NULL, \
298+
}; \
299+
\
300+
DEVICE_DT_INST_DEFINE(index, lvd_renesas_ra_init, NULL, &lvd_renesas_ra_data_##index, \
301+
&lvd_renesas_ra_config_##index, PRE_KERNEL_1, \
302+
CONFIG_COMPARATOR_INIT_PRIORITY, &lvd_renesas_ra_api);
303+
304+
DT_INST_FOREACH_STATUS_OKAY(LVD_RENESAS_RA_INIT)

0 commit comments

Comments
 (0)