Skip to content
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

Drivers: comparator: silabs_acmp implementation #83980

Merged
2 changes: 2 additions & 0 deletions boards/silabs/dev_kits/xg24_dk2601b/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ The board configuration supports the following hardware features:
+-----------+------------+------------------------------------+
| RADIO | on-chip | bluetooth |
+-----------+------------+------------------------------------+
| ACMP | on-chip | comparator |
+-----------+------------+------------------------------------+

Other hardware features are currently not supported by the port.

Expand Down
1 change: 1 addition & 0 deletions boards/silabs/dev_kits/xg24_dk2601b/xg24_dk2601b.yaml
silabs-chgalant marked this conversation as resolved.
Show resolved Hide resolved
silabs-chgalant marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ supported:
- dma
- watchdog
- clock_control
- comparator
silabs-chgalant marked this conversation as resolved.
Show resolved Hide resolved
testing:
ignore_tags:
- pm
Expand Down
2 changes: 2 additions & 0 deletions boards/silabs/dev_kits/xg24_ek2703a/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ The ``xg24_ek2703a`` board supports the following hardware features:
+-----------+------------+-------------------------------------+
| RADIO | on-chip | bluetooth |
+-----------+------------+-------------------------------------+
| ACMP | on-chip | comparator |
+-----------+------------+-------------------------------------+

Other hardware features are currently not supported by the port.

Expand Down
1 change: 1 addition & 0 deletions boards/silabs/dev_kits/xg24_ek2703a/xg24_ek2703a.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ supported:
- uart
- watchdog
- clock_control
- comparator
testing:
ignore_tags:
- pm
Expand Down
2 changes: 2 additions & 0 deletions boards/silabs/dev_kits/xg27_dk2602a/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ The xg27_dk2602a board configuration supports the following hardware features:
+-----------+------------+-------------------------------------+
| DMA | on-chip | ldma |
+-----------+------------+-------------------------------------+
| ACMP | on-chip | comparator |
+-----------+------------+-------------------------------------+

Flashing
========
Expand Down
1 change: 1 addition & 0 deletions boards/silabs/dev_kits/xg27_dk2602a/xg27_dk2602a.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ supported:
- uart
- dma
- clock_control
- comparator
vendor: silabs
2 changes: 2 additions & 0 deletions boards/silabs/radio_boards/xg23_rb4210a/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ The board configuration supports the following hardware features:
+-----------+------------+-------------------------------------+
| WATCHDOG | on-chip | watchdog |
+-----------+------------+-------------------------------------+
| ACMP | on-chip | comparator |
+-----------+------------+-------------------------------------+

Other hardware features are currently not supported by the port.

Expand Down
1 change: 1 addition & 0 deletions boards/silabs/radio_boards/xg23_rb4210a/xg23_rb4210a.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ supported:
- uart
- dma
- watchdog
- comparator
testing:
ignore_tags:
- pm
Expand Down
2 changes: 2 additions & 0 deletions boards/silabs/radio_boards/xg24_rb4187c/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ The board configuration supports the following hardware features:
+-----------+------------+-------------------------------------+
| WATCHDOG | on-chip | watchdog |
+-----------+------------+-------------------------------------+
| ACMP | on-chip | comparator |
+-----------+------------+-------------------------------------+

Other hardware features are currently not supported by the port.

Expand Down
1 change: 1 addition & 0 deletions boards/silabs/radio_boards/xg24_rb4187c/xg24_rb4187c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ supported:
- uart
- dma
- watchdog
- comparator
testing:
ignore_tags:
- pm
Expand Down
2 changes: 2 additions & 0 deletions boards/silabs/radio_boards/xg29_rb4412a/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ The ``xg29_rb4412a`` board target supports the following hardware features:
+-----------+------------+------------------------+
| RADIO | on-chip | bluetooth |
+-----------+------------+------------------------+
| ACMP | on-chip | comparator |
+-----------+------------+------------------------+

Programming and Debugging
*************************
Expand Down
1 change: 1 addition & 0 deletions boards/silabs/radio_boards/xg29_rb4412a/xg29_rb4412a.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ supported:
- uart
- dma
- watchdog
- comparator
testing:
ignore_tags:
- pm
Expand Down
1 change: 1 addition & 0 deletions drivers/comparator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/comparator.h)
zephyr_library()

zephyr_library_sources_ifdef(CONFIG_USERSPACE comparator_handlers.c)
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_SILABS_ACMP comparator_silabs_acmp.c)
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_FAKE_COMP comparator_fake_comp.c)
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_MCUX_ACMP comparator_mcux_acmp.c)
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_COMP comparator_nrf_comp.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/comparator/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ config COMPARATOR_INIT_PRIORITY
Comparator device driver initialization priority.

