nuttx/arch/arm/src/phy62xx/phyplus_tim.c
Xiang Xiao bdeaea3742 Remove the unnessary empty line after label
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2022-09-30 17:54:56 +02:00

560 lines
14 KiB
C

/****************************************************************************
* arch/arm/src/phy62xx/phyplus_tim.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include "phyplus_tim.h"
#include "mcu_phy_bumbee.h"
#include "arm_internal.h"
struct phyplus_tim_priv_s
{
const struct phyplus_tim_ops_s *ops;
uint32_t base; /* Timer register base address */
bool inuse; /* Flag indicating if the timer is in use */
/* AP_TIM_TypeDef *timer; */
};
/****************************************************************************
* Private Function prototypes
****************************************************************************/
/* static int phyplus_tim_checkint(struct phyplus_tim_dev_s *dev,
* int source);
*/
/****************************************************************************
* Private Data
****************************************************************************/
struct phyplus_tim_ops_s phyplus_tim_ops =
{
.start = phyplus_tim_start,
.stop = phyplus_tim_stop,
.clear = phyplus_tim_clear,
.setmode = phyplus_tim_setmode,
.getcounter = phyplus_tim_getcounter,
.setcounter = phyplus_tim_setcounter,
.setisr = phyplus_tim_setisr,
.enableint = phyplus_tim_enableint,
.disableint = phyplus_tim_disableint,
.ackint = phyplus_tim_ackint,
/* .checkint = phyplus_tim_checkint */
};
/* #ifdef CONFIG_PHYPLUS_TIM1 */
struct phyplus_tim_priv_s phyplus_tim1_priv =
{
.ops = &phyplus_tim_ops,
.base = (long unsigned int)AP_TIM1,
.inuse = false,
};
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM2 */
struct phyplus_tim_priv_s phyplus_tim2_priv =
{
.ops = &phyplus_tim_ops,
.base = (long unsigned int)AP_TIM2,
.inuse = false,
};
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM3 */
struct phyplus_tim_priv_s phyplus_tim3_priv =
{
.ops = &phyplus_tim_ops,
.base = (long unsigned int)AP_TIM3,
.inuse = false,
};
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM4 */
struct phyplus_tim_priv_s phyplus_tim4_priv =
{
.ops = &phyplus_tim_ops,
.base = (long unsigned int)AP_TIM4,
.inuse = false,
};
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM5 */
struct phyplus_tim_priv_s phyplus_tim5_priv =
{
.ops = &phyplus_tim_ops,
.base = (long unsigned int)AP_TIM5,
.inuse = false,
};
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM6 */
struct phyplus_tim_priv_s phyplus_tim6_priv =
{
.ops = &phyplus_tim_ops,
.base = (long unsigned int)AP_TIM6,
.inuse = false,
};
/* #endif */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: phyplus_tim_getreg32
*
* Description:
* Get a 32-bit register value by offset
*
****************************************************************************/
uint32_t phyplus_tim_getreg32(struct phyplus_tim_dev_s *dev,
uint32_t offset)
{
DEBUGASSERT(dev);
return getreg32(((struct phyplus_tim_priv_s *)dev)->base + offset);
}
/****************************************************************************
* Name: phyplus_tim_putreg32
*
* Description:
* Put a 32-bit register value by offset
*
****************************************************************************/
void phyplus_tim_putreg32(struct phyplus_tim_dev_s *dev,
uint32_t offset,
uint32_t value)
{
DEBUGASSERT(dev);
putreg32(value, ((struct phyplus_tim_priv_s *)dev)->base + offset);
}
/****************************************************************************
* Name: phyplus_tim_modifyreg32
*
* Description:
* Modify a reg of 32 bits
*
****************************************************************************/
void phyplus_tim_modifyreg32(struct phyplus_tim_dev_s *dev,
uint32_t offset,
uint32_t clearbits,
uint32_t setbits)
{
DEBUGASSERT(dev);
modifyreg32(((struct phyplus_tim_priv_s *)dev)->base + offset,
clearbits, setbits);
}
/****************************************************************************
* Name: phyplus_tim_start
*
* Description:
* Releases the counter
*
****************************************************************************/
void phyplus_tim_start(struct phyplus_tim_dev_s *dev)
{
syslog(LOG_ERR, "timer_enable\n");
DEBUGASSERT(dev);
phyplus_tim_modifyreg32(dev, TIM_CONTROLREG_OFFSET, 0, TIM_ENABLE);
}
/****************************************************************************
* Name: phyplus_tim_stop
*
* Description:
* Halts the counter
*
****************************************************************************/
void phyplus_tim_stop(struct phyplus_tim_dev_s *dev)
{
syslog(LOG_ERR, "timer_disable\n");
DEBUGASSERT(dev);
phyplus_tim_modifyreg32(dev, TIM_CONTROLREG_OFFSET, TIM_ENABLE, 0);
}
/****************************************************************************
* Name: phyplus_tim_clear
*
* Description:
* Set the counter to zero instantly
*
****************************************************************************/
void phyplus_tim_clear(struct phyplus_tim_dev_s *dev)
{
uint32_t clear_value = 0;
DEBUGASSERT(dev);
phyplus_tim_setcounter(dev, clear_value);
phyplus_tim_getreg32(dev, TIM_EOI_OFFSET); /* clear the timer. */
}
/****************************************************************************
* Name: phyplus_tim_setmode
*
* Description:
* Set counter mode (up/down)
*
****************************************************************************/
void phyplus_tim_setmode(struct phyplus_tim_dev_s *dev,
phyplus_tim_mode_t mode)
{
DEBUGASSERT(dev);
if (mode == PHYPLUS_TIM_FREERUN)
{
phyplus_tim_modifyreg32(dev, TIM_CONTROLREG_OFFSET, TIM_MODE, 0);
}
else if (mode == PHYPLUS_TIM_COUNT)
{
phyplus_tim_modifyreg32(dev, TIM_CONTROLREG_OFFSET, 0, TIM_MODE);
}
}
/****************************************************************************
* Name: phyplus_tim_getcounter
*
* Description:
* Get the current counter value
*
****************************************************************************/
void phyplus_tim_getcounter(struct phyplus_tim_dev_s *dev,
uint32_t *value)
{
DEBUGASSERT(dev);
*value = phyplus_tim_getreg32(dev, TIM_COUNT_OFFSET);
}
/****************************************************************************
* Name: phyplus_tim_setcounter
*
* Description:
* Set the value to be loaded to the counter
* If you want the counter to be loaded at an alarm, enable the alarm and
* the auto-reload before.
*
****************************************************************************/
void phyplus_tim_setcounter(struct phyplus_tim_dev_s *dev,
uint32_t value)
{
DEBUGASSERT(dev);
phyplus_tim_putreg32(dev, TIM_COUNT_OFFSET, (uint32_t)value);
}
void phyplus_tim_getcurrent(struct phyplus_tim_dev_s *dev,
uint32_t *value)
{
DEBUGASSERT(dev);
*value = phyplus_tim_getreg32(dev, TIM_CURRENT_OFFSET);
}
void phyplus_tim_getcontrolreg(struct phyplus_tim_dev_s *dev,
uint32_t *value)
{
DEBUGASSERT(dev);
*value = phyplus_tim_getreg32(dev, TIM_CONTROLREG_OFFSET);
}
/****************************************************************************
* Name: phyplus_tim_setisr
*
* Description:
* Allocates a level CPU Interrupt, connects the peripheral source to this
* Interrupt, register the callback and enables the Interruption. It does
* opposite if the handler and arg are NULL.
*
****************************************************************************/
int phyplus_tim_setisr(struct phyplus_tim_dev_s *dev, xcpt_t handler,
void *arg)
{
struct phyplus_tim_priv_s *tim = NULL;
int vectorno;
DEBUGASSERT(dev);
tim = (struct phyplus_tim_priv_s *)dev;
if ((long unsigned int)AP_TIM1 == ((struct phyplus_tim_priv_s *)dev)->base)
{
vectorno = PHY62XX_IRQ_TIM1_IRQn;
}
else if ((long unsigned int)AP_TIM2 ==
((struct phyplus_tim_priv_s *)dev)->base)
{
vectorno = PHY62XX_IRQ_TIM2_IRQn;
}
else if ((long unsigned int)AP_TIM3 ==
((struct phyplus_tim_priv_s *)dev)->base)
{
vectorno = PHY62XX_IRQ_TIM3_IRQn;
}
else if ((long unsigned int)AP_TIM4 ==
((struct phyplus_tim_priv_s *)dev)->base)
{
vectorno = PHY62XX_IRQ_TIM4_IRQn;
}
else if ((long unsigned int)AP_TIM5 ==
((struct phyplus_tim_priv_s *)dev)->base)
{
vectorno = PHY62XX_IRQ_TIM5_IRQn;
}
else if ((long unsigned int)AP_TIM6 ==
((struct phyplus_tim_priv_s *)dev)->base)
{
vectorno = PHY62XX_IRQ_TIM6_IRQn;
}
else
{
return -EINVAL;
}
/* Disable interrupt when callback is removed */
if (!handler)
{
up_disable_irq(vectorno);
irq_detach(vectorno);
return OK;
}
/* Otherwise set callback and enable interrupt */
irq_attach(vectorno, handler, arg);
up_enable_irq(vectorno);
return OK;
}
/****************************************************************************
* Name: phyplus_tim_enableint
*
* Description:
* Enables a level Interrupt at the alarm if it is set.
*
****************************************************************************/
void phyplus_tim_enableint(struct phyplus_tim_dev_s *dev)
{
DEBUGASSERT(dev);
/* Set the level interrupt bit */
phyplus_tim_modifyreg32(dev, TIM_CURRENT_OFFSET, 0, TIM_MASK);
}
/****************************************************************************
* Name: phyplus_tim_disableint
*
* Description:
* Disables a level Interrupt at the alarm if it is set.
*
****************************************************************************/
void phyplus_tim_disableint(struct phyplus_tim_dev_s *dev)
{
DEBUGASSERT(dev);
/* Clear the level interrupt bit */
phyplus_tim_modifyreg32(dev, TIM_CURRENT_OFFSET, TIM_MASK, 0);
}
/****************************************************************************
* Name: phyplus_tim_ackint
*
* Description:
*
****************************************************************************/
void phyplus_tim_ackint(struct phyplus_tim_dev_s *dev)
{
DEBUGASSERT(dev);
/* Clear the level interrupt bit */
phyplus_tim_getreg32(dev, TIM_EOI_OFFSET);
}
/****************************************************************************
* Name: phyplus_tim_init
*
* Description:
* Initialize TIMER device.
*
****************************************************************************/
struct phyplus_tim_dev_s *phyplus_tim_init(int timer)
{
struct phyplus_tim_priv_s *tim = NULL;
/* First, take the data structure associated with the timer instance */
syslog(LOG_ERR, "phyplus_tim_init 1\n");
switch (timer)
{
/* #ifdef CONFIG_PHYPLUS_TIM1 */
case 1:
{
tim = &phyplus_tim1_priv;
break;
}
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM2 */
case 2:
{
tim = &phyplus_tim2_priv;
break;
}
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM3 */
case 3:
{
tim = &phyplus_tim3_priv;
break;
}
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM4 */
case 4:
{
tim = &phyplus_tim4_priv;
break;
}
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM5 */
case 5:
{
tim = &phyplus_tim5_priv;
break;
}
/* #endif */
/* #ifdef CONFIG_PHYPLUS_TIM6 */
case 6:
{
tim = &phyplus_tim6_priv;
break;
}
/* #endif */
default:
{
tmrerr("ERROR: unsupported TIMER %d\n", timer);
return NULL;
}
}
/* Verify if it is in use */
if (tim->inuse == false)
{
tim->inuse = true; /* If it was not, now it is */
}
else
{
tmrerr("ERROR: TIMER %d is already in use\n", timer);
return NULL;
}
syslog(LOG_ERR, "phyplus_tim_init 2\n");
return (struct phyplus_tim_dev_s *)tim;
}
/****************************************************************************
* Name: esp32_tim_deinit
*
* Description:
* Deinit TIMER device
*
****************************************************************************/
void phyplus_tim_deinit(struct phyplus_tim_dev_s *dev)
{
struct phyplus_tim_priv_s *tim = NULL;
DEBUGASSERT(dev);
tim = (struct phyplus_tim_priv_s *)dev;
tim->inuse = false;
}