Skip to content

Commit 86d9932

Browse files
committed
NXP driver: lptmr: add alarm and guard period API functions.
Add alarm APIs: set_alarm, cancel_alarm Add guard period APIs: set_guard_period Signed-off-by: Holt.Sun <[email protected]>
1 parent 4bd1d39 commit 86d9932

File tree

1 file changed

+135
-2
lines changed

1 file changed

+135
-2
lines changed

drivers/counter/counter_mcux_lptmr.c

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <zephyr/irq.h>
1313
#include <fsl_lptmr.h>
1414

15+
#define NUM_CHANNELS 1
16+
1517
struct mcux_lptmr_config {
1618
struct counter_config_info info;
1719
LPTMR_Type *base;
@@ -22,11 +24,15 @@ struct mcux_lptmr_config {
2224
lptmr_pin_select_t pin;
2325
lptmr_pin_polarity_t polarity;
2426
void (*irq_config_func)(const struct device *dev);
27+
unsigned int irqn;
2528
};
2629

2730
struct mcux_lptmr_data {
2831
counter_top_callback_t top_callback;
32+
counter_alarm_callback_t alarm_callback;
2933
void *top_user_data;
34+
void *alarm_user_data;
35+
uint32_t guard_period;
3036
};
3137

3238
static int mcux_lptmr_start(const struct device *dev)
@@ -118,11 +124,132 @@ static void mcux_lptmr_isr(const struct device *dev)
118124
if (data->top_callback) {
119125
data->top_callback(dev, data->top_user_data);
120126
}
127+
128+
if (data->alarm_callback) {
129+
uint32_t ticks;
130+
ticks = LPTMR_GetCurrentTimerCount(config->base);
131+
counter_alarm_callback_t alarm_callback = data->alarm_callback;
132+
void *alarm_user_data = data->alarm_user_data;
133+
data->alarm_callback = NULL;
134+
data->alarm_user_data = NULL;
135+
alarm_callback(dev, 0, ticks, alarm_user_data);
136+
}
137+
}
138+
139+
static int mcux_lptmr_set_guard_period(const struct device *dev, uint32_t guard, uint32_t flags)
140+
{
141+
struct mcux_lptmr_data *data = dev->data;
142+
143+
ARG_UNUSED(flags);
144+
145+
__ASSERT_NO_MSG(guard < mcux_lptmr_get_top_value(dev));
146+
data->guard_period = guard;
147+
148+
return 0;
149+
}
150+
151+
static uint32_t mcux_lptmr_get_guard_period(const struct device *dev, uint32_t flags)
152+
{
153+
struct mcux_lptmr_data *data = dev->data;
154+
155+
ARG_UNUSED(flags);
156+
157+
return data->guard_period;
158+
}
159+
160+
static int mcux_lptmr_set_alarm(const struct device *dev, uint8_t chan_id,
161+
const struct counter_alarm_cfg *alarm_cfg)
162+
{
163+
const struct mcux_lptmr_config *config = dev->config;
164+
struct mcux_lptmr_data *data = dev->data;
165+
uint32_t current;
166+
uint32_t max_rel_val;
167+
bool irq_on_late = false;
168+
uint32_t ticks = alarm_cfg->ticks;
169+
bool absolute = alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE;
170+
int err = 0;
171+
uint32_t top = mcux_lptmr_get_top_value(dev);
172+
173+
if (alarm_cfg->ticks > top) {
174+
return -EINVAL;
175+
}
176+
177+
if (chan_id != 0) {
178+
return -EINVAL;
179+
}
180+
181+
if (data->alarm_callback) {
182+
return -EBUSY;
183+
}
184+
185+
data->alarm_callback = alarm_cfg->callback;
186+
data->alarm_user_data = alarm_cfg->user_data;
187+
188+
current = LPTMR_GetCurrentTimerCount(config->base);
189+
max_rel_val = (current + data->guard_period) % config->info.max_top_value;
190+
191+
if (absolute == 0) {
192+
/*
193+
* If relative value is smaller than half of the counter range it is assumed
194+
* that there is a risk of setting value too late and late detection algorithm
195+
* must be applied. When late setting is detected, interrupt shall be
196+
* triggered for immediate expiration of the timer. Detection is performed
197+
* by limiting relative distance between CMP and CNT.
198+
*
199+
* Note that half of counter range is an arbitrary value.
200+
*/
201+
irq_on_late = ticks < (config->info.max_top_value / 2);
202+
ticks = (ticks + current) % config->info.max_top_value;
203+
} else {
204+
irq_on_late = alarm_cfg->flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE;
205+
ticks = alarm_cfg->ticks % config->info.max_top_value;
206+
}
207+
208+
/*
209+
* When LPTMR is enabled, the CMR can be altered only when CSR[TCF] = 1, since this cannot
210+
* be guaranteed, the timer must be stopped before setting the CMR.
211+
*/
212+
LPTMR_StopTimer(config->base);
213+
214+
LPTMR_SetTimerPeriod(config->base, ticks);
215+
LPTMR_EnableInterrupts(config->base, kLPTMR_TimerInterruptEnable);
216+
217+
LPTMR_StartTimer(config->base);
218+
219+
if (ticks <= max_rel_val) {
220+
if (absolute) {
221+
err = -ETIME;
222+
}
223+
224+
if (irq_on_late) {
225+
NVIC_SetPendingIRQ(config->irqn);
226+
} else {
227+
data->alarm_callback = NULL;
228+
}
229+
}
230+
231+
return err;
232+
}
233+
234+
static int mcux_lptmr_cancel_alarm(const struct device *dev, uint8_t chan_id)
235+
{
236+
const struct mcux_lptmr_config *config = dev->config;
237+
struct mcux_lptmr_data *data = dev->data;
238+
239+
if (chan_id != 0) {
240+
return -EINVAL;
241+
}
242+
243+
LPTMR_DisableInterrupts(config->base, kLPTMR_TimerInterruptEnable);
244+
data->alarm_callback = NULL;
245+
246+
return 0;
121247
}
122248

