1 /*
2 * Copyright (c) 2024, Texas Instruments Incorporated
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/__assert.h>
10 #include <kernel/zephyr/dpl/dpl.h>
11 #include <ti/drivers/dpl/ClockP.h>
12 #include <ti/drivers/dpl/HwiP.h>
13
14 /* Driverlib includes*/
15 #include <ti/devices/DeviceFamily.h>
16 #include DeviceFamily_constructPath(inc/hw_types.h)
17 #include DeviceFamily_constructPath(inc/hw_memmap.h)
18 #include DeviceFamily_constructPath(inc/hw_systim.h)
19
20 /** Max number of ClockP ticks into the future supported by this ClockP
21 * implementation.
22 *
23 * Under the hood, ClockP uses the SysTimer whose events trigger immediately if
24 * the compare value is less than 2^22 systimer ticks in the past
25 * (4.194sec at 1us resolution). Therefore, the max number of SysTimer ticks you
26 * can schedule into the future is 2^32 - 2^22 - 1 ticks (~= 4290 sec at 1us
27 * resolution). */
28 #define ClockP_PERIOD_MAX (0xFFBFFFFFU / ClockP_TICK_PERIOD)
29 /** Max number of seconds into the future supported by this ClockP
30 * implementation.
31 *
32 * This limit affects ClockP_sleep() */
33 #define ClockP_PERIOD_MAX_SEC 4290U
34
35 /* Get the current ClockP tick value */
36 #define getClockPTick() (HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U) / ClockP_TICK_PERIOD)
37
38 /*
39 * ClockP_STRUCT_SIZE in ClockP.h must be updated to match the size of this
40 * struct
41 */
42 typedef struct _ClockP_Obj
43 {
44 struct k_timer timer;
45 ClockP_Fxn clock_fxn;
46 uintptr_t arg;
47 uint32_t timeout;
48 uint32_t period;
49 bool active;
50 } ClockP_Obj;
51
52 static ClockP_Params ClockP_defaultParams = {
53 .startFlag = false,
54 .period = 0,
55 .arg = 0,
56 };
57
expiry_fxn(struct k_timer * timer_id)58 static void expiry_fxn(struct k_timer *timer_id)
59 {
60 ClockP_Obj *obj = (ClockP_Obj *)k_timer_user_data_get(timer_id);
61
62 obj->clock_fxn(obj->arg);
63 }
64
65 #ifdef CONFIG_DYNAMIC_DPL_OBJECTS
66
67 /* We can't easily dynamically allocate kernel objects so we use memory slabs */
68 #define DPL_MAX_CLOCKS 5
69 K_MEM_SLAB_DEFINE(clock_slab, sizeof(ClockP_Obj), DPL_MAX_CLOCKS,\
70 MEM_ALIGN);
71
dpl_clock_pool_alloc()72 static ClockP_Obj *dpl_clock_pool_alloc()
73 {
74 ClockP_Obj *clock_ptr = NULL;
75
76 if (k_mem_slab_alloc(&clock_slab, (void **)&clock_ptr, K_NO_WAIT) < 0) {
77
78 __ASSERT(0, "Increase size of DPL clock pool");
79 }
80 return clock_ptr;
81 }
82
dpl_clock_pool_free(ClockP_Obj * clock)83 static void dpl_clock_pool_free(ClockP_Obj *clock)
84 {
85 k_mem_slab_free(&clock_slab, (void *)&clock);
86
87 return;
88 }
89
90 /*
91 * ======== ClockP_create ========
92 */
ClockP_create(ClockP_Fxn clkFxn,uint32_t timeout,ClockP_Params * params)93 ClockP_Handle ClockP_create(ClockP_Fxn clkFxn, uint32_t timeout, ClockP_Params *params)
94 {
95 ClockP_Handle handle;
96
97 handle = (ClockP_Handle)dpl_clock_pool_alloc();
98
99 /* ClockP_construct will check handle for NULL, no need here */
100 handle = ClockP_construct((ClockP_Struct *)handle, clkFxn, timeout, params);
101
102 return (handle);
103 }
104
105 /*
106 * ======== ClockP_delete ========
107 */
ClockP_delete(ClockP_Handle handle)108 void ClockP_delete(ClockP_Handle handle)
109 {
110 ClockP_destruct((ClockP_Struct *)handle);
111
112 dpl_clock_pool_free((ClockP_Obj*) handle);
113 }
114
115 #endif /* CONFIG_DYNAMIC_DPL_OBJECTS */
116
117 /*
118 * ======== ClockP_construct ========
119 */
ClockP_construct(ClockP_Struct * handle,ClockP_Fxn clockFxn,uint32_t timeout,ClockP_Params * params)120 ClockP_Handle ClockP_construct(ClockP_Struct *handle, ClockP_Fxn clockFxn, uint32_t timeout, ClockP_Params *params)
121 {
122 ClockP_Obj *obj = (ClockP_Obj *)handle;
123
124 if (handle == NULL)
125 {
126 return NULL;
127 }
128
129 if (params == NULL)
130 {
131 params = &ClockP_defaultParams;
132 }
133
134 obj->clock_fxn = clockFxn;
135 obj->arg = params->arg;
136 obj->period = params->period * ClockP_getSystemTickPeriod() / USEC_PER_MSEC;
137 obj->timeout = timeout;
138 obj->active = false;
139
140 k_timer_init(&obj->timer, expiry_fxn, NULL);
141 k_timer_user_data_set(&obj->timer, obj);
142
143 if (params->startFlag)
144 {
145 ClockP_start(obj);
146 }
147
148 return ((ClockP_Handle)handle);
149 }
150
151 /*
152 * ======== ClockP_getSystemTickPeriod ========
153 */
154 uint32_t ClockP_tickPeriod = (USEC_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC);
ClockP_getSystemTickPeriod()155 uint32_t ClockP_getSystemTickPeriod()
156 {
157 return ClockP_tickPeriod;
158 }
159
ClockP_getSystemTicks()160 uint32_t ClockP_getSystemTicks()
161 {
162 return (uint32_t)k_ms_to_ticks_ceil32(k_uptime_get_32());
163 }
164
165 /*
166 * ======== ClockP_Params_init ========
167 */
ClockP_Params_init(ClockP_Params * params)168 void ClockP_Params_init(ClockP_Params *params)
169 {
170 params->arg = 0;
171 params->startFlag = false;
172 params->period = 0;
173 }
174
175 /*
176 * ======== ClockP_setTimeout ========
177 */
ClockP_setTimeout(ClockP_Handle handle,uint32_t timeout)178 void ClockP_setTimeout(ClockP_Handle handle, uint32_t timeout)
179 {
180 ClockP_Obj *obj = (ClockP_Obj *)handle;
181
182 obj->timeout = timeout;
183 }
184
185 /*
186 * ======== ClockP_start ========
187 */
ClockP_start(ClockP_Handle handle)188 void ClockP_start(ClockP_Handle handle)
189 {
190 ClockP_Obj *obj = (ClockP_Obj *)handle;
191 int32_t timeout;
192 int32_t period;
193
194 __ASSERT_NO_MSG(obj->timeout / CONFIG_SYS_CLOCK_TICKS_PER_SEC <= UINT32_MAX / USEC_PER_MSEC);
195 __ASSERT_NO_MSG(obj->period / CONFIG_SYS_CLOCK_TICKS_PER_SEC <= UINT32_MAX / USEC_PER_MSEC);
196
197 /* Avoid overflow */
198 if (obj->timeout > UINT32_MAX / USEC_PER_MSEC)
199 {
200 timeout = obj->timeout / CONFIG_SYS_CLOCK_TICKS_PER_SEC * USEC_PER_MSEC;
201 }
202 else if ((obj->timeout != 0) && (obj->timeout < CONFIG_SYS_CLOCK_TICKS_PER_SEC / USEC_PER_MSEC))
203 {
204 /* For small timeouts we use 1 msec */
205 timeout = 1;
206 }
207 else
208 {
209 timeout = obj->timeout * USEC_PER_MSEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
210 }
211
212 if (obj->period > UINT32_MAX / USEC_PER_MSEC)
213 {
214 period = obj->period / CONFIG_SYS_CLOCK_TICKS_PER_SEC * USEC_PER_MSEC;
215 }
216 else if ((obj->period != 0) && (obj->period < CONFIG_SYS_CLOCK_TICKS_PER_SEC / USEC_PER_MSEC))
217 {
218 period = 1;
219 }
220 else
221 {
222 period = obj->period * USEC_PER_MSEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
223 }
224
225 k_timer_start(&obj->timer, K_MSEC(timeout), K_MSEC(period));
226
227 obj->active = true;
228 }
229
230 /*
231 * ======== ClockP_stop ========
232 */
ClockP_stop(ClockP_Handle handle)233 void ClockP_stop(ClockP_Handle handle)
234 {
235 ClockP_Obj *obj = (ClockP_Obj *)handle;
236
237 k_timer_stop(&obj->timer);
238 obj->active = false;
239 }
240
241 /*
242 * ======== ClockP_setFunc ========
243 */
ClockP_setFunc(ClockP_Handle handle,ClockP_Fxn clockFxn,uintptr_t arg)244 void ClockP_setFunc(ClockP_Handle handle, ClockP_Fxn clockFxn, uintptr_t arg)
245 {
246 ClockP_Obj *obj = (ClockP_Obj *)handle;
247
248 uintptr_t key = HwiP_disable();
249
250 obj->clock_fxn = clockFxn;
251 obj->arg = arg;
252
253 HwiP_restore(key);
254 }
255
256 /*
257 * ======== ClockP_sleep ========
258 */
ClockP_sleep(uint32_t sec)259 void ClockP_sleep(uint32_t sec)
260 {
261 uint32_t ticksToSleep;
262
263 if (sec > ClockP_PERIOD_MAX_SEC)
264 {
265 sec = ClockP_PERIOD_MAX_SEC;
266 }
267 /* Convert from seconds to number of ticks */
268 ticksToSleep = (sec * USEC_PER_SEC) / ClockP_TICK_PERIOD;
269 k_sleep(K_TICKS(ticksToSleep));
270 }
271
272 /*
273 * ======== ClockP_usleep ========
274 */
ClockP_usleep(uint32_t usec)275 void ClockP_usleep(uint32_t usec)
276 {
277 k_sleep(K_USEC(usec));
278 }
279
280 /*
281 * ======== ClockP_getTimeout ========
282 */
ClockP_getTimeout(ClockP_Handle handle)283 uint32_t ClockP_getTimeout(ClockP_Handle handle)
284 {
285 ClockP_Obj *obj = (ClockP_Obj *)handle;
286 return k_timer_remaining_get(&obj->timer) * CONFIG_SYS_CLOCK_TICKS_PER_SEC / USEC_PER_MSEC;
287 }
288
289 /*
290 * ======== ClockP_isActive ========
291 */
ClockP_isActive(ClockP_Handle handle)292 bool ClockP_isActive(ClockP_Handle handle)
293 {
294 ClockP_Obj *obj = (ClockP_Obj *)handle;
295 return obj->active;
296 }
297
298 /*
299 * ======== ClockP_getCpuFreq ========
300 */
ClockP_getCpuFreq(ClockP_FreqHz * freq)301 void ClockP_getCpuFreq(ClockP_FreqHz *freq)
302 {
303 freq->lo = (uint32_t)CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
304 freq->hi = 0;
305 }
306
ClockP_destruct(ClockP_Struct * clockP)307 void ClockP_destruct(ClockP_Struct *clockP)
308 {
309 ClockP_Obj *obj = (ClockP_Obj *)clockP->data;
310
311 obj->clock_fxn = NULL;
312 obj->arg = 0;
313 obj->period = 0;
314 obj->timeout = 0;
315 obj->active = false;
316
317 k_timer_stop(&obj->timer);
318 }
319