| /**************************************************************************** |
| * 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) */ |