diff --git a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi index 306da273f3c16..d3ba959c8abec 100644 --- a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi +++ b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi @@ -135,4 +135,12 @@ nxp,analog-mode; }; }; + + pinmux_hscmp0: pinmux_hscmp0 { + group0 { + pinmux = ; + slew-rate = "standard"; + nxp,analog-mode; + }; + }; }; diff --git a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts index 46da74e55e310..605286d746f5b 100644 --- a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts +++ b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts @@ -214,3 +214,9 @@ zephyr_udc0: &usbfs { pinctrl-0 = <&pinmux_opamp0>; pinctrl-names = "default"; }; + +&hscmp0 { + status = "okay"; + pinctrl-0 = <&pinmux_hscmp0>; + pinctrl-names = "default"; +}; diff --git a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.yaml b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.yaml index 68c9e00555b0a..1cbf188bbf4c3 100644 --- a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.yaml +++ b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.yaml @@ -23,4 +23,5 @@ supported: - pwm - usb_device - usbd + - comparator vendor: nxp diff --git a/drivers/clock_control/clock_control_mcux_syscon.c b/drivers/clock_control/clock_control_mcux_syscon.c index 464e194576599..62817337dab92 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -176,6 +176,24 @@ static int mcux_lpc_syscon_clock_control_on(const struct device *dev, } #endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hscmp0)) + if ((uint32_t)sub_system == MCUX_HSCMP0_CLK) { + CLOCK_EnableClock(kCLOCK_Hscmp0); + } +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hscmp1)) + if ((uint32_t)sub_system == MCUX_HSCMP1_CLK) { + CLOCK_EnableClock(kCLOCK_Hscmp1); + } +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hscmp2)) + if ((uint32_t)sub_system == MCUX_HSCMP2_CLK) { + CLOCK_EnableClock(kCLOCK_Hscmp2); + } +#endif + #ifdef CONFIG_SOC_FAMILY_MCXN #if DT_NODE_HAS_STATUS(DT_NODELABEL(trng), okay) if ((uint32_t)sub_system == MCUX_ELS_CLK) { diff --git a/drivers/comparator/CMakeLists.txt b/drivers/comparator/CMakeLists.txt index a2a2ed31b476f..6802cc894c830 100644 --- a/drivers/comparator/CMakeLists.txt +++ b/drivers/comparator/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_COMPARATOR_MCUX_ACMP comparator_mcux_acmp.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_COMP comparator_nrf_comp.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_LPCOMP comparator_nrf_lpcomp.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NXP_CMP comparator_nxp_cmp.c) +zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NXP_HSCMP comparator_nxp_hscmp.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_RENESAS_RA comparator_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_RENESAS_RA_LVD comparator_renesas_ra_lvd.c) zephyr_library_sources_ifdef(CONFIG_COMPARATOR_RENESAS_RX_LVD comparator_renesas_rx_lvd.c) diff --git a/drivers/comparator/Kconfig b/drivers/comparator/Kconfig index c2e6d7ca9a55b..2069bcde171ea 100644 --- a/drivers/comparator/Kconfig +++ b/drivers/comparator/Kconfig @@ -26,6 +26,7 @@ rsource "Kconfig.mcux_acmp" rsource "Kconfig.nrf_comp" rsource "Kconfig.nrf_lpcomp" rsource "Kconfig.nxp_cmp" +rsource "Kconfig.nxp_hscmp" rsource "Kconfig.renesas_ra" rsource "Kconfig.renesas_rx" rsource "Kconfig.shell" diff --git a/drivers/comparator/Kconfig.nxp_hscmp b/drivers/comparator/Kconfig.nxp_hscmp new file mode 100644 index 0000000000000..d1780cad39389 --- /dev/null +++ b/drivers/comparator/Kconfig.nxp_hscmp @@ -0,0 +1,11 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config COMPARATOR_NXP_HSCMP + bool "NXP HSCMP comparator driver" + default y + depends on DT_HAS_NXP_HSCMP_ENABLED + select PINCTRL + select CLOCK_CONTROL + select RESET + select REGULATOR diff --git a/drivers/comparator/comparator_nxp_hscmp.c b/drivers/comparator/comparator_nxp_hscmp.c new file mode 100644 index 0000000000000..5587c1548b25f --- /dev/null +++ b/drivers/comparator/comparator_nxp_hscmp.c @@ -0,0 +1,367 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(nxp_hscmp, CONFIG_COMPARATOR_LOG_LEVEL); + +#define DT_DRV_COMPAT nxp_hscmp + +struct nxp_hscmp_config { + HSCMP_Type *base; + bool enable_stop_mode; + bool invert_output; + bool enable_pin_out; + bool use_unfiltered_output; + bool positive_mux_is_dac; + bool negative_mux_is_dac; + uint8_t filter_count; + uint8_t filter_period; + uint8_t positive_mux_input; + uint8_t negative_mux_input; + uint8_t dac_value; + uint8_t dac_vref_source; + uint8_t hysteresis_mode; + uint8_t power_mode; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + struct reset_dt_spec reset; + void (*irq_config_func)(const struct device *dev); + const struct pinctrl_dev_config *pcfg; + const struct device *ref_supplies; + int32_t ref_supply_val; +}; + +struct nxp_hscmp_data { + uint8_t interrupt_mask; + comparator_callback_t callback; + void *user_data; +}; + +static int nxp_hscmp_get_output(const struct device *dev) +{ + const struct nxp_hscmp_config *config = dev->config; + + return (config->base->CSR & HSCMP_CSR_COUT_MASK) ? 1 : 0; +} + +static int nxp_hscmp_set_trigger(const struct device *dev, + enum comparator_trigger trigger) +{ + const struct nxp_hscmp_config *config = dev->config; + struct nxp_hscmp_data *data = dev->data; + + config->base->IER &= ~(HSCMP_IER_CFR_IE_MASK | HSCMP_IER_CFF_IE_MASK); + data->interrupt_mask = 0U; + + switch (trigger) { + case COMPARATOR_TRIGGER_NONE: + break; + case COMPARATOR_TRIGGER_RISING_EDGE: + data->interrupt_mask = HSCMP_IER_CFR_IE_MASK; + break; + case COMPARATOR_TRIGGER_FALLING_EDGE: + data->interrupt_mask = HSCMP_IER_CFF_IE_MASK; + break; + case COMPARATOR_TRIGGER_BOTH_EDGES: + data->interrupt_mask = HSCMP_IER_CFR_IE_MASK | HSCMP_IER_CFF_IE_MASK; + break; + default: + LOG_ERR("Invalid trigger type."); + return -EINVAL; + } + + /* Clear latched status flags before enabling interrupts. */ + config->base->CSR |= (HSCMP_CSR_CFF_MASK | HSCMP_CSR_CFR_MASK); + + if ((data->interrupt_mask != 0U) && (data->callback != NULL)) { + config->base->IER |= data->interrupt_mask; + } + + return 0; +} + +static int nxp_hscmp_trigger_is_pending(const struct device *dev) +{ + const struct nxp_hscmp_config *config = dev->config; + struct nxp_hscmp_data *data = dev->data; + uint32_t status_flags; + + status_flags = config->base->CSR & (HSCMP_CSR_CFF_MASK | HSCMP_CSR_CFR_MASK); + config->base->CSR |= (HSCMP_CSR_CFF_MASK | HSCMP_CSR_CFR_MASK); + + if (((data->interrupt_mask & HSCMP_IER_CFF_IE_MASK) != 0U) && + ((status_flags & HSCMP_CSR_CFF_MASK) != 0U)) { + return 1; + } + + if (((data->interrupt_mask & HSCMP_IER_CFR_IE_MASK) != 0U) && + ((status_flags & HSCMP_CSR_CFR_MASK) != 0U)) { + return 1; + } + + return 0; +} + +static int nxp_hscmp_set_trigger_callback(const struct device *dev, + comparator_callback_t callback, + void *user_data) +{ + const struct nxp_hscmp_config *config = dev->config; + struct nxp_hscmp_data *data = dev->data; + + config->base->CCR0 &= ~HSCMP_CCR0_CMP_EN_MASK; + + data->callback = callback; + data->user_data = user_data; + + /* Clear any pending flags when (re)arming the callback. */ + config->base->CSR |= (HSCMP_CSR_CFF_MASK | HSCMP_CSR_CFR_MASK); + + if ((data->callback != NULL) && (data->interrupt_mask != 0U)) { + config->base->IER |= data->interrupt_mask; + } else { + config->base->IER &= ~(HSCMP_IER_CFR_IE_MASK | HSCMP_IER_CFF_IE_MASK); + } + + config->base->CCR0 |= HSCMP_CCR0_CMP_EN_MASK; + + return 0; +} + +static void nxp_hscmp_irq_handler(const struct device *dev) +{ + const struct nxp_hscmp_config *config = dev->config; + struct nxp_hscmp_data *data = dev->data; + + /* Clear interrupt status flags */ + config->base->CSR |= (HSCMP_CSR_CFF_MASK | HSCMP_CSR_CFR_MASK); + + if (data->callback == NULL) { + LOG_WRN("No callback can be executed."); + return; + } + + data->callback(dev, data->user_data); +} + +#if CONFIG_PM_DEVICE +static int nxp_hscmp_pm_callback(const struct device *dev, + enum pm_device_action action) +{ + const struct nxp_hscmp_config *config = dev->config; + + if (action == PM_DEVICE_ACTION_RESUME) { + config->base->CCR0 |= HSCMP_CCR0_CMP_EN_MASK; + return 0; + } + + if (action == PM_DEVICE_ACTION_SUSPEND) { + config->base->CCR0 &= ~HSCMP_CCR0_CMP_EN_MASK; + return 0; + } + + return -ENOTSUP; +} +#endif + +static int nxp_hscmp_init(const struct device *dev) +{ + const struct nxp_hscmp_config *config = dev->config; + const struct device *regulator = config->ref_supplies; + int32_t vref_uv = config->ref_supply_val * 1000; + HSCMP_Type *base = config->base; + int ret; + + if (!device_is_ready(config->clock_dev)) { + LOG_ERR("Clock device is not ready"); + return -ENODEV; + } + + ret = clock_control_on(config->clock_dev, config->clock_subsys); + if (ret != 0) { + LOG_ERR("Device clock turn on failed (%d)", ret); + return ret; + } + + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("Reset device is not ready"); + return -ENODEV; + } + + ret = reset_line_assert(config->reset.dev, config->reset.id); + if (ret != 0) { + LOG_ERR("Failed to assert reset line (%d)", ret); + return ret; + } + + ret = reset_line_deassert(config->reset.dev, config->reset.id); + if (ret != 0) { + LOG_ERR("Failed to deassert reset line (%d)", ret); + return ret; + } + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to configure pins (%d)", ret); + return ret; + } + + if (regulator != NULL) { + ret = regulator_enable(regulator); + if (ret) { + LOG_ERR("Failed to enable regulator (%d)", ret); + return ret; + } + ret = regulator_set_voltage(regulator, vref_uv, vref_uv); + if (ret < 0) { + LOG_ERR("Failed to set regulator voltage (%d)", ret); + return ret; + } + } + + /* Disable comparator before configuring. */ + base->CCR0 &= ~HSCMP_CCR0_CMP_EN_MASK; + + base->CCR0 = ((base->CCR0 & ~(HSCMP_CCR0_CMP_STOP_EN_MASK)) | + HSCMP_CCR0_CMP_STOP_EN(config->enable_stop_mode ? 1U : 0U)); + + base->CCR1 = ((base->CCR1 & ~(HSCMP_CCR1_COUT_INV_MASK | HSCMP_CCR1_COUT_PEN_MASK | + HSCMP_CCR1_COUT_SEL_MASK | HSCMP_CCR1_FILT_CNT_MASK | + HSCMP_CCR1_FILT_PER_MASK | HSCMP_CCR1_SAMPLE_EN_MASK | + HSCMP_CCR1_WINDOW_EN_MASK)) | + HSCMP_CCR1_COUT_INV(config->invert_output ? 1U : 0U) | + HSCMP_CCR1_COUT_PEN(config->enable_pin_out ? 1U : 0U)); + + if (config->use_unfiltered_output) { + base->CCR1 |= HSCMP_CCR1_COUT_SEL_MASK; + } else { + base->CCR1 &= ~HSCMP_CCR1_COUT_SEL_MASK; + if (config->filter_count != 0U) { + base->CCR1 |= HSCMP_CCR1_FILT_CNT(config->filter_count); + base->CCR1 |= HSCMP_CCR1_FILT_PER(config->filter_period); + } + } + + /* Configure inputmux, input source, hysteresis, and power mode. */ + base->CCR2 = ((base->CCR2 & ~(HSCMP_CCR2_CMP_HPMD_MASK | HSCMP_CCR2_CMP_NPMD_MASK | + HSCMP_CCR2_HYSTCTR_MASK | HSCMP_CCR2_PSEL_MASK | HSCMP_CCR2_MSEL_MASK)) | + HSCMP_CCR2_PSEL(config->positive_mux_is_dac ? 5U : config->positive_mux_input) | + HSCMP_CCR2_MSEL(config->negative_mux_is_dac ? 5U : config->negative_mux_input) | + HSCMP_CCR2_HYSTCTR(config->hysteresis_mode)); + + switch (config->power_mode) { + case 1U: /* high speed */ + base->CCR2 |= HSCMP_CCR2_CMP_HPMD_MASK; + break; + case 2U: /* nano power */ + base->CCR2 |= HSCMP_CCR2_CMP_NPMD_MASK; + break; + default: /* low power */ + break; + } + + /* Configure DAC if needed. */ + base->DCR &= ~(HSCMP_DCR_DAC_EN_MASK | HSCMP_DCR_DAC_HPMD_MASK | HSCMP_DCR_VRSEL_MASK | + HSCMP_DCR_DAC_DATA_MASK); + + if (config->positive_mux_is_dac || config->negative_mux_is_dac) { + base->DCR |= (HSCMP_DCR_VRSEL(config->dac_vref_source) | + HSCMP_DCR_DAC_DATA(config->dac_value) | HSCMP_DCR_DAC_EN_MASK); + } + + /* Clear status flags before enabling interrupts or the comparator. */ + base->CSR = (HSCMP_CSR_CFF_MASK | HSCMP_CSR_CFR_MASK); + base->IER &= ~(HSCMP_IER_CFR_IE_MASK | HSCMP_IER_CFF_IE_MASK); + + config->irq_config_func(dev); + + base->CCR0 |= HSCMP_CCR0_CMP_EN_MASK; + +#if CONFIG_PM_DEVICE + return pm_device_driver_init(dev, nxp_hscmp_pm_callback); +#else + return 0; +#endif +} + +static DEVICE_API(comparator, nxp_hscmp_api) = { + .get_output = nxp_hscmp_get_output, + .set_trigger = nxp_hscmp_set_trigger, + .set_trigger_callback = nxp_hscmp_set_trigger_callback, + .trigger_is_pending = nxp_hscmp_trigger_is_pending, +}; + +#define HSCMP_DT_ENUM_IDX(inst, prop, default_val) \ + DT_ENUM_IDX_OR(DT_DRV_INST(inst), prop, default_val) + +#define HSCMP_DT_MUX_IS_DAC(inst, prop) DT_ENUM_HAS_VALUE(DT_DRV_INST(inst), prop, dac) +#define HSCMP_DT_MUX_IDX(inst, prop) HSCMP_DT_ENUM_IDX(inst, prop, 0) + +#if CONFIG_PM_DEVICE +#define HSCMP_PM_DEVICE_DEFINE PM_DEVICE_DT_INST_DEFINE(inst, nxp_hscmp_pm_callback); +#define HSCMP_PM_DEVICE_GET PM_DEVICE_DT_INST_GET(inst) +#else +#define HSCMP_PM_DEVICE_DEFINE +#define HSCMP_PM_DEVICE_GET NULL +#endif + +#define NXP_HSCMP_DEVICE_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static struct nxp_hscmp_data _CONCAT(data, inst) = { \ + .interrupt_mask = 0U, \ + }; \ + \ + HSCMP_PM_DEVICE_DEFINE \ + \ + static void _CONCAT(nxp_hscmp_irq_config, inst)(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ + nxp_hscmp_irq_handler, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + static const struct nxp_hscmp_config _CONCAT(config, inst) = { \ + .base = (HSCMP_Type *)DT_INST_REG_ADDR(inst), \ + .enable_stop_mode = DT_INST_PROP(inst, enable_stop_mode), \ + .invert_output = DT_INST_PROP(inst, invert_output), \ + .enable_pin_out = DT_INST_PROP(inst, enable_pin_out), \ + .use_unfiltered_output = DT_INST_PROP(inst, use_unfiltered_output), \ + .filter_count = DT_INST_PROP_OR(inst, filter_count, 0), \ + .filter_period = DT_INST_PROP_OR(inst, filter_period, 0), \ + .positive_mux_is_dac = HSCMP_DT_MUX_IS_DAC(inst, positive_mux_input), \ + .negative_mux_is_dac = HSCMP_DT_MUX_IS_DAC(inst, negative_mux_input), \ + .positive_mux_input = HSCMP_DT_MUX_IDX(inst, positive_mux_input), \ + .negative_mux_input = HSCMP_DT_MUX_IDX(inst, negative_mux_input), \ + .dac_value = DT_INST_PROP_OR(inst, dac_value, 0), \ + .dac_vref_source = HSCMP_DT_ENUM_IDX(inst, dac_vref_source, 0), \ + .hysteresis_mode = DT_INST_ENUM_IDX_OR(inst, hysteresis_mode, 0), \ + .power_mode = HSCMP_DT_ENUM_IDX(inst, power_mode, 0), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, name), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .irq_config_func = _CONCAT(nxp_hscmp_irq_config, inst), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .ref_supplies = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, nxp_references), \ + (DEVICE_DT_GET(DT_INST_PHANDLE(inst, nxp_references))), (NULL)), \ + .ref_supply_val = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, nxp_references), \ + (DT_INST_PHA(inst, nxp_references, vref_mv)), (0)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, nxp_hscmp_init, HSCMP_PM_DEVICE_GET, \ + &_CONCAT(data, inst), &_CONCAT(config, inst), POST_KERNEL, \ + CONFIG_COMPARATOR_INIT_PRIORITY, &nxp_hscmp_api); + +DT_INST_FOREACH_STATUS_OKAY(NXP_HSCMP_DEVICE_INIT) diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index f75ae4398017e..8c70c28551d9c 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -312,6 +312,36 @@ clocks = <&syscon MCUX_LPADC1_CLK>; }; + hscmp0: comparator@b3000 { + compatible = "nxp,hscmp"; + reg = <0xb3000 0x1000>; + interrupts = <77 0>; + clocks = <&syscon MCUX_HSCMP0_CLK>; + resets = <&reset NXP_SYSCON_RESET(3, 15)>; + status = "disabled"; + nxp,references = <&vref0 1800>; + }; + + hscmp1: comparator@b7000 { + compatible = "nxp,hscmp"; + reg = <0xb7000 0x1000>; + interrupts = <78 0>; + clocks = <&syscon MCUX_HSCMP1_CLK>; + resets = <&reset NXP_SYSCON_RESET(3, 16)>; + status = "disabled"; + nxp,references = <&vref0 1800>; + }; + + hscmp2: comparator@ba000 { + compatible = "nxp,hscmp"; + reg = <0xba000 0x1000>; + interrupts = <79 0>; + clocks = <&syscon MCUX_HSCMP2_CLK>; + resets = <&reset NXP_SYSCON_RESET(3, 17)>; + status = "disabled"; + nxp,references = <&vref0 1800>; + }; + opamp0: opamp@b4000 { compatible = "nxp,opamp"; reg = <0xb4000 0x1000>; diff --git a/dts/bindings/comparator/nxp,hscmp.yaml b/dts/bindings/comparator/nxp,hscmp.yaml new file mode 100644 index 0000000000000..a1f819f3837fc --- /dev/null +++ b/dts/bindings/comparator/nxp,hscmp.yaml @@ -0,0 +1,124 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP High Speed Comparator (HSCMP) + +compatible: "nxp,hscmp" + +include: + - base.yaml + - pinctrl-device.yaml + - reset-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + resets: + required: true + + power-mode: + type: string + enum: + - "low_speed" + - "high_speed" + - "nano_power" + description: | + Select comparator power/speed mode. + + hysteresis-mode: + type: string + enum: + - "LEVEL0" + - "LEVEL1" + - "LEVEL2" + - "LEVEL3" + description: | + Comparator hysteresis level. + + enable-stop-mode: + type: boolean + description: | + Allow the comparator to remain enabled in STOP mode. + + invert-output: + type: boolean + description: | + Invert comparator output. + + enable-pin-out: + type: boolean + description: | + Drive comparator output on the associated pin. + + use-unfiltered-output: + type: boolean + description: | + Route unfiltered comparator output to COUT. + When false, the filtered output is used and filter parameters + are taken from filter-count and filter-period. + + filter-count: + type: int + enum: [0, 1, 2, 3, 4, 5, 6, 7] + description: | + Number of consecutive samples that must agree before updating + the filtered output. Set to 0 to bypass the filter. + + filter-period: + type: int + description: | + Sampling period for the filter in bus clock cycles. + Valid range: 0 - 255. + + dac-vref-source: + type: string + enum: + - "VREFH0" + - "VREFH1" + description: | + DAC reference high-voltage source selection. + + dac-value: + type: int + description: | + 8-bit DAC code used when an input channel is set to DAC output. + Valid range: 0 - 255. + + positive-mux-input: + type: string + enum: + - "IN0" + - "IN1" + - "IN2" + - "IN3" + - "IN4" + - "IN5" + - "DAC" + description: | + Positive input multiplexer selection. "DAC" routes the internal DAC output. + + negative-mux-input: + type: string + enum: + - "IN0" + - "IN1" + - "IN2" + - "IN3" + - "IN4" + - "IN5" + - "DAC" + description: | + Negative input multiplexer selection. "DAC" routes the internal DAC output. + + nxp,references: + type: phandle-array + description: | + References to required regulators which must be enabled for HSCMP to function diff --git a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h index 03c2e9653203b..6e21673946735 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -140,4 +140,8 @@ #define MCUX_MICFIL_CLK MCUX_LPC_CLK_ID(0x20, 0x00) +#define MCUX_HSCMP0_CLK MCUX_LPC_CLK_ID(0x21, 0x00) +#define MCUX_HSCMP1_CLK MCUX_LPC_CLK_ID(0x21, 0x01) +#define MCUX_HSCMP2_CLK MCUX_LPC_CLK_ID(0x21, 0x02) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ diff --git a/soc/nxp/lpc/lpc55xxx/Kconfig.defconfig b/soc/nxp/lpc/lpc55xxx/Kconfig.defconfig index f100f34326aa1..d3a1f30ddc7e1 100644 --- a/soc/nxp/lpc/lpc55xxx/Kconfig.defconfig +++ b/soc/nxp/lpc/lpc55xxx/Kconfig.defconfig @@ -5,6 +5,7 @@ if SOC_SERIES_LPC55XXX config NUM_IRQS # must be >= the highest interrupt number used + default 119 if SOC_LPC55S36 default 60 config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/nxp/lpc/lpc55xxx/soc.c b/soc/nxp/lpc/lpc55xxx/soc.c index 100569953286f..cbf7474d2a9ee 100644 --- a/soc/nxp/lpc/lpc55xxx/soc.c +++ b/soc/nxp/lpc/lpc55xxx/soc.c @@ -444,6 +444,27 @@ DT_FOREACH_STATUS_OKAY(nxp_ctimer_pwm, CTIMER_CLOCK_SETUP) SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U); SYSCON->MCLKIO = 1U; #endif /* CONFIG_AUDIO_CODEC_WM8904 */ + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hscmp0)) + POWER_DisablePD(kPDRUNCFG_PD_VREF); + POWER_DisablePD(kPDRUNCFG_PD_CMPBIAS); + POWER_DisablePD(kPDRUNCFG_PD_HSCMP0); + POWER_DisablePD(kPDRUNCFG_PD_HSCMP0_DAC); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hscmp1)) + POWER_DisablePD(kPDRUNCFG_PD_VREF); + POWER_DisablePD(kPDRUNCFG_PD_CMPBIAS); + POWER_DisablePD(kPDRUNCFG_PD_HSCMP1); + POWER_DisablePD(kPDRUNCFG_PD_HSCMP1_DAC); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hscmp2)) + POWER_DisablePD(kPDRUNCFG_PD_VREF); + POWER_DisablePD(kPDRUNCFG_PD_CMPBIAS); + POWER_DisablePD(kPDRUNCFG_PD_HSCMP2); + POWER_DisablePD(kPDRUNCFG_PD_HSCMP2_DAC); +#endif } /** diff --git a/tests/drivers/comparator/gpio_loopback/boards/lpcxpresso55s36.overlay b/tests/drivers/comparator/gpio_loopback/boards/lpcxpresso55s36.overlay new file mode 100644 index 0000000000000..523930ba39d90 --- /dev/null +++ b/tests/drivers/comparator/gpio_loopback/boards/lpcxpresso55s36.overlay @@ -0,0 +1,25 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + test-comp = &hscmp0; + }; + + zephyr,user { + /* P0-10 (LPC55S36-EVK J9-7) output connect to P1-5 (LPC55S36-EVK J9-9). */ + test-gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; + }; +}; + +&hscmp0 { + positive-mux-input = "IN3"; + negative-mux-input = "DAC"; + dac-vref-source = "VREFH1"; + dac-value = <127>; +}; diff --git a/tests/drivers/comparator/gpio_loopback/testcase.yaml b/tests/drivers/comparator/gpio_loopback/testcase.yaml index 0af23dcb7ee19..0ff7b7061cec8 100644 --- a/tests/drivers/comparator/gpio_loopback/testcase.yaml +++ b/tests/drivers/comparator/gpio_loopback/testcase.yaml @@ -44,3 +44,6 @@ tests: platform_allow: - nucleo_h745zi_q/stm32h745xx/m7 - nucleo_g474re/stm32g474xx + drivers.comparator.gpio_loopback.nxp_hscmp: + platform_allow: + - lpcxpresso55s36