123249
static int mcux_lptmr_init(const struct device *dev)
124250
{
125251
const struct mcux_lptmr_config *config = dev->config;
252+
struct mcux_lptmr_data *data = dev->data;
126253
lptmr_config_t lptmr_config;
127254

128255
LPTMR_GetDefaultConfig(&lptmr_config);
@@ -143,6 +270,8 @@ static int mcux_lptmr_init(const struct device *dev)
143270

144271
config->irq_config_func(dev);
145272

273+
data->guard_period = 0;
274+
146275
return 0;
147276
}
148277

@@ -153,6 +282,10 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
153282
.set_top_value = mcux_lptmr_set_top_value,
154283
.get_pending_int = mcux_lptmr_get_pending_int,
155284
.get_top_value = mcux_lptmr_get_top_value,
285+
.set_alarm = mcux_lptmr_set_alarm,
286+
.cancel_alarm = mcux_lptmr_cancel_alarm,
287+
.set_guard_period = mcux_lptmr_set_guard_period,
288+
.get_guard_period = mcux_lptmr_get_guard_period,
156289
};
157290

158291
#define COUNTER_MCUX_LPTMR_DEVICE_INIT(n) \
@@ -181,7 +314,7 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
181314
.freq = DT_INST_PROP(n, clock_frequency) / \
182315
DT_INST_PROP(n, prescaler), \
183316
.flags = COUNTER_CONFIG_INFO_COUNT_UP, \
184-
.channels = 0, \
317+
.channels = NUM_CHANNELS, \
185318
}, \
186319
.base = (LPTMR_Type *)DT_INST_REG_ADDR(n), \
187320
.clk_source = DT_INST_PROP(n, clk_source), \
@@ -193,6 +326,7 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
193326
.prescaler_glitch = DT_INST_PROP(n, prescale_glitch_filter) + \
194327
DT_INST_PROP(n, timer_mode_sel) - 1, \
195328
.irq_config_func = mcux_lptmr_irq_config_##n, \
329+
.irqn = DT_INST_IRQN(n), \
196330
}; \
197331
\
198332
DEVICE_DT_INST_DEFINE(n, &mcux_lptmr_init, NULL, \
@@ -201,5 +335,4 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
201335
POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \
202336
&mcux_lptmr_driver_api);
203337

204-
205338
DT_INST_FOREACH_STATUS_OKAY(COUNTER_MCUX_LPTMR_DEVICE_INIT)

0 commit comments

Comments
 (0)