Skip to content

Commit 6d724bd

Browse files
ZhaoxiangJincfriedt
authored andcommitted
drivers: comparator: Enable nxp comparator (cmp)
Enable nxp comparator (cmp) Signed-off-by: Zhaoxiang Jin <[email protected]>
1 parent 711a887 commit 6d724bd

File tree

5 files changed

+421
-0
lines changed

5 files changed

+421
-0
lines changed

drivers/comparator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ zephyr_library_sources_ifdef(CONFIG_COMPARATOR_SILABS_ACMP comparator_silabs_acm
1010
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_FAKE_COMP comparator_fake_comp.c)
1111
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_IT51XXX_VCMP comparator_it51xxx_vcmp.c)
1212
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_MCUX_ACMP comparator_mcux_acmp.c)
13+
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NXP_CMP comparator_nxp_cmp.c)
1314
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_COMP comparator_nrf_comp.c)
1415
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_NRF_LPCOMP comparator_nrf_lpcomp.c)
1516
zephyr_library_sources_ifdef(CONFIG_COMPARATOR_SHELL comparator_shell.c)

drivers/comparator/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ rsource "Kconfig.fake_comp"
2222
rsource "Kconfig.silabs_acmp"
2323
rsource "Kconfig.it51xxx_vcmp"
2424
rsource "Kconfig.mcux_acmp"
25+
rsource "Kconfig.nxp_cmp"
2526
rsource "Kconfig.nrf_comp"
2627
rsource "Kconfig.nrf_lpcomp"
2728
rsource "Kconfig.shell"

