12
12
#include <zephyr/irq.h>
13
13
#include <fsl_lptmr.h>
14
14
15
+ #define NUM_CHANNELS 1
16
+
15
17
struct mcux_lptmr_config {
16
18
struct counter_config_info info ;
17
19
LPTMR_Type * base ;
@@ -22,11 +24,15 @@ struct mcux_lptmr_config {
22
24
lptmr_pin_select_t pin ;
23
25
lptmr_pin_polarity_t polarity ;
24
26
void (* irq_config_func )(const struct device * dev );
27
+ unsigned int irqn ;
25
28
};
26
29
27
30
struct mcux_lptmr_data {
28
31
counter_top_callback_t top_callback ;
32
+ counter_alarm_callback_t alarm_callback ;
29
33
void * top_user_data ;
34
+ void * alarm_user_data ;
35
+ uint32_t guard_period ;
30
36
};
31
37
32
38
static int mcux_lptmr_start (const struct device * dev )
@@ -118,11 +124,132 @@ static void mcux_lptmr_isr(const struct device *dev)
118
124
if (data -> top_callback ) {
119
125
data -> top_callback (dev , data -> top_user_data );
120
126
}
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 ;
121
247
}
122
248
123
249
static int mcux_lptmr_init (const struct device * dev )
124
250
{
125
251
const struct mcux_lptmr_config * config = dev -> config ;
252
+ struct mcux_lptmr_data * data = dev -> data ;
126
253
lptmr_config_t lptmr_config ;
127
254
128
255
LPTMR_GetDefaultConfig (& lptmr_config );
@@ -143,6 +270,8 @@ static int mcux_lptmr_init(const struct device *dev)
143
270
144
271
config -> irq_config_func (dev );
145
272
273
+ data -> guard_period = 0 ;
274
+
146
275
return 0 ;
147
276
}
148
277
@@ -153,6 +282,10 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
153
282
.set_top_value = mcux_lptmr_set_top_value ,
154
283
.get_pending_int = mcux_lptmr_get_pending_int ,
155
284
.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 ,
156
289
};
157
290
158
291
#define COUNTER_MCUX_LPTMR_DEVICE_INIT (n ) \
@@ -181,7 +314,7 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
181
314
.freq = DT_INST_PROP(n, clock_frequency) / \
182
315
DT_INST_PROP(n, prescaler), \
183
316
.flags = COUNTER_CONFIG_INFO_COUNT_UP, \
184
- .channels = 0, \
317
+ .channels = NUM_CHANNELS, \
185
318
}, \
186
319
.base = (LPTMR_Type *)DT_INST_REG_ADDR(n), \
187
320
.clk_source = DT_INST_PROP(n, clk_source), \
@@ -193,6 +326,7 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
193
326
.prescaler_glitch = DT_INST_PROP(n, prescale_glitch_filter) + \
194
327
DT_INST_PROP(n, timer_mode_sel) - 1, \
195
328
.irq_config_func = mcux_lptmr_irq_config_##n, \
329
+ .irqn = DT_INST_IRQN(n), \
196
330
}; \
197
331
\
198
332
DEVICE_DT_INST_DEFINE(n, &mcux_lptmr_init, NULL, \
@@ -201,5 +335,4 @@ static DEVICE_API(counter, mcux_lptmr_driver_api) = {
201
335
POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \
202
336
&mcux_lptmr_driver_api);
203
337
204
-
205
338
DT_INST_FOREACH_STATUS_OKAY (COUNTER_MCUX_LPTMR_DEVICE_INIT )
0 commit comments