Skip to content

Commit a4b5f72

Browse files
committed
drivers: misc: lvd: Add support for LVD driver for RX130 series
Add the low-voltage detection driver support for RX130 series which run on LVDAb modules. The target is to monitor the voltage level input to Vcc/CMPA2 pin using a program Signed-off-by: Quy Tran <quy.tran.pz@renesas.com>
1 parent 0dd2807 commit a4b5f72

File tree

9 files changed

+387
-0
lines changed

9 files changed

+387
-0
lines changed

drivers/misc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher)
1212
add_subdirectory_ifdef(CONFIG_MCUX_FLEXIO mcux_flexio)
1313
add_subdirectory_ifdef(CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT renesas_ra_external_interrupt)
1414
add_subdirectory_ifdef(CONFIG_RENESAS_RX_EXTERNAL_INTERRUPT renesas_rx_external_interrupt)
15+
add_subdirectory_ifdef(CONFIG_RENESAS_RX_LVD renesas_rx_lvd)
1516
add_subdirectory_ifdef(CONFIG_NXP_RTXXX_DSP_CTRL nxp_rtxxx_dsp_ctrl)
1617
add_subdirectory_ifdef(CONFIG_STM32N6_AXISRAM stm32n6_axisram)
1718

drivers/misc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ source "drivers/misc/coresight/Kconfig"
1919
source "drivers/misc/interconn/Kconfig"
2020
source "drivers/misc/renesas_ra_external_interrupt/Kconfig"
2121
source "drivers/misc/renesas_rx_external_interrupt/Kconfig"
22+
source "drivers/misc/renesas_rx_lvd/Kconfig"
2223
source "drivers/misc/nxp_rtxxx_dsp_ctrl/Kconfig"
2324
source "drivers/misc/stm32n6_axisram/Kconfig"
2425

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_RX_LVD renesas_rx_lvd.c)

