| /**************************************************************************** |
| * arch/arm/src/phy62xx/phyplus_tim.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * 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; |
| } |