blob: 4128a63e20d6991b65307c3d17e33e093f86f2dc [file] [log] [blame]
/*
* Copyright (c) 2017, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <ti/drivers/dpl/HwiP.h>
#include <ti/drivers/dpl/ClockP.h>
#include <ti/drivers/capture/CaptureCC32XX.h>
#include <ti/drivers/power/PowerCC32XX.h>
#include <ti/drivers/timer/TimerCC32XX.h>
#include <ti/devices/cc32xx/inc/hw_types.h>
#include <ti/devices/cc32xx/inc/hw_memmap.h>
#include <ti/devices/cc32xx/inc/hw_timer.h>
#include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
#include <ti/devices/cc32xx/inc/hw_apps_config.h>
#include <ti/devices/cc32xx/driverlib/timer.h>
#define getTimerBaseAddress(config) (TIMERA0_BASE | ((config >> 18) & 0x3000))
#define getSubTimer(config) ((config >> 28) & 0x3)
#define getTimerIntNum(config) ((config >> 20) & 0xFF)
#define getPadOffset(config) ((config >> 4) & 0xFFF)
#define getPinMode(config) (config & 0xF)
#define getGPIOBaseAddress(config) (GPIOA0_BASE + ((config >> 4) & 0xF000))
#define PAD_RESET_STATE 0xC61
void CaptureCC32XX_close(Capture_Handle handle);
int_fast16_t CaptureCC32XX_control(Capture_Handle handle,
uint_fast16_t cmd, void *arg);
void CaptureCC32XX_init(Capture_Handle handle);
Capture_Handle CaptureCC32XX_open(Capture_Handle handle, Capture_Params *params);
int32_t CaptureCC32XX_start(Capture_Handle handle);
void CaptureCC32XX_stop(Capture_Handle handle);
/* Internal static Functions */
static void CaptureCC32XX_hwiIntFunction(uintptr_t arg);
static uint32_t getPowerMgrId(uint32_t baseAddress);
static void initHw(Capture_Handle handle);
static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
uintptr_t clientArg);
/* System Clock Frequency */
static ClockP_FreqHz clockFreq;
/* Function table for CaptureCC32XX implementation */
const Capture_FxnTable CaptureCC32XX_fxnTable = {
.closeFxn = CaptureCC32XX_close,
.openFxn = CaptureCC32XX_open,
.startFxn = CaptureCC32XX_start,
.stopFxn = CaptureCC32XX_stop,
.initFxn = CaptureCC32XX_init,
.controlFxn = CaptureCC32XX_control
};
/*
* ======== CaptureCC32XX_close ========
*/
void CaptureCC32XX_close(Capture_Handle handle)
{
CaptureCC32XX_Object *object = handle->object;
CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
TimerCC32XX_SubTimer subTimer;
uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
subTimer = (TimerCC32XX_SubTimer) getSubTimer(hwAttrs->capturePin);
CaptureCC32XX_stop(handle);
Power_unregisterNotify(&(object->notifyObj));
Power_releaseDependency(getPowerMgrId(getGPIOBaseAddress(hwAttrs->capturePin)));
if (object->hwiHandle) {
HwiP_delete(object->hwiHandle);
object->hwiHandle = NULL;
}
TimerCC32XX_freeTimerResource(baseAddress, subTimer);
/* Restore the GPIO pad to its reset state */
HWREG(OCP_SHARED_BASE + getPadOffset(hwAttrs->capturePin))
= PAD_RESET_STATE;
}
/*
* ======== CaptureCC32XX_control ========
*/
int_fast16_t CaptureCC32XX_control(Capture_Handle handle,
uint_fast16_t cmd, void *arg)
{
return (Capture_STATUS_UNDEFINEDCMD);
}
/*
* ======== CaptureCC32XX_hwiIntFunction ========
*/
void CaptureCC32XX_hwiIntFunction(uintptr_t arg)
{
Capture_Handle handle = (Capture_Handle) arg;
CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
CaptureCC32XX_Object *object = handle->object;
uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
uint32_t interruptMask;
uint32_t interval, currentCount;
/* Read the TXR register */
currentCount = TimerValueGet(baseAddress, object->timer);
/* Calculate the interval */
if (currentCount < object->previousCount) {
/* Calculate the difference if the timer rolled over */
interval = currentCount + (0xFFFFFF - object->previousCount);
}
else if (currentCount > object->previousCount) {
interval = currentCount - object->previousCount - 1;
}
else {
interval = 1;
}
/* Store the interval for the next interrupt */
object->previousCount = currentCount;
/* Compensate for prescale register roll-over hardware issue */
interval = interval - (interval / 0xFFFF);
/* Clear the interrupts used by this driver instance */
interruptMask = object->timer & (TIMER_CAPB_EVENT | TIMER_CAPA_EVENT);
TimerIntClear(baseAddress, interruptMask);
/* Need to convert the interval to periodUnits if microseconds or hertz */
if (object->periodUnits == Capture_PERIOD_US) {
interval = interval / (clockFreq.lo / 1000000);
}
else if (object->periodUnits == Capture_PERIOD_HZ) {
interval = clockFreq.lo / interval;
}
/* Call the user callbackFxn */
object->callBack(handle, interval);
}
/*
* ======== CaptureCC32XX_init ========
*/
void CaptureCC32XX_init(Capture_Handle handle)
{
return;
}
/*
* ======== CaptureCC32XX_open ========
*/
Capture_Handle CaptureCC32XX_open(Capture_Handle handle, Capture_Params *params)
{
CaptureCC32XX_Object *object = handle->object;
CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
HwiP_Params hwiParams;
uint32_t powerId;
/* Check parameters. This driver requires a callback function. */
if (params == NULL ||
params->callbackFxn == NULL) {
return (NULL);
}
powerId = getPowerMgrId(getGPIOBaseAddress(hwAttrs->capturePin));
if (powerId == (uint32_t) -1) {
return (NULL);
}
/* Attempt to allocate timer hardware resource */
if (!TimerCC32XX_allocateTimerResource(getTimerBaseAddress(hwAttrs->capturePin),
(TimerCC32XX_SubTimer) getSubTimer(hwAttrs->capturePin))) {
return (NULL);
}
/* Turn on Power to the GPIO */
Power_setDependency(powerId);
/* Function to re-initialize the timer after a low-power event */
Power_registerNotify(&(object->notifyObj), PowerCC32XX_AWAKE_LPDS,
postNotifyFxn, (uintptr_t) handle);
/* Determine which timer half will be used. */
if (getSubTimer(hwAttrs->capturePin) == TimerCC32XX_timer16A) {
object->timer = TIMER_A;
}
else {
object->timer = TIMER_B;
}
/* Set the mode */
if (params->mode == Capture_RISING_EDGE) {
object->mode = TIMER_EVENT_POS_EDGE;
}
else if (params->mode == Capture_FALLING_EDGE) {
object->mode = TIMER_EVENT_NEG_EDGE;
}
else {
object->mode = TIMER_EVENT_BOTH_EDGES;
}
object->isRunning = false;
object->callBack = params->callbackFxn;
object->periodUnits = params->periodUnit;
/* Setup the hardware interrupt function to handle timer interrupts */
HwiP_Params_init(&hwiParams);
hwiParams.arg = (uintptr_t) handle;
hwiParams.priority = hwAttrs->intPriority;
object->hwiHandle = HwiP_create(getTimerIntNum(hwAttrs->capturePin),
CaptureCC32XX_hwiIntFunction, &hwiParams);
if (object->hwiHandle == NULL) {
CaptureCC32XX_close(handle);
return (NULL);
}
/* Static global storing the CPU frequency */
ClockP_getCpuFreq(&clockFreq);
/* Initialize the timer hardware */
initHw(handle);
return (handle);
}
/*
* ======== CaptureCC32XX_start ========
*/
int32_t CaptureCC32XX_start(Capture_Handle handle)
{
CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
CaptureCC32XX_Object *object = handle->object;
uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
uint32_t interruptMask;
uintptr_t key;
interruptMask = object->timer & (TIMER_CAPB_EVENT | TIMER_CAPA_EVENT);
key = HwiP_disable();
if (object->isRunning) {
HwiP_restore(key);
return (Capture_STATUS_ERROR);
}
object->isRunning = true;
object->previousCount = 0;
Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
TimerIntClear(baseAddress, interruptMask);
TimerIntEnable(baseAddress, interruptMask);
TimerValueSet(baseAddress, object->timer, 0);
TimerEnable(baseAddress, object->timer);
HwiP_restore(key);
return (Capture_STATUS_SUCCESS);
}
/*
* ======== CaptureCC32XX_stop ========
*/
void CaptureCC32XX_stop(Capture_Handle handle)
{
CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
CaptureCC32XX_Object *object = handle->object;
uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
uint32_t interruptMask;
uintptr_t key;
interruptMask = object->timer & (TIMER_CAPB_EVENT | TIMER_CAPA_EVENT);
key = HwiP_disable();
if (object->isRunning) {
object->isRunning = false;
TimerDisable(baseAddress, object->timer);
TimerIntDisable(baseAddress, interruptMask);
Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
}
HwiP_restore(key);
}
/*
* ======== getPowerMgrId ========
*/
static uint32_t getPowerMgrId(uint32_t baseAddress)
{
switch (baseAddress) {
case GPIOA0_BASE:
return (PowerCC32XX_PERIPH_GPIOA0);
case GPIOA1_BASE:
return (PowerCC32XX_PERIPH_GPIOA1);
case GPIOA2_BASE:
return (PowerCC32XX_PERIPH_GPIOA2);
case GPIOA3_BASE:
return (PowerCC32XX_PERIPH_GPIOA3);
case GPIOA4_BASE:
return (PowerCC32XX_PERIPH_GPIOA4);
default:
return ((uint32_t) -1);
}
}
/*
* ======== initHw ========
*/
static void initHw(Capture_Handle handle)
{
CaptureCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
CaptureCC32XX_Object const *object = handle->object;
uint32_t baseAddress = getTimerBaseAddress(hwAttrs->capturePin);
uintptr_t key;
/* Enable external GPT trigger */
HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_GPT_TRIG_SEL) = 0xFF;
/* Route the GPIO pad for capture usage */
HWREG(OCP_SHARED_BASE + getPadOffset(hwAttrs->capturePin))
= getPinMode(hwAttrs->capturePin);
/* Read/Write modifications for shared registers */
key = HwiP_disable();
/* Disable the timer */
TimerDisable(baseAddress, object->timer);
/* Set trigger event for the capture pin */
TimerControlEvent(baseAddress, object->timer, object->mode);
/* This function controls the stall response for the timer. When true,
* the timer stops counting if the processor is halted. The
* default setting for the hardware is false.
*/
TimerControlStall(baseAddress, object->timer, true);
HwiP_restore(key);
/* Configure in 16-bit mode */
HWREG(baseAddress + TIMER_O_CFG) = TIMER_CFG_16_BIT;
/* Configure in capture time edge mode, counting up */
if (object->timer == TIMER_A) {
HWREG(baseAddress + TIMER_O_TAMR) = TIMER_CFG_A_CAP_TIME_UP;
}
else {
HWREG(baseAddress + TIMER_O_TBMR) = TIMER_CFG_A_CAP_TIME_UP;
}
}
/*
* ======== postNotifyFxn ========
* This function is called when a transition from LPDS mode is made.
* clientArg should be a handle of a previously opened Timer instance.
*/
static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
uintptr_t clientArg)
{
initHw((Capture_Handle) clientArg);
return (Power_NOTIFYDONE);
}