/**************************************************************************** * 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 #include #include #include #include #include #include #include #include #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; }