drivers/misc/renesas_rx_lvd/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2025 Renesas Electronics Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Renesas RX Voltage Detection Circuit
5+
6+
config RENESAS_RX_LVD
7+
bool "Renesas RX Low-Voltage Detection Driver"
8+
depends on DT_HAS_RENESAS_RX_LVD_ENABLED
9+
default y
10+
select USE_RX_RDP_LVD
11+
select PINCTRL
12+
help
13+
Enable Renesas RX low voltage detection driver
14+
15+
config RENESAS_RX_LVD_INIT_PRIORITY
16+
int "RX LVD initialization priority"
17+
default KERNEL_INIT_PRIORITY_DEVICE
18+
help
19+
System initialization priority for RX LVD driver.
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
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/kernel.h>
10+
#include <zephyr/devicetree.h>
11+
#include <zephyr/irq.h>
12+
#include <soc.h>
13+
#include <zephyr/logging/log.h>
14+
#include <zephyr/drivers/misc/renesas_lvd/renesas_rx_lvd.h>
15+
#include <zephyr/drivers/pinctrl.h>
16+
17+
LOG_MODULE_REGISTER(renesas_rx_lvd, CONFIG_SOC_LOG_LEVEL);
18+
19+
#define LVD0_NODE DT_NODELABEL(lvd0)
20+
#define LVD1_NODE DT_NODELABEL(lvd1)
21+
#define LVD_NO_FUNC ((void (*)(void *))NULL)
22+
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+
30+
struct rx_lvd_data {
31+
void (*callback)(void *args);
32+
void (*user_callback)(void *user_data);
33+
void *user_data;
34+
};
35+
36+
struct rx_lvd_config {
37+
lvd_channel_t channel;
38+
lvd_config_t lvd_config;
39+
uint8_t vdet_target;
40+
uint8_t lvd_action;
41+
bool lvd_support_cpma2;
42+
};
43+
44+
int renesas_rx_pin_set_cmpa2(const struct device *dev)
45+
{
46+
const struct rx_lvd_config *config = dev->config;
47+
const struct pinctrl_dev_config *pcfg;
48+
49+
if (config->channel == 0) {
50+
if (DT_NODE_HAS_PROP(LVD0_NODE, pinctrl_0)) {
51+
PINCTRL_DT_DEFINE(LVD0_NODE);
52+
pcfg = PINCTRL_DT_DEV_CONFIG_GET(LVD0_NODE);
53+
} else {
54+
LOG_ERR("No pinctrl-0 property found in the device tree");
55+
return -EINVAL;
56+
}
57+
} else {
58+
if (DT_NODE_HAS_PROP(LVD1_NODE, pinctrl_0)) {
59+
PINCTRL_DT_DEFINE(LVD1_NODE);
60+
pcfg = PINCTRL_DT_DEV_CONFIG_GET(LVD1_NODE);
61+
} else {
62+
LOG_ERR("No pinctrl_0 property found in the device tree");
63+
return -EINVAL;
64+
}
65+
}
66+
67+
/* In the case of monitoring the CMPA2 pin, set the CMPA2 pin. */
68+
/* This only applicable to channel 1 with the LVDb driver */
69+
int ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);
70+
71+
if (ret < 0) {
72+
LOG_ERR("Failed to apply pinctrl state: %d\n", ret);
73+
return -EINVAL;
74+
}
75+
76+
return 0;
77+
}
78+
79+
int renesas_rx_lvd_get_status(const struct device *dev, lvd_status_position_t *status_position,
80+
lvd_status_cross_t *status_cross)
81+
{
82+
const struct rx_lvd_config *config = dev->config;
83+
int ret;
84+
85+
ret = R_LVD_GetStatus(config->channel, status_position, status_cross);
86+
if (ret != 0) {
87+
LOG_ERR("Failed to get LVD status");
88+
return -EINVAL;
89+
}
90+
91+
return ret;
92+
}
93+
94+
int renesas_rx_lvd_clear_status(const struct device *dev)
95+
{
96+
const struct rx_lvd_config *config = dev->config;
97+
int ret;
98+
99+
ret = R_LVD_ClearStatus(config->channel);
100+
if (ret != 0) {
101+
LOG_ERR("Failed to clear LVD status");
102+
return -EINVAL;
103+
}
104+
105+
return ret;
106+
}
107+
108+
int renesas_rx_lvd_register_callback(const struct device *dev, void (*callback)(void *),
109+
void *user_data)
110+
{
111+
struct rx_lvd_data *data = dev->data;
112+
113+
data->user_callback = callback;
114+
data->user_data = user_data;
115+
116+
return 0;
117+
}
118+
119+
#define LVD_IRQ_CONNECT() \
120+
do { \
121+
IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(LVD0_NODE), ( \
122+
IRQ_CONNECT(DT_IRQN(LVD0_NODE), \
123+
DT_IRQ(LVD0_NODE, priority), \
124+
lvd_ch1_isr, \
125+
DEVICE_DT_GET(LVD0_NODE), \
126+
0); \
127+
irq_enable(DT_IRQN(LVD0_NODE)); \
128+
)) \
129+
IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(LVD1_NODE), ( \
130+
IRQ_CONNECT(DT_IRQN(LVD1_NODE), \
131+
DT_IRQ(LVD1_NODE, priority), \
132+
lvd_ch2_isr, \
133+
DEVICE_DT_GET(LVD1_NODE), \
134+
0); \
135+
irq_enable(DT_IRQN(LVD1_NODE)); \
136+
)) \
137+
} while (0)
138+
139+
static int renesas_rx_lvd_init(const struct device *dev)
140+
{
141+
lvd_err_t ret;
142+
143+
LVD_IRQ_CONNECT();
144+
145+
const struct rx_lvd_config *config = dev->config;
146+
const struct rx_lvd_data *data = dev->data;
147+
148+
/* In reset or no-action when LVD is detected, callback will not be triggered. */
149+
ret = R_LVD_Open(config->channel, &config->lvd_config, data->callback);
150+
if (ret != 0) {
151+
LOG_ERR("Failed to initialize LVD channel %d", config->channel);
152+
return -EIO;
153+
}
154+
155+
/* Set the CMPA2 pin if the target is CMPA2 */
156+
/* NOTE: For the RX130 series, CMPA2 is only used on channel 2. */
157+
if ((config->lvd_support_cpma2) && (config->vdet_target == 1)) {
158+
return renesas_rx_pin_set_cmpa2(dev);
159+
}
160+
161+
return 0;
162+
}
163+
164+
#define RENESAS_RX_LVD_INIT(index) \
165+
\
166+
static const struct rx_lvd_config rx_lvd_config_##index = { \
167+
.channel = DT_INST_PROP(index, channel), \
168+
.lvd_config = \
169+
{ \
170+
.trigger = DT_INST_PROP(index, lvd_trigger), \
171+
}, \
172+
.lvd_action = DT_INST_PROP(index, lvd_action), \
173+
.vdet_target = DT_INST_PROP(index, vdet_target), \
174+
.lvd_support_cpma2 = DT_INST_PROP(index, renesas_lvd_external_target), \
175+
}; \
176+
\
177+
void rx_lvd_callback_##index(void *args) \
178+
{ \
179+
ARG_UNUSED(args); \
180+
const struct device *dev = DEVICE_DT_GET(DT_INST(index, renesas_rx_lvd)); \
181+
struct rx_lvd_data *data = dev->data; \
182+
\
183+
/* Call the user's callback function*/ \
184+
if (data->user_callback) { \
185+
data->user_callback(data->user_data); \
186+
} \
187+
}; \
188+
\
189+
static struct rx_lvd_data rx_lvd_data_##index = { \
190+
.callback = rx_lvd_callback_##index, \
191+
}; \
192+
\
193+
static int renesas_rx_lvd_init_##index(const struct device *dev) \
194+
{ \
195+
int err = renesas_rx_lvd_init(dev); \
196+
if (err != 0) { \
197+
return err; \
198+
} \
199+
return 0; \
200+
} \
201+
\
202+
DEVICE_DT_INST_DEFINE(index, renesas_rx_lvd_init_##index, NULL, &rx_lvd_data_##index, \
203+
&rx_lvd_config_##index, PRE_KERNEL_1, \
204+
CONFIG_RENESAS_RX_LVD_INIT_PRIORITY, NULL);
205+
206+
DT_INST_FOREACH_STATUS_OKAY(RENESAS_RX_LVD_INIT)

