nuttx/arch/arm/src/stm32h7/stm32_lptim.c
Xiang Xiao 972a260391 arch/arm: Remove FAR and CODE from chip folder(3)
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2022-05-03 16:50:52 +03:00

470 lines
13 KiB
C

/****************************************************************************
* arch/arm/src/stm32h7/stm32_lptim.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 <arch/board/board.h>
#include "chip.h"
#include "arm_internal.h"
#include "stm32_rcc.h"
#include "stm32_gpio.h"
#include "stm32_lptim.h"
#if defined(CONFIG_STM32H7_LPTIM1) || defined(CONFIG_STM32H7_LPTIM2) || \
defined(CONFIG_STM32H7_LPTIM3) || defined(CONFIG_STM32H7_LPTIM4) || \
defined(CONFIG_STM32H7_LPTIM5)
/****************************************************************************
* Private Function prototypes
****************************************************************************/
/* Low-power timer methods */
static void stm32_lptim_setcfgr(struct stm32_lptim_dev_s *dev,
uint32_t regval);
static void stm32_lptim_setperiod(struct stm32_lptim_dev_s *dev,
uint32_t period);
static void stm32_lptim_setcompare(struct stm32_lptim_dev_s *dev,
uint32_t cmp);
static uint32_t stm32_lptim_getcounter(struct stm32_lptim_dev_s *dev);
static int stm32_lptim_setinput(struct stm32_lptim_dev_s *dev,
uint32_t input, uint32_t mux);
static void stm32_lptim_enable(struct stm32_lptim_dev_s *dev, bool on);
static void stm32_lptim_start(struct stm32_lptim_dev_s *dev,
stm32_lptim_start_mode_t mode);
static void stm32_lptim_resetcounter(struct stm32_lptim_dev_s *dev);
static void stm32_lptim_enablerar(struct stm32_lptim_dev_s *dev,
bool on);
static int stm32_lptim_setisr(struct stm32_lptim_dev_s *dev,
xcpt_t handler, void *arg, int source);
static void stm32_lptim_enableint(struct stm32_lptim_dev_s *dev,
int source);
static void stm32_lptim_disableint(struct stm32_lptim_dev_s *dev,
int source);
static void stm32_lptim_ackint(struct stm32_lptim_dev_s *dev,
int source);
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static const struct stm32_lptim_ops_s stm32_lptim_ops =
{
.setcfgr = &stm32_lptim_setcfgr,
.setperiod = &stm32_lptim_setperiod,
.setcompare = &stm32_lptim_setcompare,
.getcounter = &stm32_lptim_getcounter,
.setinput = &stm32_lptim_setinput,
.enable = &stm32_lptim_enable,
.start = &stm32_lptim_start,
.resetcounter = &stm32_lptim_resetcounter,
.enablerar = &stm32_lptim_enablerar,
.setisr = &stm32_lptim_setisr,
.enableint = &stm32_lptim_enableint,
.disableint = &stm32_lptim_disableint,
.ackint = &stm32_lptim_ackint
};
#ifdef CONFIG_STM32H7_LPTIM1
struct stm32_lptim_dev_s stm32_lptim1_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM1_BASE,
};
#endif
#ifdef CONFIG_STM32H7_LPTIM2
struct stm32_lptim_dev_s stm32_lptim2_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM2_BASE,
};
#endif
#ifdef CONFIG_STM32H7_LPTIM3
struct stm32_lptim_dev_s stm32_lptim3_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM3_BASE,
};
#endif
#ifdef CONFIG_STM32H7_LPTIM4
struct stm32_lptim_dev_s stm32_lptim4_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM4_BASE,
};
#endif
#ifdef CONFIG_STM32H7_LPTIM5
struct stm32_lptim_dev_s stm32_lptim5_priv =
{
.ops = &stm32_lptim_ops,
.base = STM32_LPTIM5_BASE,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/* Get a 32-bit register value by offset.
*/
static inline uint32_t stm32_getreg32(struct stm32_lptim_dev_s *dev,
uint8_t offset)
{
return getreg32(dev->base + offset);
}
/* Put a 32-bit register value by offset.
*/
static inline void stm32_putreg32(struct stm32_lptim_dev_s *dev,
uint8_t offset, uint32_t value)
{
putreg32(value, dev->base + offset);
}
static void stm32_lptim_setcfgr(struct stm32_lptim_dev_s *dev,
uint32_t regval)
{
stm32_putreg32(dev, STM32_LPTIM_CFGR_OFFSET, regval);
}
static void stm32_lptim_setperiod(struct stm32_lptim_dev_s *dev,
uint32_t period)
{
stm32_putreg32(dev, STM32_LPTIM_ARR_OFFSET, period);
}
static void stm32_lptim_setcompare(struct stm32_lptim_dev_s *dev,
uint32_t cmp)
{
stm32_putreg32(dev, STM32_LPTIM_CMP_OFFSET, cmp);
}
static uint32_t stm32_lptim_getcounter(struct stm32_lptim_dev_s *dev)
{
/* For a reliable LPTIM_CNT register read access, two consecutive
* read accesses must be performed and compared
*/
uint32_t cnt1;
uint32_t cnt2;
cnt2 = stm32_getreg32(dev, STM32_LPTIM_CNT_OFFSET);
do
{
cnt1 = cnt2;
cnt2 = stm32_getreg32(dev, STM32_LPTIM_CNT_OFFSET);
}
while (cnt1 != cnt2);
return cnt1;
}
static int stm32_lptim_setinput(struct stm32_lptim_dev_s *dev,
uint32_t input, uint32_t mux)
{
switch (dev->base)
{
#if defined(CONFIG_STM32H7_LPTIM1) || defined(CONFIG_STM32H7_LPTIM2)
case STM32_LPTIM1_BASE:
case STM32_LPTIM2_BASE:
if (input == 0)
{
modifyreg32(dev->base + STM32_LPTIM_CFGR2_OFFSET,
LPTIM_CFGR2_IN1SEL_MASK, mux);
}
else
{
modifyreg32(dev->base + STM32_LPTIM_CFGR2_OFFSET,
LPTIM_CFGR2_IN2SEL_MASK,
mux << LPTIM_CFGR2_IN2SEL_SHIFT);
}
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM3
case STM32_LPTIM3_BASE:
modifyreg32(dev->base + STM32_LPTIM_CFGR2_OFFSET,
LPTIM_CFGR2_IN1SEL_MASK, mux);
break;
#endif
default:
return -EINVAL;
}
return OK;
}
static void stm32_lptim_enable(struct stm32_lptim_dev_s *dev, bool on)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
if (on)
{
val |= LPTIM_CR_ENABLE;
}
else
{
val &= ~LPTIM_CR_ENABLE;
}
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static void stm32_lptim_start(struct stm32_lptim_dev_s *dev,
stm32_lptim_start_mode_t mode)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
switch (mode)
{
case STM32_LPTIM_MODE_CONTINUOUS:
val |= LPTIM_CR_CNTSTRT;
break;
case STM32_LPTIM_MODE_SINGLE:
val |= LPTIM_CR_SNGSTRT;
break;
}
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static void stm32_lptim_resetcounter(struct stm32_lptim_dev_s *dev)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
val |= LPTIM_CR_COUNTRST;
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static void stm32_lptim_enablerar(struct stm32_lptim_dev_s *dev, bool on)
{
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_CR_OFFSET);
if (on)
{
val |= LPTIM_CR_RSTARE;
}
else
{
val &= ~LPTIM_CR_RSTARE;
}
stm32_putreg32(dev, STM32_LPTIM_CR_OFFSET, val);
}
static int stm32_lptim_setisr(struct stm32_lptim_dev_s *dev,
xcpt_t handler, void *arg, int source)
{
int vectorno;
DEBUGASSERT(dev != NULL);
DEBUGASSERT(source == 0);
switch (dev->base)
{
#ifdef CONFIG_STM32H7_LPTIM1
case STM32_LPTIM1_BASE:
vectorno = STM32_IRQ_LPTIM1;
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM2
case STM32_LPTIM2_BASE:
vectorno = STM32_IRQ_LPTIM2;
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM3
case STM32_LPTIM3_BASE:
vectorno = STM32_IRQ_LPTIM3;
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM4
case STM32_LPTIM4_BASE:
vectorno = STM32_IRQ_LPTIM4;
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM5
case STM32_LPTIM5_BASE:
vectorno = STM32_IRQ_LPTIM5;
break;
#endif
default:
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);
#ifdef CONFIG_ARCH_IRQPRIO
/* Set the interrupt priority */
up_prioritize_irq(vectorno, NVIC_SYSH_PRIORITY_DEFAULT);
#endif
return OK;
}
static void stm32_lptim_enableint(struct stm32_lptim_dev_s *dev,
int source)
{
DEBUGASSERT(dev != NULL);
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_IER_OFFSET);
val |= source;
stm32_putreg32(dev, STM32_LPTIM_IER_OFFSET, val);
}
static void stm32_lptim_disableint(struct stm32_lptim_dev_s *dev,
int source)
{
DEBUGASSERT(dev != NULL);
uint32_t val = stm32_getreg32(dev, STM32_LPTIM_IER_OFFSET);
val &= ~source;
stm32_putreg32(dev, STM32_LPTIM_IER_OFFSET, val);
}
static void stm32_lptim_ackint(struct stm32_lptim_dev_s *dev, int source)
{
stm32_putreg32(dev, STM32_LPTIM_ICR_OFFSET, source);
}
/****************************************************************************
* Public Functions
****************************************************************************/
struct stm32_lptim_dev_s *stm32_lptim_init(int lptimer)
{
struct stm32_lptim_dev_s *dev = NULL;
/* Get structure and enable power */
switch (lptimer)
{
#ifdef CONFIG_STM32H7_LPTIM1
case 1:
dev = &stm32_lptim1_priv;
modifyreg32(STM32_RCC_APB1LENR, 0, RCC_APB1LENR_LPTIM1EN);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM2
case 2:
dev = &stm32_lptim2_priv;
modifyreg32(STM32_RCC_APB4ENR, 0, RCC_APB4ENR_LPTIM2EN);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM3
case 3:
dev = &stm32_lptim3_priv;
modifyreg32(STM32_RCC_APB4ENR, 0, RCC_APB4ENR_LPTIM3EN);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM4
case 4:
dev = &stm32_lptim4_priv;
modifyreg32(STM32_RCC_APB4ENR, 0, RCC_APB4ENR_LPTIM4EN);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM5
case 5:
dev = &stm32_lptim5_priv;
modifyreg32(STM32_RCC_APB4ENR, 0, RCC_APB4ENR_LPTIM5EN);
break;
#endif
default:
return NULL;
}
return dev;
}
int stm32_lptim_deinit(struct stm32_lptim_dev_s * dev)
{
DEBUGASSERT(dev != NULL);
/* Disable power */
switch (dev->base)
{
#ifdef CONFIG_STM32H7_LPTIM1
case STM32_LPTIM1_BASE:
modifyreg32(STM32_RCC_APB1LLPENR, RCC_APB1LENR_LPTIM1EN, 0);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM2
case STM32_LPTIM2_BASE:
modifyreg32(STM32_RCC_APB4LPENR, RCC_APB4ENR_LPTIM2EN, 0);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM3
case STM32_LPTIM3_BASE:
modifyreg32(STM32_RCC_APB4LPENR, RCC_APB4ENR_LPTIM3EN, 0);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM4
case STM32_LPTIM4_BASE:
modifyreg32(STM32_RCC_APB4LPENR, RCC_APB4ENR_LPTIM4EN, 0);
break;
#endif
#ifdef CONFIG_STM32H7_LPTIM5
case STM32_LPTIM5_BASE:
modifyreg32(STM32_RCC_APB4LPENR, RCC_APB4ENR_LPTIM5EN, 0);
break;
#endif
default:
return -EINVAL;
}
return OK;
}
#endif /* defined(CONFIG_STM32H7_LPTIM1 || ... || CONFIG_STM32H7_LPTIM5) */