Skip to content

drivers: misc: Add Low-voltage detection (LVD) driver support for RX130 #93694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher)
add_subdirectory_ifdef(CONFIG_MCUX_FLEXIO mcux_flexio)
add_subdirectory_ifdef(CONFIG_RENESAS_RA_EXTERNAL_INTERRUPT renesas_ra_external_interrupt)
add_subdirectory_ifdef(CONFIG_RENESAS_RX_EXTERNAL_INTERRUPT renesas_rx_external_interrupt)
add_subdirectory_ifdef(CONFIG_RENESAS_RX_LVD renesas_rx_lvd)
add_subdirectory_ifdef(CONFIG_NXP_RTXXX_DSP_CTRL nxp_rtxxx_dsp_ctrl)
add_subdirectory_ifdef(CONFIG_STM32N6_AXISRAM stm32n6_axisram)

Expand Down
1 change: 1 addition & 0 deletions drivers/misc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ source "drivers/misc/coresight/Kconfig"
source "drivers/misc/interconn/Kconfig"
source "drivers/misc/renesas_ra_external_interrupt/Kconfig"
source "drivers/misc/renesas_rx_external_interrupt/Kconfig"
source "drivers/misc/renesas_rx_lvd/Kconfig"
source "drivers/misc/nxp_rtxxx_dsp_ctrl/Kconfig"
source "drivers/misc/stm32n6_axisram/Kconfig"

Expand Down
5 changes: 5 additions & 0 deletions drivers/misc/renesas_rx_lvd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources_ifdef(CONFIG_RENESAS_RX_LVD renesas_rx_lvd.c)
19 changes: 19 additions & 0 deletions drivers/misc/renesas_rx_lvd/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0

# Renesas RX Voltage Detection Circuit

config RENESAS_RX_LVD
bool "Renesas RX Low-Voltage Detection Driver"
depends on DT_HAS_RENESAS_RX_LVD_ENABLED
default y
select USE_RX_RDP_LVD
select PINCTRL
help
Enable Renesas RX low voltage detection driver

config RENESAS_RX_LVD_INIT_PRIORITY
int "RX LVD initialization priority"
default KERNEL_INIT_PRIORITY_DEVICE
help
System initialization priority for RX LVD driver.
206 changes: 206 additions & 0 deletions drivers/misc/renesas_rx_lvd/renesas_rx_lvd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT renesas_rx_lvd

#include <zephyr/kernel.h>
#include <zephyr/devicetree.h>
#include <zephyr/irq.h>
#include <soc.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/misc/renesas_rx_lvd/renesas_rx_lvd.h>
#include <zephyr/drivers/pinctrl.h>

LOG_MODULE_REGISTER(renesas_rx_lvd, CONFIG_SOC_LOG_LEVEL);

#define LVD0_NODE DT_NODELABEL(lvd0)
#define LVD1_NODE DT_NODELABEL(lvd1)
#define LVD_NO_FUNC ((void (*)(void *))NULL)

/*
* The extern functions below are implemented in the r_lvd_rx_hw.c source file.
* For more information, please refer to r_lvd_rx_hw.c in HAL Renesas
*/
extern void lvd_ch1_isr(void);
extern void lvd_ch2_isr(void);

struct rx_lvd_data {
void (*callback)(void *args);
void (*user_callback)(void *user_data);
void *user_data;
};

struct rx_lvd_config {
lvd_channel_t channel;
lvd_config_t lvd_config;
uint8_t vdet_target;
uint8_t lvd_action;
bool lvd_support_cpma2;
};

