1 /*
2 * Copyright (c) 2017-2019, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <stdint.h>
34 #include <stddef.h>
35 #include <stdbool.h>
36
37 #include <ti/drivers/dpl/HwiP.h>
38 #include <ti/drivers/dpl/ClockP.h>
39
40 #include <ti/drivers/capture/CaptureCC32XX.h>
41 #include <ti/drivers/power/PowerCC32XX.h>
42 #include <ti/drivers/timer/TimerCC32XX.h>
43
44 #include <ti/devices/cc32xx/inc/hw_types.h>
45 #include <ti/devices/cc32xx/inc/hw_memmap.h>
46 #include <ti/devices/cc32xx/inc/hw_timer.h>
47 #include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
48 #include <ti/devices/cc32xx/inc/hw_apps_config.h>
49 #include <ti/devices/cc32xx/driverlib/timer.h>
50
51 #define getTimerBaseAddress(config) (TIMERA0_BASE | ((config >> 18) & 0x3000))
52 #define getSubTimer(config) ((config >> 28) & 0x3)
53 #define getTimerIntNum(config) ((config >> 20) & 0xFF)
54 #define getPadOffset(config) ((config >> 4) & 0xFFF)
55 #define getPinMode(config) (config & 0xF)
56 #define getGPIOBaseAddress(config) (GPIOA0_BASE + ((config >> 4) & 0xF000))
57
58 #define PAD_RESET_STATE 0xC61
59
60 void CaptureCC32XX_close(Capture_Handle handle);
61 int_fast16_t CaptureCC32XX_control(Capture_Handle handle,
62 uint_fast16_t cmd, void *arg);
63 void CaptureCC32XX_init(Capture_Handle handle);
64 Capture_Handle CaptureCC32XX_open(Capture_Handle handle, Capture_Params *params);
65 int32_t CaptureCC32XX_start(Capture_Handle handle);
66 void CaptureCC32XX_stop(Capture_Handle handle);
67
68 /* Internal static Functions */
69 static void CaptureCC32XX_hwiIntFunction(uintptr_t arg);
70 static uint32_t getPowerMgrId(uint32_t baseAddress);
71 static void initHw(Capture_Handle handle);
72 static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
73 uintptr_t clientArg);
74
75 /* System Clock Frequency */
76 static ClockP_FreqHz clockFreq;
77
78 /* Function table for CaptureCC32XX implementation */
79 const Capture_FxnTable CaptureCC32XX_fxnTable = {
80 .closeFxn = CaptureCC32XX_close,
81 .openFxn = CaptureCC32XX_open,
82 .startFxn = CaptureCC32XX_start,
83 .stopFxn = CaptureCC32XX_stop,
84 .initFxn = CaptureCC32XX_init,
85 .controlFxn = CaptureCC32XX_control
86 };
87
88 /*
89 * ======== CaptureCC32XX_close ========
90 */
CaptureCC32XX_close(Capture_Handle handle)91 void CaptureCC32XX_close(Capture_Handle handle)
92 {
93 CaptureCC32XX_Object *object = handle->object;
94 CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
95 TimerCC32XX_SubTimer subTimer;
96 uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
97
98 subTimer = (TimerCC32XX_SubTimer) getSubTimer(hwAttrs->capturePin);
99
100 CaptureCC32XX_stop(handle);
101
102 Power_unregisterNotify(&(object->notifyObj));
103 Power_releaseDependency(getPowerMgrId(getGPIOBaseAddress(hwAttrs->capturePin)));
104
105 if (object->hwiHandle) {
106
107 HwiP_delete(object->hwiHandle);
108 object->hwiHandle = NULL;
109 }
110
111 TimerCC32XX_freeTimerResource(baseAddress, subTimer);
112
113 /* Restore the GPIO pad to its reset state */
114 HWREG(OCP_SHARED_BASE + getPadOffset(hwAttrs->capturePin))
115 = PAD_RESET_STATE;
116 }
117
118 /*
119 * ======== CaptureCC32XX_control ========
120 */
CaptureCC32XX_control(Capture_Handle handle,uint_fast16_t cmd,void * arg)121 int_fast16_t CaptureCC32XX_control(Capture_Handle handle,
122 uint_fast16_t cmd, void *arg)
123 {
124 return (Capture_STATUS_UNDEFINEDCMD);
125 }
126
127 /*
128 * ======== CaptureCC32XX_hwiIntFunction ========
129 */
CaptureCC32XX_hwiIntFunction(uintptr_t arg)130 void CaptureCC32XX_hwiIntFunction(uintptr_t arg)
131 {
132 Capture_Handle handle = (Capture_Handle) arg;
133 CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
134 CaptureCC32XX_Object *object = handle->object;
135 uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
136 uint32_t interruptMask;
137 uint32_t interval, currentCount;
138
139 /* Read the TXR register */
140 currentCount = TimerValueGet(baseAddress, object->timer);
141
142 /* Calculate the interval */
143 if (currentCount < object->previousCount) {
144
145 /* Calculate the difference if the timer rolled over */
146 interval = currentCount + (0xFFFFFF - object->previousCount);
147 }
148 else if (currentCount > object->previousCount) {
149
150 interval = currentCount - object->previousCount - 1;
151 }
152 else {
153 interval = 1;
154 }
155
156 /* Store the interval for the next interrupt */
157 object->previousCount = currentCount;
158
159 /* Compensate for prescale register roll-over hardware issue */
160 interval = interval - (interval / 0xFFFF);
161
162 /* Clear the interrupts used by this driver instance */
163 interruptMask = object->timer & (TIMER_CAPB_EVENT | TIMER_CAPA_EVENT);
164 TimerIntClear(baseAddress, interruptMask);
165
166 /* Need to convert the interval to periodUnits if microseconds or hertz */
167 if (object->periodUnits == Capture_PERIOD_US) {
168
169 interval = interval / (clockFreq.lo / 1000000);
170 }
171 else if (object->periodUnits == Capture_PERIOD_HZ) {
172
173 interval = clockFreq.lo / interval;
174 }
175
176 /* Call the user callbackFxn */
177 object->callBack(handle, interval, Capture_STATUS_SUCCESS);
178 }
179
180 /*
181 * ======== CaptureCC32XX_init ========
182 */
CaptureCC32XX_init(Capture_Handle handle)183 void CaptureCC32XX_init(Capture_Handle handle)
184 {
185 return;
186 }
187
188 /*
189 * ======== CaptureCC32XX_open ========
190 */
CaptureCC32XX_open(Capture_Handle handle,Capture_Params * params)191 Capture_Handle CaptureCC32XX_open(Capture_Handle handle, Capture_Params *params)
192 {
193 CaptureCC32XX_Object *object = handle->object;
194 CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
195 HwiP_Params hwiParams;
196 uint32_t powerId;
197
198 /* Check parameters. This driver requires a callback function. */
199 if (params == NULL ||
200 params->callbackFxn == NULL) {
201
202 return (NULL);
203 }
204
205 /* Set the mode */
206 if (params->mode == Capture_RISING_EDGE) {
207
208 object->mode = TIMER_EVENT_POS_EDGE;
209 }
210 else if (params->mode == Capture_FALLING_EDGE) {
211
212 object->mode = TIMER_EVENT_NEG_EDGE;
213 }
214 else if (params->mode == Capture_ANY_EDGE) {
215
216 object->mode = TIMER_EVENT_BOTH_EDGES;
217 }
218 else {
219 /* Fail if Capture mode is not supported by device*/
220 return (NULL);
221 }
222
223 powerId = getPowerMgrId(getGPIOBaseAddress(hwAttrs->capturePin));
224
225 if (powerId == (uint32_t) -1) {
226
227 return (NULL);
228 }
229
230 /* Attempt to allocate timer hardware resource */
231 if (!TimerCC32XX_allocateTimerResource(getTimerBaseAddress(hwAttrs->capturePin),
232 (TimerCC32XX_SubTimer) getSubTimer(hwAttrs->capturePin))) {
233
234 return (NULL);
235 }
236
237 /* Turn on Power to the GPIO */
238 Power_setDependency(powerId);
239
240 /* Function to re-initialize the timer after a low-power event */
241 Power_registerNotify(&(object->notifyObj), PowerCC32XX_AWAKE_LPDS,
242 postNotifyFxn, (uintptr_t) handle);
243
244 /* Determine which timer half will be used. */
245 if (getSubTimer(hwAttrs->capturePin) == TimerCC32XX_timer16A) {
246
247 object->timer = TIMER_A;
248 }
249 else {
250
251 object->timer = TIMER_B;
252 }
253
254 object->isRunning = false;
255 object->callBack = params->callbackFxn;
256 object->periodUnits = params->periodUnit;
257
258 /* Setup the hardware interrupt function to handle timer interrupts */
259 HwiP_Params_init(&hwiParams);
260 hwiParams.arg = (uintptr_t) handle;
261 hwiParams.priority = hwAttrs->intPriority;
262
263 object->hwiHandle = HwiP_create(getTimerIntNum(hwAttrs->capturePin),
264 CaptureCC32XX_hwiIntFunction, &hwiParams);
265
266 if (object->hwiHandle == NULL) {
267
268 CaptureCC32XX_close(handle);
269
270 return (NULL);
271 }
272
273 /* Static global storing the CPU frequency */
274 ClockP_getCpuFreq(&clockFreq);
275
276 /* Initialize the timer hardware */
277 initHw(handle);
278
279 return (handle);
280 }
281
282 /*
283 * ======== CaptureCC32XX_start ========
284 */
CaptureCC32XX_start(Capture_Handle handle)285 int32_t CaptureCC32XX_start(Capture_Handle handle)
286 {
287 CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
288 CaptureCC32XX_Object *object = handle->object;
289 uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
290 uint32_t interruptMask;
291 uintptr_t key;
292
293 interruptMask = object->timer & (TIMER_CAPB_EVENT | TIMER_CAPA_EVENT);
294
295 key = HwiP_disable();
296
297 if (object->isRunning) {
298
299 HwiP_restore(key);
300
301 return (Capture_STATUS_ERROR);
302 }
303
304 object->isRunning = true;
305 object->previousCount = 0;
306
307 Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
308
309 TimerIntClear(baseAddress, interruptMask);
310 TimerIntEnable(baseAddress, interruptMask);
311 TimerValueSet(baseAddress, object->timer, 0);
312 TimerEnable(baseAddress, object->timer);
313
314 HwiP_restore(key);
315
316 return (Capture_STATUS_SUCCESS);
317 }
318
319 /*
320 * ======== CaptureCC32XX_stop ========
321 */
CaptureCC32XX_stop(Capture_Handle handle)322 void CaptureCC32XX_stop(Capture_Handle handle)
323 {
324 CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
325 CaptureCC32XX_Object *object = handle->object;
326 uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
327 uint32_t interruptMask;
328 uintptr_t key;
329
330 interruptMask = object->timer & (TIMER_CAPB_EVENT | TIMER_CAPA_EVENT);
331
332 key = HwiP_disable();
333
334 if (object->isRunning) {
335
336 object->isRunning = false;
337
338 TimerDisable(baseAddress, object->timer);
339 TimerIntDisable(baseAddress, interruptMask);
340 Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
341 }
342
343 HwiP_restore(key);
344 }
345
346
347 /*
348 * ======== getPowerMgrId ========
349 */
getPowerMgrId(uint32_t baseAddress)350 static uint32_t getPowerMgrId(uint32_t baseAddress)
351 {
352 switch (baseAddress) {
353
354 case GPIOA0_BASE:
355
356 return (PowerCC32XX_PERIPH_GPIOA0);
357
358 case GPIOA1_BASE:
359
360 return (PowerCC32XX_PERIPH_GPIOA1);
361
362 case GPIOA2_BASE:
363
364 return (PowerCC32XX_PERIPH_GPIOA2);
365
366 case GPIOA3_BASE:
367
368 return (PowerCC32XX_PERIPH_GPIOA3);
369
370 case GPIOA4_BASE:
371
372 return (PowerCC32XX_PERIPH_GPIOA4);
373
374 default:
375
376 return ((uint32_t) -1);
377 }
378 }
379
380 /*
381 * ======== initHw ========
382 */
initHw(Capture_Handle handle)383 static void initHw(Capture_Handle handle)
384 {
385 CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
386 CaptureCC32XX_Object const *object = handle->object;
387 uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
388 uintptr_t key;
389
390 /* Enable external GPT trigger */
391 HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_GPT_TRIG_SEL) = 0xFF;
392
393 /* Route the GPIO pad for capture usage */
394 HWREG(OCP_SHARED_BASE + getPadOffset(hwAttrs->capturePin))
395 = getPinMode(hwAttrs->capturePin);
396
397 /* Read/Write modifications for shared registers */
398 key = HwiP_disable();
399
400 /* Disable the timer */
401 TimerDisable(baseAddress, object->timer);
402
403 /* Set trigger event for the capture pin */
404 TimerControlEvent(baseAddress, object->timer, object->mode);
405
406 /* This function controls the stall response for the timer. When true,
407 * the timer stops counting if the processor is halted. The
408 * default setting for the hardware is false.
409 */
410 TimerControlStall(baseAddress, object->timer, true);
411
412 HwiP_restore(key);
413
414 /* Configure in 16-bit mode */
415 HWREG(baseAddress + TIMER_O_CFG) = TIMER_CFG_16_BIT;
416
417 /* Configure in capture time edge mode, counting up */
418 if (object->timer == TIMER_A) {
419
420 HWREG(baseAddress + TIMER_O_TAMR) = TIMER_CFG_A_CAP_TIME_UP;
421 }
422 else {
423
424 HWREG(baseAddress + TIMER_O_TBMR) = TIMER_CFG_A_CAP_TIME_UP;
425 }
426 }
427
428 /*
429 * ======== postNotifyFxn ========
430 * This function is called when a transition from LPDS mode is made.
431 * clientArg should be a handle of a previously opened Timer instance.
432 */
postNotifyFxn(unsigned int eventType,uintptr_t eventArg,uintptr_t clientArg)433 static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
434 uintptr_t clientArg)
435 {
436 initHw((Capture_Handle) clientArg);
437
438 return (Power_NOTIFYDONE);
439 }
440