rsource "Kconfig.fake_comp"
rsource "Kconfig.silabs_acmp"
rsource "Kconfig.mcux_acmp"
rsource "Kconfig.nrf_comp"
rsource "Kconfig.nrf_lpcomp"
Expand Down
12 changes: 12 additions & 0 deletions drivers/comparator/Kconfig.silabs_acmp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) 2025 Silicon Laboratories Inc.
# SPDX-License-Identifier: Apache-2.0
config COMPARATOR_SILABS_ACMP
bool "Silabs ACMP comparator driver"
default y
depends on DT_HAS_SILABS_ACMP_ENABLED
select PINCTRL
select SOC_SILABS_ACMP
silabs-chgalant marked this conversation as resolved.
Show resolved Hide resolved
help
Enable the comparator driver for the Analog Comparator hardware block
present on Silicon Labs devices. This block is commonly used to
monitor the power supply.
203 changes: 203 additions & 0 deletions drivers/comparator/comparator_silabs_acmp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* Copyright (c) 2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <em_device.h>
#include <em_acmp.h>
#include <zephyr/device.h>
#include <zephyr/drivers/comparator.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/clock_control_silabs.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/irq.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(silabs_acmp, CONFIG_COMPARATOR_LOG_LEVEL);

#define DT_DRV_COMPAT silabs_acmp

struct acmp_config {
ACMP_TypeDef *base;
const struct pinctrl_dev_config *pincfg;
const struct device *clock_dev;
const struct silabs_clock_control_cmu_config clock_cfg;
void (*irq_init)(void);
ACMP_Init_TypeDef init;
int input_negative;
int input_positive;
};

struct acmp_data {
uint32_t interrupt_mask;
comparator_callback_t callback;
void *user_data;
};

static int acmp_init(const struct device *dev)
{
int err;
const struct acmp_config *config = dev->config;

/* Enable ACMP Clock */
err = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->clock_cfg);
if (err < 0) {
return err;
}

err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
if (err < 0 && err != -ENOENT) {
LOG_ERR("failed to allocate silabs,analog-bus via pinctrl");
return err;
}

/* Initialize the ACMP */
ACMP_Init(config->base, &config->init);

/* Configure the ACMP Input Channels */
ACMP_ChannelSet(config->base, config->input_negative, config->input_positive);

/* Initialize the irq handler */
config->irq_init();

return 0;
}

static int acmp_get_output(const struct device *dev)
{
const struct acmp_config *config = dev->config;

return config->base->STATUS & ACMP_STATUS_ACMPOUT;
}

static int acmp_set_trigger(const struct device *dev, enum comparator_trigger trigger)
{
const struct acmp_config *config = dev->config;
struct acmp_data *data = dev->data;

/* Disable ACMP trigger interrupts */
ACMP_IntDisable(config->base, ACMP_IEN_RISE | ACMP_IEN_FALL);

/* Clear ACMP trigger interrupt flags */
ACMP_IntClear(config->base, ACMP_IEN_RISE | ACMP_IEN_FALL);

switch (trigger) {
case COMPARATOR_TRIGGER_BOTH_EDGES:
data->interrupt_mask = ACMP_IEN_RISE | ACMP_IEN_FALL;
silabs-chgalant marked this conversation as resolved.
Show resolved Hide resolved
break;
case COMPARATOR_TRIGGER_RISING_EDGE:
data->interrupt_mask = ACMP_IEN_RISE;
break;
case COMPARATOR_TRIGGER_FALLING_EDGE:
data->interrupt_mask = ACMP_IEN_FALL;
break;
case COMPARATOR_TRIGGER_NONE:
data->interrupt_mask = 0;
break;
default:
return -EINVAL;
}

/* Only enable interrupts when the trigger is not none and if a
* callback is set.
*/
if (data->interrupt_mask && data->callback != NULL) {
ACMP_IntEnable(config->base, data->interrupt_mask);
}

return 0;
}

static int acmp_set_trigger_callback(const struct device *dev, comparator_callback_t callback,
void *user_data)
{
const struct acmp_config *config = dev->config;
struct acmp_data *data = dev->data;

/* Disable ACMP trigger interrupts while setting callback */
ACMP_IntDisable(config->base, ACMP_IEN_RISE | ACMP_IEN_FALL);

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

if (data->callback == NULL) {
return 0;
}

/* Re-enable currently set ACMP trigger interrupts */
if (data->interrupt_mask) {
ACMP_IntEnable(config->base, data->interrupt_mask);
}

return 0;
}