drivers/comparator/Kconfig.nxp_cmp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config COMPARATOR_NXP_CMP
5+
bool "NXP comparator driver"
6+
default y
7+
depends on DT_HAS_NXP_CMP_ENABLED
8+
select PINCTRL
9+
select CLOCK_CONTROL
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/irq.h>
8+
#include <zephyr/pm/device.h>
9+
#include <zephyr/drivers/comparator.h>
10+
#include <zephyr/logging/log.h>
11+
#include <zephyr/drivers/clock_control.h>
12+
13+
LOG_MODULE_REGISTER(nxp_cmp, CONFIG_COMPARATOR_LOG_LEVEL);
14+
15+
#define DT_DRV_COMPAT nxp_cmp
16+
17+
struct nxp_cmp_config {
18+
CMP_Type *base;
19+
bool enable_high_speed_mode;
20+
bool invert_output;
21+
bool enable_pin_out;
22+
bool use_unfiltered_output;
23+
uint8_t filter_count;
24+
uint8_t filter_period;
25+
uint8_t positive_mux_input;
26+
uint8_t negative_mux_input;
27+
uint8_t dac_value;
28+
uint8_t dac_vref_source;
29+
uint8_t hysteresis_mode;
30+
void (*irq_config_func)(const struct device *dev);
31+
const struct device *clock_dev;
32+
clock_control_subsys_t clock_subsys;
33+
};
34+
35+
struct nxp_cmp_data {
36+
uint8_t interrupt_mask;
37+
comparator_callback_t callback;
38+
void *user_data;
39+
};
40+
41+
static int nxp_cmp_get_output(const struct device *dev)
42+
{
43+
const struct nxp_cmp_config *config = dev->config;
44+
45+
return ((bool)(config->base->SCR & CMP_SCR_COUT_MASK)) ? 1 : 0;
46+
}
47+
48+
static int nxp_cmp_set_trigger(const struct device *dev,
49+
enum comparator_trigger trigger)
50+
{
51+
const struct nxp_cmp_config *config = dev->config;
52+
struct nxp_cmp_data *data = dev->data;
53+
54+
config->base->SCR &= ~(CMP_SCR_IEF_MASK | CMP_SCR_IER_MASK);
55+
56+
switch (trigger) {
57+
case COMPARATOR_TRIGGER_NONE:
58+
data->interrupt_mask = 0;
59+
break;
60+
61+
case COMPARATOR_TRIGGER_RISING_EDGE:
62+
data->interrupt_mask = CMP_SCR_IER_MASK;
63+
break;
64+
65+
case COMPARATOR_TRIGGER_FALLING_EDGE:
66+
data->interrupt_mask = CMP_SCR_IEF_MASK;
67+
break;
68+
69+
case COMPARATOR_TRIGGER_BOTH_EDGES:
70+
data->interrupt_mask = CMP_SCR_IEF_MASK | CMP_SCR_IER_MASK;
71+
break;
72+
73+
default:
74+
LOG_ERR("Invalid trigger type.");
75+
return -EINVAL;
76+
}
77+
78+
/* Enable interrupts when interrupt_mask is non-zero and
79+
* callback function is not NULL.
80+
*/
81+
if ((data->interrupt_mask != 0) && (data->callback != NULL)) {
82+
config->base->SCR |= data->interrupt_mask;
83+
}
84+
85+
return 0;
86+
}
87+
88+
static int nxp_cmp_trigger_is_pending(const struct device *dev)
89+
{
90+
const struct nxp_cmp_config *config = dev->config;
91+
struct nxp_cmp_data *data = dev->data;
92+
uint8_t status_flags;
93+
94+
status_flags = config->base->SCR & (CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK);
95+
config->base->SCR |= (CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK);
96+
97+
if (((data->interrupt_mask & CMP_SCR_IEF_MASK) != 0) &&
98+
((status_flags & CMP_SCR_CFF_MASK) != 0)) {
99+
return 1;
100+
}
101+
102+
if (((data->interrupt_mask & CMP_SCR_IER_MASK) != 0) &&
103+
((status_flags & CMP_SCR_CFR_MASK) != 0)) {
104+
return 1;
105+
}
106+
107+
return 0;
108+
}
109+
110+
static int nxp_cmp_set_trigger_callback(const struct device *dev,
111+
comparator_callback_t callback,
112+
void *user_data)
113+
{
114+
const struct nxp_cmp_config *config = dev->config;
115+
struct nxp_cmp_data *data = dev->data;
116+
117+
config->base->CR1 &= ~CMP_CR1_EN_MASK;
118+
119+
data->callback = callback;
120+
data->user_data = user_data;
121+
122+
config->base->CR1 |= CMP_CR1_EN_MASK;
123+
124+
if (data->callback == NULL) {
125+
LOG_INF("Callback is not set.");
126+
return 0;
127+
}
128+
129+
return 0;
130+
}
131+
132+
static void nxp_cmp_irq_handler(const struct device *dev)
133+
{
134+
const struct nxp_cmp_config *config = dev->config;
135+
struct nxp_cmp_data *data = dev->data;
136+
137+
/* Clear interrupt status flags */
138+
config->base->SCR |= (CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK);
139+
140+
if (data->callback == NULL) {
141+
LOG_WRN("No callback can be executed.");
142+
return;
143+
}
144+
145+
data->callback(dev, data->user_data);
146+
}
147+
148+
static int nxp_cmp_pm_callback(const struct device *dev,
149+
enum pm_device_action action)
150+
{
151+
const struct nxp_cmp_config *config = dev->config;
152+
153+
if (action == PM_DEVICE_ACTION_RESUME) {
154+
config->base->CR1 |= CMP_CR1_EN_MASK;
155+
}
156+
157+
if (action == PM_DEVICE_ACTION_SUSPEND) {
158+
config->base->CR1 &= ~CMP_CR1_EN_MASK;
159+
}
160+
161+
return 0;
162+
}
163+
164+
static int nxp_cmp_init(const struct device *dev)
165+
{
166+
const struct nxp_cmp_config *config = dev->config;
167+
int ret;
168+
169+
ret = clock_control_on(config->clock_dev, config->clock_subsys);
170+
171+
if (ret) {
172+
LOG_ERR("Device clock turn on failed");
173+
return ret;
174+
}
175+
176+
config->base->CR0 = ((config->base->CR0 & ~CMP_CR0_HYSTCTR_MASK) |
177+
CMP_CR0_HYSTCTR(config->hysteresis_mode));
178+
179+
config->base->CR1 = ((config->base->CR1 & ~(CMP_CR1_PMODE_MASK |
180+
CMP_CR1_INV_MASK | CMP_CR1_OPE_MASK | CMP_CR1_COS_MASK)) |
181+
(CMP_CR1_PMODE(config->enable_high_speed_mode) |
182+
CMP_CR1_INV(config->invert_output) |
183+
CMP_CR1_OPE(config->enable_pin_out) |
184+
CMP_CR1_COS(config->use_unfiltered_output)));
185+
186+
/* Input mux configuration */
187+
config->base->MUXCR = ((config->base->MUXCR & ~(CMP_MUXCR_PSEL_MASK |
188+
CMP_MUXCR_MSEL_MASK)) | (CMP_MUXCR_PSEL(config->positive_mux_input) |
189+
CMP_MUXCR_MSEL(config->negative_mux_input)));
190+
191+
/* DAC configuration */
192+
if (7 == config->negative_mux_input) {
193+
config->base->DACCR = ((config->base->DACCR & ~(CMP_DACCR_VRSEL_MASK |
194+
CMP_DACCR_VOSEL_MASK)) | (CMP_DACCR_VRSEL(config->dac_vref_source) |
195+
CMP_DACCR_VOSEL(config->dac_value) | CMP_DACCR_DACEN_MASK));
196+
}
197+
198+
/* Filter configuration. */
199+
if (0 != config->filter_count) {
200+
config->base->CR1 &= ~CMP_CR1_SE_MASK;
201+
config->base->FPR = CMP_FPR_FILT_PER(config->filter_period);
202+
config->base->CR0 = ((config->base->CR0 & ~CMP_CR0_FILTER_CNT_MASK) |
203+
CMP_CR0_FILTER_CNT(config->filter_count));
204+
}
205+
206+
config->irq_config_func(dev);
207+
208+
return pm_device_driver_init(dev, nxp_cmp_pm_callback);
209+
}
210+
211+
static DEVICE_API(comparator, nxp_cmp_api) = {
212+
.get_output = nxp_cmp_get_output,
213+
.set_trigger = nxp_cmp_set_trigger,
214+
.set_trigger_callback = nxp_cmp_set_trigger_callback,
215+
.trigger_is_pending = nxp_cmp_trigger_is_pending,
216+
};
217+
218+
#define NXP_CMP_DEVICE_INIT(inst) \
219+
\
220+
static struct nxp_cmp_data _CONCAT(data, inst) = { \
221+
.interrupt_mask = 0, \
222+
}; \
223+
\
224+
PM_DEVICE_DT_INST_DEFINE(inst, nxp_cmp_pm_callback); \
225+
\
226+
static void _CONCAT(nxp_cmp_irq_config, inst)(const struct device *dev) \
227+
{ \
228+
IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \
229+
nxp_cmp_irq_handler, DEVICE_DT_INST_GET(inst), 0); \
230+
irq_enable(DT_INST_IRQN(inst)); \
231+
} \
232+
\
233+
static const struct nxp_cmp_config _CONCAT(config, inst) = { \
234+
.base = (CMP_Type *)DT_INST_REG_ADDR(inst), \
235+
.enable_high_speed_mode = DT_INST_PROP(inst, \
236+
enable_high_speed_mode), \
237+
.invert_output = DT_INST_PROP(inst, invert_output), \
238+
.enable_pin_out = DT_INST_PROP(inst, enable_pin_out), \
239+
.use_unfiltered_output = DT_INST_PROP(inst, \
240+
use_unfiltered_output), \
241+
.filter_count = DT_INST_PROP_OR(inst, filter_count, 0), \
242+
.filter_period = DT_INST_PROP_OR(inst, filter_period, 0), \
243+
.positive_mux_input = DT_ENUM_IDX_OR(DT_DRV_INST(inst), \
244+
positive_mux_input, 0), \
245+
.negative_mux_input = DT_ENUM_IDX_OR(DT_DRV_INST(inst), \
246+
negative_mux_input, 0), \
247+
.dac_value = DT_INST_PROP_OR(inst, dac_value, 0), \
248+
.dac_vref_source = DT_ENUM_IDX_OR(DT_DRV_INST(inst), \
249+
dac_vref_source, 0), \
250+
.hysteresis_mode = DT_INST_PROP_OR(DT_DRV_INST(inst), \
251+
hysteresis_mode, 0), \
252+
.irq_config_func = _CONCAT(nxp_cmp_irq_config, inst), \
253+
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
254+
.clock_subsys = \
255+
(clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, name),\
256+
}; \
257+
\
258+
DEVICE_DT_INST_DEFINE(inst, nxp_cmp_init, PM_DEVICE_DT_INST_GET(inst), \
259+
&_CONCAT(data, inst), &_CONCAT(config, inst), \
260+
POST_KERNEL, CONFIG_COMPARATOR_INIT_PRIORITY, \
261+
&nxp_cmp_api);
262+
263+
DT_INST_FOREACH_STATUS_OKAY(NXP_CMP_DEVICE_INIT)

0 commit comments

Comments
 (0)