Skip to content

Commit 729f3eb

Browse files
khoa-nguyen-18csarip
authored andcommitted
drivers: comparator: Initial Comparator support for Renesas RA
Initial Comparator driver support for Renesas RA Signed-off-by: Khoa Nguyen <khoa.nguyen.xh@renesas.com>
1 parent 5a74e41 commit 729f3eb

File tree

8 files changed

+470
-0
lines changed

8 files changed

+470
-0
lines changed

drivers/comparator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ zephyr_library_sources_ifdef(CONFIG_COMPARATOR_MCUX_ACMP comparator_mcux_acmp.c)
1212
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_COMP comparator_nrf_comp.c)
1313
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_LPCOMP comparator_nrf_lpcomp.c)
1414
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_SHELL comparator_shell.c)
15+
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_RENESAS_RA comparator_renesas_ra.c)

drivers/comparator/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ rsource "Kconfig.mcux_acmp"
2424
rsource "Kconfig.nrf_comp"
2525
rsource "Kconfig.nrf_lpcomp"
2626
rsource "Kconfig.shell"
27+
rsource "Kconfig.renesas_ra"
2728

2829
endif # COMPARATOR

drivers/comparator/Kconfig.renesas_ra

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_RA
5+
bool "Renesas RA ACMPHS"
6+
default y
7+
depends on DT_HAS_RENESAS_RA_ACMPHS_ENABLED
8+
select USE_RA_FSP_ACMPHS
9+
select PINCTRL
10+
help
11+
Enable Renesas RA ACMPHS Driver.
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
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_acmphs
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_acmphs.h"
17+
18+
LOG_MODULE_REGISTER(acmphs_renesas_ra, CONFIG_COMPARATOR_LOG_LEVEL);
19+
20+
#define ACMPHS_RENESAS_RA_FLAG_HS BIT(0)
21+
22+
void comp_hs_int_isr(void);
23+
24+
struct acmphs_renesas_ra_global_config {
25+
const struct pinctrl_dev_config *pcfg;
26+
};
27+
28+
struct acmphs_renesas_ra_config {
29+
const struct pinctrl_dev_config *pcfg;
30+
};
31+
32+
struct acmphs_renesas_ra_data {
33+
const struct device *dev;
34+
acmphs_instance_ctrl_t acmphs;
35+
comparator_cfg_t fsp_config;
36+
comparator_callback_t user_cb;
37+
void *user_cb_data;
38+
atomic_t flags;
39+
};
40+
41+
static int acmphs_renesas_get_output(const struct device *dev)
42+
{
43+
struct acmphs_renesas_ra_data *data = dev->data;
44+
comparator_status_t status;
45+
fsp_err_t fsp_err;
46+
47+
fsp_err = R_ACMPHS_StatusGet(&data->acmphs, &status);
48+
if (FSP_SUCCESS != fsp_err) {
49+
return -EIO;
50+
}
51+
52+
switch (status.state) {
53+
case COMPARATOR_STATE_OUTPUT_LOW:
54+
return 0;
55+
56+
case COMPARATOR_STATE_OUTPUT_HIGH:
57+
return 1;
58+
59+
case COMPARATOR_STATE_OUTPUT_DISABLED:
60+
LOG_ERR("Need to set trigger to open comparator first");
61+
return -EIO;
62+
}
63+
64+
return 0;
65+
}
66+
67+
static int acmphs_renesas_set_trigger(const struct device *dev, enum comparator_trigger trigger)
68+
{
69+
struct acmphs_renesas_ra_data *data = dev->data;
70+
71+
/* Disable interrupt */
72+
data->acmphs.p_reg->CMPCTL &= ~R_ACMPHS0_CMPCTL_CEG_Msk;
73+
74+
switch (trigger) {
75+
case COMPARATOR_TRIGGER_RISING_EDGE:
76+
data->fsp_config.trigger = COMPARATOR_TRIGGER_RISING;
77+
break;
78+
79+
case COMPARATOR_TRIGGER_FALLING_EDGE:
80+
data->fsp_config.trigger = COMPARATOR_TRIGGER_FALLING;
81+
break;
82+
83+
case COMPARATOR_TRIGGER_BOTH_EDGES:
84+
data->fsp_config.trigger = COMPARATOR_TRIGGER_BOTH_EDGE;
85+
break;
86+
87+
case COMPARATOR_TRIGGER_NONE:
88+
data->fsp_config.trigger = COMPARATOR_TRIGGER_NO_EDGE;
89+
break;
90+
}
91+
92+
data->acmphs.p_reg->CMPCTL |= (data->fsp_config.trigger << R_ACMPHS0_CMPCTL_CEG_Pos);
93+
94+
return 0;
95+
}
96+
97+
static int acmphs_renesas_set_trigger_callback(const struct device *dev,
98+
comparator_callback_t callback, void *user_data)
99+
{
100+
struct acmphs_renesas_ra_data *data = dev->data;
101+
102+
/* Disable interrupt */
103+
data->acmphs.p_reg->CMPCTL &= ~R_ACMPHS0_CMPCTL_CEG_Msk;
104+
105+
data->user_cb = callback;
106+
data->user_cb_data = user_data;
107+
108+
/* Enable interrupt */
109+
data->acmphs.p_reg->CMPCTL |= (data->fsp_config.trigger << R_ACMPHS0_CMPCTL_CEG_Pos);
110+
111+
return 0;
112+
}
113+
114+
static int acmphs_renesas_trigger_is_pending(const struct device *dev)
115+
{
116+
struct acmphs_renesas_ra_data *data = dev->data;
117+
118+
if (data->flags & ACMPHS_RENESAS_RA_FLAG_HS) {
119+
atomic_and(&data->flags, ~ACMPHS_RENESAS_RA_FLAG_HS);
120+
return 1;
121+
}
122+
123+
return 0;
124+
}
125+
126+
static void acmphs_renesas_ra_hs_isr(comparator_callback_args_t *fsp_args)
127+
{
128+
const struct device *dev = fsp_args->p_context;
129+
struct acmphs_renesas_ra_data *data = dev->data;
130+
comparator_callback_t cb = data->user_cb;
131+
132+
if (cb != NULL) {
133+
cb(dev, data->user_cb_data);
134+
return;
135+
}
136+
137+
atomic_or(&data->flags, ACMPHS_RENESAS_RA_FLAG_HS);
138+
}
139+
140+
static int acmphs_renesas_ra_global_init(const struct device *dev)
141+
{
142+
const struct acmphs_renesas_ra_global_config *cfg = dev->config;
143+
int ret;
144+
145+
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
146+
if (ret < 0) {
147+
LOG_DBG("pin VCOUT initial failed");
148+
return ret;
149+
}
150+
151+
return 0;
152+
}
153+
154+
static int acmphs_renesas_ra_init(const struct device *dev)
155+
{
156+
struct acmphs_renesas_ra_data *data = dev->data;
157+
const struct acmphs_renesas_ra_config *cfg = dev->config;
158+
fsp_err_t fsp_err;
159+
int ret;
160+
161+
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
162+
if (ret < 0) {
163+
LOG_DBG("pin default initial failed");
164+
return ret;
165+
}
166+
167+
data->fsp_config.p_context = dev;
168+
169+
fsp_err = R_ACMPHS_Open(&data->acmphs, &data->fsp_config);
170+
if (FSP_SUCCESS != fsp_err) {
171+
return -EIO;
172+
}
173+
174+
/*
175+
* Once the analog comparator is configurate, the program must wait
176+
* for the ACMPHS stabilization time (300ns enabling + 200ns input switching)
177+
* before using the comparator.
178+
*/
179+
k_usleep(5);
180+
181+
fsp_err = R_ACMPHS_OutputEnable(&data->acmphs);
182+
if (FSP_SUCCESS != fsp_err) {
183+
return -EIO;
184+
}
185+
186+
return 0;
187+
}
188+
189+
static DEVICE_API(comparator, acmphs_renesas_ra_api) = {
190+
.get_output = acmphs_renesas_get_output,
191+
.set_trigger = acmphs_renesas_set_trigger,
192+
.set_trigger_callback = acmphs_renesas_set_trigger_callback,
193+
.trigger_is_pending = acmphs_renesas_trigger_is_pending,
194+
};
195+
196+
PINCTRL_DT_DEFINE(DT_INST(0, renesas_ra_acmphs_global));
197+
198+
static const struct acmphs_renesas_ra_global_config acmphs_renesas_ra_global_config = {
199+
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST(0, renesas_ra_acmphs_global)),
200+
};
201+
202+
DEVICE_DT_DEFINE(DT_COMPAT_GET_ANY_STATUS_OKAY(renesas_ra_acmphs_global),
203+
acmphs_renesas_ra_global_init, NULL, NULL, &acmphs_renesas_ra_global_config,
204+
PRE_KERNEL_2, CONFIG_COMPARATOR_INIT_PRIORITY, NULL)
205+
206+
#define ACMPHS_RENESAS_RA_IRQ_INIT(idx) \
207+
{ \
208+
R_ICU->IELSR_b[DT_INST_IRQ_BY_NAME(idx, hs, irq)].IELS = \
209+
BSP_PRV_IELS_ENUM(CONCAT(EVENT_ACMPHS, DT_INST_PROP(idx, channel), _INT)); \
210+
\
211+
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, hs, irq), \
212+
DT_INST_IRQ_BY_NAME(idx, hs, priority), comp_hs_int_isr, \
213+
DEVICE_DT_INST_GET(idx), 0); \
214+
\
215+
irq_enable(DT_INST_IRQ_BY_NAME(idx, hs, irq)); \
216+
}
217+
218+
#define FILTER_PARAMETER(idx) \
219+
COND_CODE_1(IS_EQ(DT_INST_PROP(idx, noise_filter), 1), \
220+
(COMPARATOR_FILTER_OFF), (UTIL_CAT(COMPARATOR_FILTER_, DT_INST_PROP(idx, noise_filter))))
221+
222+
#define INVERT_PARAMETER(idx) \
223+
COND_CODE_1(DT_INST_PROP(idx, output_invert_polarity), \
224+
(COMPARATOR_POLARITY_INVERT_ON), (COMPARATOR_POLARITY_INVERT_OFF))
225+
226+
#define PIN_OUTPUT_PARAMETER(idx) \
227+
COND_CODE_1(DT_INST_PROP(idx, pin_output_enable), \
228+
(COMPARATOR_PIN_OUTPUT_ON), (COMPARATOR_PIN_OUTPUT_OFF))
229+
230+
#define IRQ_PARAMETER(idx) \
231+
COND_CODE_1(DT_INST_IRQ_HAS_NAME(idx, hs), \
232+
(DT_INST_IRQ_BY_NAME(idx, hs, irq)), (FSP_INVALID_VECTOR))
233+
234+
#define IPL_PARAMETER(idx) \
235+
COND_CODE_1(DT_INST_IRQ_HAS_NAME(idx, hs), \
236+
(DT_INST_IRQ_BY_NAME(idx, hs, priority)), (BSP_IRQ_DISABLED))
237+
238+
#define IRQ_INIT_MACRO_FUNCTION(idx) \
239+
COND_CODE_1(DT_INST_IRQ_HAS_NAME(idx, hs), (ACMPHS_RENESAS_RA_IRQ_INIT(idx);), ())
240+
241+
#define ACMPHS_RENESAS_RA_INIT(idx) \
242+
PINCTRL_DT_INST_DEFINE(idx); \
243+
static r_acmphs_extended_cfg_t g_acmphs_cfg_extend_##idx = { \
244+
.input_voltage = UTIL_CAT(ACMPHS_INPUT_, \
245+
DT_INST_STRING_UPPER_TOKEN(idx, compare_input_source)), \
246+
.reference_voltage = \
247+
UTIL_CAT(ACMPHS_REFERENCE_, \
248+
DT_INST_STRING_UPPER_TOKEN(idx, reference_input_source)), \
249+
.maximum_status_retries = 1024, \
250+
}; \
251+
static const struct acmphs_renesas_ra_config acmphs_renesas_ra_config_##idx = { \
252+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
253+
}; \
254+
static struct acmphs_renesas_ra_data acmphs_renesas_ra_data_##idx = { \
255+
.dev = DEVICE_DT_INST_GET(idx), \
256+
.fsp_config = \
257+
{ \
258+
.channel = DT_INST_PROP(idx, channel), \
259+
.mode = COMPARATOR_MODE_NORMAL, \
260+
.trigger = COMPARATOR_TRIGGER_NO_EDGE, \
261+
.filter = FILTER_PARAMETER(idx), \
262+
.invert = INVERT_PARAMETER(idx), \
263+
.pin_output = PIN_OUTPUT_PARAMETER(idx), \
264+
.p_extend = &g_acmphs_cfg_extend_##idx, \
265+
.irq = IRQ_PARAMETER(idx), \
266+
.ipl = IPL_PARAMETER(idx), \
267+
.p_callback = acmphs_renesas_ra_hs_isr, \
268+
}, \
269+
.flags = 0, \
270+
}; \
271+
static int acmphs_renesas_ra_init##idx(const struct device *dev) \
272+
{ \
273+
IRQ_INIT_MACRO_FUNCTION(idx) \
274+
return acmphs_renesas_ra_init(dev); \
275+
} \
276+
\
277+
DEVICE_DT_INST_DEFINE(idx, acmphs_renesas_ra_init##idx, NULL, \
278+
&acmphs_renesas_ra_data_##idx, &acmphs_renesas_ra_config_##idx, \
279+
POST_KERNEL, CONFIG_COMPARATOR_INIT_PRIORITY, \
280+
&acmphs_renesas_ra_api)
281+
282+
DT_INST_FOREACH_STATUS_OKAY(ACMPHS_RENESAS_RA_INIT);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright (c) 2025 Renesas Electronics Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
Renesas RA ACMPHS (High-Speed Analog COMParator) Global
6+
7+
The following example displays the minimum node layout:
8+
9+
acmphs_global: acmphs_global@deadbeef {
10+
compatible = "renesas,ra-acmphs-global";
11+
reg = <0xdeadbeef 0x200>;
12+
status = "disabled";
13+
14+
acmphs0: acmphs0 {
15+
...
16+
};
17+
};
18+
19+
If the pin-output-enable is selected in the comparator controller node,
20+
this global node needs to define the VCOUT pin to enable output on that pin.
21+
22+
Note: The VCOUT pinctrl for the comparator global node is already defined
23+
on each board that supported comparator. Please check the board’s pinctrl
24+
before defining it.
25+
26+
acmphs_vcout: acmphs_vcout {
27+
group1 {
28+
/* VCOUT */
29+
psels = <RA_PSEL(RA_PSEL_ACMPHS_VCOUT, ..., ...)>;
30+
};
31+
};
32+
33+
&acmphs_global {
34+
pinctrl-0 = <&acmphs_vcout>;
35+
pinctrl-names = "default";
36+
status = "okay";
37+
38+
acmphs0 {
39+
...
40+
};
41+
};
42+
43+
Note: There is only one VCOUT shared across all comparator controller nodes.
44+
Therefore, the VCOUT value is the logical OR of the output signals from all
45+
comparator controllers that have pin-output-enable enabled.
46+
47+
compatible: "renesas,ra-acmphs-global"
48+
49+
include: [base.yaml, pinctrl-device.yaml]

0 commit comments

Comments
 (0)