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