dts/bindings/misc/renesas,rx-lvd.yaml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Copyright (c) 2025 Renesas Electronics Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Renesas RX LVD driver
5+
6+
compatible: "renesas,rx-lvd"
7+
8+
include: [base.yaml, pinctrl-device.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
channel:
15+
type: int
16+
description: RX LVD channel
17+
18+
lvd-action:
19+
required: true
20+
type: int
21+
enum: [0, 1, 2, 3]
22+
description: |
23+
Choose the action to be taken when the LVD is detected.
24+
- 0: Reset
25+
- 1: Non-maskable interrupt
26+
- 2: Maskable interrupt
27+
- 3: No action
28+
29+
voltage-level:
30+
required: true
31+
type: int
32+
description: |
33+
Specifies the voltage detection level for each channel, set an integer
34+
value which expresses the number up to two decimal places.
35+
Example:
36+
- To set the voltage detection level to 3.00 V, specify '300'.
37+
- To set the voltage detection level to default value, specify '0xFFFF'
38+
For specific voltage detection support levels of each RX MCU series,
39+
please refer to the HWM.
40+
41+
renesas,lvd-external-target:
42+
type: boolean
43+
description: |
44+
Specifies whether the RX LVD driver supports CMPA2 pin as target.
45+
Note: For RX130 series, CMPA2 pin is available only for channel 1.
46+
47+
vdet-target:
48+
required: true
49+
type: int
50+
enum: [0, 1]
51+
description: |
52+
Specifies the target to be monitored for each channel.
53+
Note: For RX130 series, CMPA2 pin is available only for channel 1.
54+
- 0: VCC
55+
- 1: CMPA2 pin
56+
57+
lvd-trigger:
58+
required: true
59+
type: int
60+
enum: [0, 1, 2]
61+
description: |
62+
Specifies the voltage detection conditions and influences interrupt conditions
63+
- 0: LVD_TRIGGER_RISE
64+
- 1: LVD_TRIGGER_FALL
65+
- 2: LVD_TRIGGER_BOTH
66+
67+
lvd-stabilization:
68+
type: int
69+
enum: [0, 1]
70+
description: |
71+
Specifies the reset negation timing for each channel, with reset selected as processing.
72+
- 0: After a LVD reset, negation occurs when a certain period elapses after the
73+
monitored voltage goes above the voltage detection level.
74+
- 1: Negation occurs when a certain period elapses after the LVD reset assertion.
75+
Note: "a certain period" here means a wait time after a voltage monitoring reset.
76+
Refer to the User's Manual: Hardware for details.
77+
78+
pinctrl-0:
79+
description: Pin control for LVD when using CMPA2 pin as target
80+
81+
pinctrl-names:
82+
description: Pin control names for LVD when using CMPA2 pin as target
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2025 Renesas Electronics Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_DRIVERS_MISC_RENESAS_RX_LVD_H_
8+
#define ZEPHYR_DRIVERS_MISC_RENESAS_RX_LVD_H_
9+
10+
#include "r_lvd_rx_if.h"
11+
12+
/**
13+
* @brief Get the current status of the LVD (Low Voltage Detection) circuit.
14+
*
15+
* This function retrieves the current voltage status from the LVD module,
16+
* including the position of the voltage level relative to the threshold,
17+
* and whether the voltage has crossed the threshold.
18+
* @param[in] dev LVD device instance.
19+
* @param[out] status_position Pointer to store the LVD status position.
20+
* @param[out] status_cross Pointer to store the LVD status cross.
21+
*
22+
* @retval 0 On success.
23+
* @retval -EINVAL On failure.
24+
*/
25+
int renesas_rx_lvd_get_status(const struct device *dev, lvd_status_position_t *status_position,
26+
lvd_status_cross_t *status_cross);
27+
28+
/**
29+
* @brief Clear the current status of the LVD (Low Voltage Detection) circuit.
30+
*
31+
* This function clears the current voltage status from the LVD module.
32+
* @param[in] dev LVD device instance.
33+
*
34+
* @retval 0 On success.
35+
* @retval -EINVAL On failure.
36+
*/
37+
int renesas_rx_lvd_clear_status(const struct device *dev);
38+
39+
/**
40+
* @brief Register a callback function for LVD status changes.
41+
*
42+
* This function registers a callback function that will be called when the
43+
* LVD status changes. This applicable only if the LVD action is set to
44+
* trigger an interrupt on status change.
45+
* @param[in] dev LVD device instance.
46+
* @param[in] callback Pointer to the callback function.
47+
* @param[in] user_data Pointer to user data that will be passed to the callback.
48+
*
49+
* @retval 0 On success.
50+
* @retval -EINVAL On failure.
51+
*/
52+
int renesas_rx_lvd_register_callback(const struct device *dev, void (*callback)(void *),
53+
void *user_data);
54+
55+
/**
56+
* @brief Set pin for CMPA2 if the target is CMPA2.
57+
*
58+
* This function sets the pin configuration for CMPA2 if the target
59+
* device is CMPA2.
60+
* @param[in] dev LVD device instance.
61+
*
62+
* @retval 0 On success.
63+
* @retval -EINVAL On failure.
64+
*/
65+
int renesas_rx_pin_set_cmpa2(const struct device *dev);
66+
67+
#endif /* ZEPHYR_DRIVERS_MISC_RENESAS_RX_LVD_H_ */

0 commit comments

Comments
 (0)