int renesas_rx_pin_set_cmpa2(const struct device *dev)
{
const struct rx_lvd_config *config = dev->config;
const struct pinctrl_dev_config *pcfg;

if (config->channel == 0) {
if (DT_NODE_HAS_PROP(LVD0_NODE, pinctrl_0)) {
PINCTRL_DT_DEFINE(LVD0_NODE);
pcfg = PINCTRL_DT_DEV_CONFIG_GET(LVD0_NODE);
} else {
LOG_ERR("No pinctrl-0 property found in the device tree");
return -EINVAL;
}
} else {
if (DT_NODE_HAS_PROP(LVD1_NODE, pinctrl_0)) {
PINCTRL_DT_DEFINE(LVD1_NODE);
pcfg = PINCTRL_DT_DEV_CONFIG_GET(LVD1_NODE);
} else {
LOG_ERR("No pinctrl_0 property found in the device tree");
return -EINVAL;
}
}

/* In the case of monitoring the CMPA2 pin, set the CMPA2 pin. */
/* This only applicable to channel 1 with the LVDb driver */
int ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);

if (ret < 0) {
LOG_ERR("Failed to apply pinctrl state: %d\n", ret);
return -EINVAL;
}

return 0;
}

int renesas_rx_lvd_get_status(const struct device *dev, lvd_status_position_t *status_position,
lvd_status_cross_t *status_cross)
{
const struct rx_lvd_config *config = dev->config;
int ret;

ret = R_LVD_GetStatus(config->channel, status_position, status_cross);
if (ret != 0) {
LOG_ERR("Failed to get LVD status");
return -EINVAL;
}

return ret;
}

int renesas_rx_lvd_clear_status(const struct device *dev)
{
const struct rx_lvd_config *config = dev->config;
int ret;

ret = R_LVD_ClearStatus(config->channel);
if (ret != 0) {
LOG_ERR("Failed to clear LVD status");
return -EINVAL;
}

return ret;
}

int renesas_rx_lvd_register_callback(const struct device *dev, void (*callback)(void *),
void *user_data)
{
struct rx_lvd_data *data = dev->data;

data->user_callback = callback;
data->user_data = user_data;

return 0;
}

#define LVD_IRQ_CONNECT() \
do { \
IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(LVD0_NODE), ( \
IRQ_CONNECT(DT_IRQN(LVD0_NODE), \
DT_IRQ(LVD0_NODE, priority), \
lvd_ch1_isr, \
DEVICE_DT_GET(LVD0_NODE), \
0); \
irq_enable(DT_IRQN(LVD0_NODE)); \
)) \
IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(LVD1_NODE), ( \
IRQ_CONNECT(DT_IRQN(LVD1_NODE), \
DT_IRQ(LVD1_NODE, priority), \
lvd_ch2_isr, \
DEVICE_DT_GET(LVD1_NODE), \
0); \
irq_enable(DT_IRQN(LVD1_NODE)); \
)) \
} while (0)

static int renesas_rx_lvd_init(const struct device *dev)
{
lvd_err_t ret;

LVD_IRQ_CONNECT();

const struct rx_lvd_config *config = dev->config;
const struct rx_lvd_data *data = dev->data;

/* In reset or no-action when LVD is detected, callback will not be triggered. */
ret = R_LVD_Open(config->channel, &config->lvd_config, data->callback);
if (ret != 0) {
LOG_ERR("Failed to initialize LVD channel %d", config->channel);
return -EIO;
}

/* Set the CMPA2 pin if the target is CMPA2 */
/* NOTE: For the RX130 series, CMPA2 is only used on channel 2. */
if ((config->lvd_support_cpma2) && (config->vdet_target == 1)) {
return renesas_rx_pin_set_cmpa2(dev);
}

return 0;
}