static int acmp_trigger_is_pending(const struct device *dev)
{
const struct acmp_config *config = dev->config;
const struct acmp_data *data = dev->data;

if (ACMP_IntGet(config->base) & data->interrupt_mask) {
ACMP_IntClear(config->base, data->interrupt_mask);
return 1;
}

return 0;
}

static void acmp_irq_handler(const struct device *dev)
{
const struct acmp_config *config = dev->config;
struct acmp_data *data = dev->data;

ACMP_IntClear(config->base, ACMP_IF_RISE | ACMP_IF_FALL);

if (data->callback == NULL) {
return;
}

data->callback(dev, data->user_data);
}

static DEVICE_API(comparator, acmp_api) = {
.get_output = acmp_get_output,
.set_trigger = acmp_set_trigger,
.set_trigger_callback = acmp_set_trigger_callback,
.trigger_is_pending = acmp_trigger_is_pending,
};

#define ACMP_DEVICE(inst) \
PINCTRL_DT_INST_DEFINE(inst); \
\
static void acmp_irq_init##inst(void) \
{ \
IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), acmp_irq_handler, \
DEVICE_DT_INST_GET(inst), 0); \
\
irq_enable(DT_INST_IRQN(inst)); \
} \
\
static struct acmp_data acmp_data##inst; \
\
static const struct acmp_config acmp_config##inst = { \
.base = (ACMP_TypeDef *)DT_INST_REG_ADDR(inst), \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
.clock_cfg = SILABS_DT_INST_CLOCK_CFG(inst), \
.irq_init = acmp_irq_init##inst, \
.init.biasProg = DT_INST_PROP(inst, bias), \
.init.inputRange = DT_INST_ENUM_IDX(inst, input_range), \
.init.accuracy = DT_INST_ENUM_IDX(inst, accuracy_mode), \
.init.hysteresisLevel = DT_INST_ENUM_IDX(inst, hysteresis_mode), \
.init.inactiveValue = false, \
.init.vrefDiv = DT_INST_PROP(inst, vref_divider), \
.init.enable = true, \
.input_negative = DT_INST_PROP(inst, input_negative), \
.input_positive = DT_INST_PROP(inst, input_positive), \
}; \
silabs-chgalant marked this conversation as resolved.
Show resolved Hide resolved
\
DEVICE_DT_INST_DEFINE(inst, acmp_init, NULL, &acmp_data##inst, &acmp_config##inst, \
POST_KERNEL, CONFIG_COMPARATOR_INIT_PRIORITY, &acmp_api);

DT_INST_FOREACH_STATUS_OKAY(ACMP_DEVICE)
7 changes: 7 additions & 0 deletions dts/arm/silabs/efr32bg27.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
reg = <0x5003c460 0x4>;
clock-frequency = <DT_FREQ_M(38)>;
};
acmp0: acmp@5a008000 {
compatible = "silabs,acmp";
reg = <0x5a008000 0x4000>;
interrupts = <48 0>;
clocks = <&cmu CLOCK_ACMP0 CLOCK_BRANCH_EM01GRPACLK>;
status = "disabled";
};
};
};

Expand Down
8 changes: 8 additions & 0 deletions dts/arm/silabs/efr32mg21.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,14 @@
clocks = <&cmu CLOCK_AUTO CLOCK_BRANCH_WDOG1CLK>;
status = "disabled";
};

acmp0: acmp@0x5a008000 {
compatible = "silabs,acmp";
reg = <0x5a008000 0x4000>;
interrupts = <41 0>;
clocks = <&cmu CLOCK_AUTO CLOCK_BRANCH_EM01GRPACLK>;
status = "disabled";
};
};
};

Expand Down
8 changes: 8 additions & 0 deletions dts/arm/silabs/efr32mg24.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,14 @@
interrupts = <53 0>;
status = "disabled";
};

acmp0: acmp@59008000 {
compatible = "silabs,acmp";
reg = <0x59008000 0x4000>;
interrupts = <40 0>;
clocks = <&cmu CLOCK_ACMP0 CLOCK_BRANCH_EM01GRPACLK>;
status = "disabled";
};
};


Expand Down
8 changes: 8 additions & 0 deletions dts/arm/silabs/efr32xg23.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,14 @@
interrupts = <54 0>;
status = "disabled";
};

acmp0: acmp@59008000 {
compatible = "silabs,acmp";
reg = <0x59008000 0x4000>;
interrupts = <41 0>;
clocks = <&cmu CLOCK_ACMP0 CLOCK_BRANCH_EM01GRPACLK>;
status = "disabled";
};
};

hwinfo: hwinfo {
Expand Down
Loading
Loading