1 /*
2  * Copyright (c) 2017, Texas Instruments Incorporated
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr.h>
8 #include <sys/__assert.h>
9 #include <kernel/zephyr/dpl/dpl.h>
10 #include <ti/drivers/dpl/ClockP.h>
11 
12 #include "stubs.h"
13 
14 /*
15  * ClockP_STRUCT_SIZE in ClockP.h must be updated to match the size of this
16  * struct
17  */
18 typedef struct _ClockP_Obj {
19 	struct k_timer timer;
20 	ClockP_Fxn clock_fxn;
21 	uintptr_t arg;
22 	uint32_t timeout;
23 	uint32_t period;
24 	bool active;
25 } ClockP_Obj;
26 
27 static ClockP_Params ClockP_defaultParams = {
28     .startFlag = false,
29     .period = 0,
30     .arg = 0,
31 };
32 
expiry_fxn(struct k_timer * timer_id)33 static void expiry_fxn(struct k_timer *timer_id)
34 {
35 	ClockP_Obj *obj = (ClockP_Obj *)k_timer_user_data_get(timer_id);
36 
37 	obj->clock_fxn(obj->arg);
38 }
39 
40 /*
41  *  ======== ClockP_construct ========
42  */
ClockP_construct(ClockP_Struct * handle,ClockP_Fxn clockFxn,uint32_t timeout,ClockP_Params * params)43 ClockP_Handle ClockP_construct(ClockP_Struct *handle, ClockP_Fxn clockFxn,
44         uint32_t timeout, ClockP_Params *params)
45 {
46 	ClockP_Obj *obj = (ClockP_Obj *)handle;
47 
48 	if (handle == NULL) {
49 		return NULL;
50 	}
51 
52 	if (params == NULL) {
53 		params = &ClockP_defaultParams;
54 	}
55 
56 	obj->clock_fxn = clockFxn;
57 	obj->arg = params->arg;
58 	obj->period = params->period * ClockP_getSystemTickPeriod() / 1000;
59 	obj->timeout = timeout;
60 	obj->active = false;
61 
62 	k_timer_init(&obj->timer, expiry_fxn, NULL);
63 	k_timer_user_data_set(&obj->timer, obj);
64 
65 	if (params->startFlag) {
66 		ClockP_start(obj);
67 	}
68 
69 	return  ((ClockP_Handle)handle);
70 }
71 
72 /*
73  *  ======== ClockP_getSystemTickPeriod ========
74  */
75 uint32_t ClockP_tickPeriod = (1000000 / CONFIG_SYS_CLOCK_TICKS_PER_SEC);
ClockP_getSystemTickPeriod()76 uint32_t ClockP_getSystemTickPeriod()
77 {
78    return ClockP_tickPeriod;
79 }
80 
ClockP_getSystemTicks()81 uint32_t ClockP_getSystemTicks()
82 {
83 	return (uint32_t)k_ms_to_ticks_ceil32(k_uptime_get_32());
84 }
85 
86 /*
87  *  ======== ClockP_Params_init ========
88  */
ClockP_Params_init(ClockP_Params * params)89 void ClockP_Params_init(ClockP_Params *params)
90 {
91 	params->arg = 0;
92 	params->startFlag = false;
93 	params->period = 0;
94 }
95 
96 /*
97  *  ======== ClockP_setTimeout ========
98  */
ClockP_setTimeout(ClockP_Handle handle,uint32_t timeout)99 void ClockP_setTimeout(ClockP_Handle handle, uint32_t timeout)
100 {
101 	ClockP_Obj *obj = (ClockP_Obj *)handle;
102 
103 	obj->timeout = timeout;
104 }
105 
106 /*
107  *  ======== ClockP_start ========
108  */
ClockP_start(ClockP_Handle handle)109 void ClockP_start(ClockP_Handle handle)
110 {
111 	ClockP_Obj *obj = (ClockP_Obj *)handle;
112 	int32_t timeout;
113 	int32_t period;
114 
115 	__ASSERT_NO_MSG(obj->timeout /
116 		CONFIG_SYS_CLOCK_TICKS_PER_SEC <= UINT32_MAX / 1000);
117 	__ASSERT_NO_MSG(obj->period /
118 		CONFIG_SYS_CLOCK_TICKS_PER_SEC <= UINT32_MAX / 1000);
119 
120 	/* Avoid overflow */
121 	if (obj->timeout > UINT32_MAX / 1000) {
122 		timeout = obj->timeout / CONFIG_SYS_CLOCK_TICKS_PER_SEC * 1000;
123 	} else if ((obj->timeout != 0) &&
124 		(obj->timeout < CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000)) {
125 		/* For small timeouts we use 1 msec */
126 		timeout = 1;
127 	} else {
128 		timeout = obj->timeout * 1000 / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
129 	}
130 
131 	if (obj->period > UINT32_MAX / 1000) {
132 		period = obj->period / CONFIG_SYS_CLOCK_TICKS_PER_SEC * 1000;
133 	} else if ((obj->period != 0) &&
134 		(obj->period < CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000)) {
135 		period = 1;
136 	} else {
137 		period = obj->period * 1000 / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
138 	}
139 
140 	k_timer_start(&obj->timer, K_MSEC(timeout), K_MSEC(period));
141 
142     obj->active = true;
143 }
144 
145 /*
146  *  ======== ClockP_stop ========
147  */
ClockP_stop(ClockP_Handle handle)148 void ClockP_stop(ClockP_Handle handle)
149 {
150 	ClockP_Obj *obj = (ClockP_Obj *)handle;
151 
152 	k_timer_stop(&obj->timer);
153 	obj->active = false;
154 }
155 
156 /*
157  *  ======== ClockP_usleep ========
158  */
ClockP_usleep(uint32_t usec)159 void ClockP_usleep(uint32_t usec)
160 {
161 	k_sleep(K_USEC(usec));
162 }
163 
164 /*
165  *  ======== ClockP_getTimeout ========
166  */
ClockP_getTimeout(ClockP_Handle handle)167 uint32_t ClockP_getTimeout(ClockP_Handle handle) {
168     ClockP_Obj *obj = (ClockP_Obj *)handle;
169     return k_timer_remaining_get(&obj->timer) * CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000;
170 }
171 
172 /*
173  *  ======== ClockP_isActive ========
174  */
ClockP_isActive(ClockP_Handle handle)175 bool ClockP_isActive(ClockP_Handle handle) {
176     ClockP_Obj *obj = (ClockP_Obj *)handle;
177     return obj->active;
178 }
179 
ClockP_destruct(ClockP_Struct * clockP)180 void ClockP_destruct(ClockP_Struct *clockP)
181 {
182 	ClockP_Obj *obj = (ClockP_Obj *)clockP->data;
183 
184 	obj->clock_fxn = NULL;
185 	obj->arg = 0;
186 	obj->period = 0;
187 	obj->timeout = 0;
188 	obj->active = false;
189 
190 	k_timer_stop(&obj->timer);
191 }
192