#define RENESAS_RX_LVD_INIT(index) \
\
static const struct rx_lvd_config rx_lvd_config_##index = { \
.channel = DT_INST_PROP(index, channel), \
.lvd_config = \
{ \
.trigger = DT_INST_PROP(index, lvd_trigger), \
}, \
.lvd_action = DT_INST_PROP(index, lvd_action), \
.vdet_target = DT_INST_PROP(index, vdet_target), \
.lvd_support_cpma2 = DT_INST_PROP(index, renesas_lvd_external_target), \
}; \
\
void rx_lvd_callback_##index(void *args) \
{ \
ARG_UNUSED(args); \
const struct device *dev = DEVICE_DT_GET(DT_INST(index, renesas_rx_lvd)); \
struct rx_lvd_data *data = dev->data; \
\
/* Call the user's callback function*/ \
if (data->user_callback) { \
data->user_callback(data->user_data); \
} \
}; \
\
static struct rx_lvd_data rx_lvd_data_##index = { \
.callback = rx_lvd_callback_##index, \
}; \
\
static int renesas_rx_lvd_init_##index(const struct device *dev) \
{ \
int err = renesas_rx_lvd_init(dev); \
if (err != 0) { \
return err; \
} \
return 0; \
} \
\
DEVICE_DT_INST_DEFINE(index, renesas_rx_lvd_init_##index, NULL, &rx_lvd_data_##index, \
&rx_lvd_config_##index, PRE_KERNEL_1, \
CONFIG_RENESAS_RX_LVD_INIT_PRIORITY, NULL);

DT_INST_FOREACH_STATUS_OKAY(RENESAS_RX_LVD_INIT)
82 changes: 82 additions & 0 deletions dts/bindings/misc/renesas,rx-lvd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright (c) 2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0

description: Renesas RX LVD driver

compatible: "renesas,rx-lvd"

include: [base.yaml, pinctrl-device.yaml]

properties:
reg:
required: true

channel:
type: int
description: RX LVD channel

lvd-action:
required: true
type: int
enum: [0, 1, 2, 3]
description: |
Choose the action to be taken when the LVD is detected.
- 0: Reset
- 1: Non-maskable interrupt
- 2: Maskable interrupt
- 3: No action

voltage-level:
required: true
type: int
description: |
Specifies the voltage detection level for each channel, set an integer
value which expresses the number up to two decimal places.
Example:
- To set the voltage detection level to 3.00 V, specify '300'.
- To set the voltage detection level to default value, specify '0xFFFF'
For specific voltage detection support levels of each RX MCU series,
please refer to the HWM.

renesas,lvd-external-target:
type: boolean
description: |
Specifies whether the RX LVD driver supports CMPA2 pin as target.
Note: For RX130 series, CMPA2 pin is available only for channel 1.

vdet-target:
required: true
type: int
enum: [0, 1]
description: |
Specifies the target to be monitored for each channel.
Note: For RX130 series, CMPA2 pin is available only for channel 1.
- 0: VCC
- 1: CMPA2 pin

lvd-trigger:
required: true
type: int
enum: [0, 1, 2]
description: |
Specifies the voltage detection conditions and influences interrupt conditions
- 0: LVD_TRIGGER_RISE
- 1: LVD_TRIGGER_FALL
- 2: LVD_TRIGGER_BOTH

lvd-stabilization:
type: int
enum: [0, 1]
description: |
Specifies the reset negation timing for each channel, with reset selected as processing.
- 0: After a LVD reset, negation occurs when a certain period elapses after the
monitored voltage goes above the voltage detection level.
- 1: Negation occurs when a certain period elapses after the LVD reset assertion.
Note: "a certain period" here means a wait time after a voltage monitoring reset.
Refer to the User's Manual: Hardware for details.

pinctrl-0:
description: Pin control for LVD when using CMPA2 pin as target

pinctrl-names:
description: Pin control names for LVD when using CMPA2 pin as target
19 changes: 19 additions & 0 deletions dts/rx/renesas/rx130-common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,25 @@
status = "disabled";
};

lvd0: lvd@800e0 {
compatible = "renesas,rx-lvd";
reg = <0x000800E0 0x02>;
channel = <0>;
interrupts = <88 1>;
interrupt-names = "lvd";
status = "disabled";
};

lvd1: lvd@800e2 {
compatible = "renesas,rx-lvd";
reg = <0x000800E2 0x02>;
channel = <1>;
interrupts = <89 1>;
interrupt-names = "lvd";
renesas,lvd-external-target;
status = "disabled";
};

ofsm: ofsm@ffffff80 {
compatible = "zephyr,memory-region";
reg = <0xFFFFFF80 0x0F>;
Expand Down
Loading
Loading