From 8d2451da0cc3f2ab1becc892443165dbbd0bc4b1 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 13 Mar 2023 12:41:29 +0100 Subject: [PATCH] arch/nrf53: add TIM support --- arch/arm/src/nrf53/Kconfig | 20 + arch/arm/src/nrf53/Make.defs | 7 + arch/arm/src/nrf53/nrf53_tim.c | 857 +++++++++++++++++++++++ arch/arm/src/nrf53/nrf53_tim.h | 172 +++++ arch/arm/src/nrf53/nrf53_tim_lowerhalf.c | 538 ++++++++++++++ arch/arm/src/nrf53/nrf53_tim_lowerhalf.h | 42 ++ 6 files changed, 1636 insertions(+) create mode 100644 arch/arm/src/nrf53/nrf53_tim.c create mode 100644 arch/arm/src/nrf53/nrf53_tim.h create mode 100644 arch/arm/src/nrf53/nrf53_tim_lowerhalf.c create mode 100644 arch/arm/src/nrf53/nrf53_tim_lowerhalf.h diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig index d1bf7849c5..607848c9b7 100644 --- a/arch/arm/src/nrf53/Kconfig +++ b/arch/arm/src/nrf53/Kconfig @@ -76,6 +76,10 @@ config NRF53_UART bool default n +config NRF53_TIMER + bool + default n + menu "NRF53 Peripheral Selection" config NRF53_UART0 @@ -90,6 +94,22 @@ config NRF53_UART1 select UART1_SERIALDRIVER select NRF53_UART +config NRF53_TIMER0 + bool "TIMER0" + select NRF53_TIMER + depends on !NRF53_SOFTDEVICE_CONTROLLER + default n + +config NRF53_TIMER1 + bool "TIMER1" + select NRF53_TIMER + default n + +config NRF53_TIMER2 + bool "TIMER2" + select NRF53_TIMER + default n + endmenu # NRF53 Peripheral Selection menu "Clock Configuration" diff --git a/arch/arm/src/nrf53/Make.defs b/arch/arm/src/nrf53/Make.defs index 659da945dd..35d9159adf 100644 --- a/arch/arm/src/nrf53/Make.defs +++ b/arch/arm/src/nrf53/Make.defs @@ -51,6 +51,13 @@ ifeq ($(CONFIG_RPTUN),y) CHIP_CSRCS += nrf53_rptun.c endif +ifeq ($(CONFIG_NRF53_TIMER),y) +CHIP_CSRCS += nrf53_tim.c +ifeq ($(CONFIG_TIMER),y) +CHIP_CSRCS += nrf53_tim_lowerhalf.c +endif +endif + ifeq ($(CONFIG_PM),y) CHIP_CSRCS += nrf53_pminitialize.c endif diff --git a/arch/arm/src/nrf53/nrf53_tim.c b/arch/arm/src/nrf53/nrf53_tim.c new file mode 100644 index 0000000000..c822f2e86f --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_tim.c @@ -0,0 +1,857 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_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 "arm_internal.h" +#include "hardware/nrf53_tim.h" + +#include "nrf53_tim.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf53_tim_priv_s +{ + struct nrf53_tim_ops_s *ops; + uint32_t base; + uint32_t irq; + uint8_t chan; + bool inuse; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* TIM registers access *****************************************************/ + +static uint32_t nrf53_tim_getreg(struct nrf53_tim_dev_s *dev, + uint32_t offset); +static void nrf53_tim_putreg(struct nrf53_tim_dev_s *dev, + uint32_t offset, + uint32_t value); + +/* TIM helpers **************************************************************/ + +static uint32_t nrf53_tim_irq2reg(struct nrf53_tim_dev_s *dev, + uint8_t s); + +/* TIM operations ***********************************************************/ + +static int nrf53_tim_start(struct nrf53_tim_dev_s *dev); +static int nrf53_tim_stop(struct nrf53_tim_dev_s *dev); +static int nrf53_tim_clear(struct nrf53_tim_dev_s *dev); +static int nrf53_tim_configure(struct nrf53_tim_dev_s *dev, uint8_t mode, + uint8_t width); +static int nrf53_tim_shorts(struct nrf53_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en); +static int nrf53_tim_count(struct nrf53_tim_dev_s *dev); +static int nrf53_tim_setcc(struct nrf53_tim_dev_s *dev, uint8_t i, + uint32_t cc); +static int nrf53_tim_getcc(struct nrf53_tim_dev_s *dev, uint8_t i, + uint32_t *cc); +static int nrf53_tim_setpre(struct nrf53_tim_dev_s *dev, uint8_t pre); +static int nrf53_tim_setisr(struct nrf53_tim_dev_s *dev, xcpt_t handler, + void * arg); +static int nrf53_tim_enableint(struct nrf53_tim_dev_s *dev, uint8_t s); +static int nrf53_tim_disableint(struct nrf53_tim_dev_s *dev, uint8_t s); +static int nrf53_tim_checkint(struct nrf53_tim_dev_s *dev, uint8_t s); +static int nrf53_tim_ackint(struct nrf53_tim_dev_s *dev, uint8_t s); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* NRF53 TIM ops */ + +struct nrf53_tim_ops_s nrf53_tim_ops = +{ + .start = nrf53_tim_start, + .stop = nrf53_tim_stop, + .clear = nrf53_tim_clear, + .configure = nrf53_tim_configure, + .shorts = nrf53_tim_shorts, + .count = nrf53_tim_count, + .setcc = nrf53_tim_setcc, + .getcc = nrf53_tim_getcc, + .setpre = nrf53_tim_setpre, + .setisr = nrf53_tim_setisr, + .enableint = nrf53_tim_enableint, + .disableint = nrf53_tim_disableint, + .checkint = nrf53_tim_checkint, + .ackint = nrf53_tim_ackint +}; + +#ifdef CONFIG_NRF53_TIMER0 +/* TIMER0 */ + +struct nrf53_tim_priv_s g_nrf53_tim0_priv = +{ + .ops = &nrf53_tim_ops, + .base = NRF53_TIMER0_BASE, + .irq = NRF53_IRQ_TIMER0, + .chan = 4, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER1 +/* TIMER1 */ + +struct nrf53_tim_priv_s g_nrf53_tim1_priv = +{ + .ops = &nrf53_tim_ops, + .base = NRF53_TIMER1_BASE, + .irq = NRF53_IRQ_TIMER1, + .chan = 4, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER2 +/* TIMER2 */ + +struct nrf53_tim_priv_s g_nrf53_tim2_priv = +{ + .ops = &nrf53_tim_ops, + .base = NRF53_TIMER2_BASE, + .irq = NRF53_IRQ_TIMER2, + .chan = 4, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER3 +/* TIMER3 */ + +struct nrf53_tim_priv_s g_nrf53_tim3_priv = +{ + .ops = &nrf53_tim_ops, + .base = NRF53_TIMER3_BASE, + .irq = NRF53_IRQ_TIMER3, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER4 +/* TIMER4 */ + +struct nrf53_tim_priv_s g_nrf53_tim4_priv = +{ + .ops = &nrf53_tim_ops, + .base = NRF53_TIMER4_BASE, + .irq = NRF53_IRQ_TIMER4, + .chan = 6, + .inuse = false, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_tim_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static uint32_t nrf53_tim_getreg(struct nrf53_tim_dev_s *dev, + uint32_t offset) +{ + DEBUGASSERT(dev); + + return getreg32(((struct nrf53_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: nrf53_tim_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static void nrf53_tim_putreg(struct nrf53_tim_dev_s *dev, + uint32_t offset, + uint32_t value) +{ + DEBUGASSERT(dev); + + putreg32(value, ((struct nrf53_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: nrf53_tim_irq2reg + * + * Description: + * Get the value of the interrupt register corresponding to the given + * interrupt source + * + ****************************************************************************/ + +static uint32_t nrf53_tim_irq2reg(struct nrf53_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + + switch (s) + { + case NRF53_TIM_INT_COMPARE0: + { + regval = TIM_INT_COMPARE(0); + break; + } + + case NRF53_TIM_INT_COMPARE1: + { + regval = TIM_INT_COMPARE(1); + break; + } + + case NRF53_TIM_INT_COMPARE2: + { + regval = TIM_INT_COMPARE(2); + break; + } + + case NRF53_TIM_INT_COMPARE3: + { + regval = TIM_INT_COMPARE(3); + break; + } + + case NRF53_TIM_INT_COMPARE4: + { + regval = TIM_INT_COMPARE(4); + break; + } + + case NRF53_TIM_INT_COMPARE5: + { + regval = TIM_INT_COMPARE(5); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + regval = 0; + goto errout; + } + } + +errout: + return regval; +} + +/**************************************************************************** + * Name: nrf53_tim_start + ****************************************************************************/ + +static int nrf53_tim_start(struct nrf53_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf53_tim_putreg(dev, NRF53_TIM_TASKS_START_OFFSET, TIM_TASKS_START); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_tim_stop + ****************************************************************************/ + +static int nrf53_tim_stop(struct nrf53_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf53_tim_putreg(dev, NRF53_TIM_TASKS_STOP_OFFSET, TIM_TASKS_STOP); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_tim_clear + ****************************************************************************/ + +static int nrf53_tim_clear(struct nrf53_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf53_tim_putreg(dev, NRF53_TIM_TASKS_CLEAR_OFFSET, TIM_TASKS_CLEAR); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_tim_configure + ****************************************************************************/ + +static int nrf53_tim_configure(struct nrf53_tim_dev_s *dev, uint8_t mode, + uint8_t width) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Configure TIMER mode */ + + switch (mode) + { + case NRF53_TIM_MODE_UNUSED: + { + regval = 0; + break; + } + + case NRF53_TIM_MODE_TIMER: + { + regval = TIM_MODE_TIMER; + break; + } + + case NRF53_TIM_MODE_COUNTER: + { + regval = TIM_MODE_COUNTER; + break; + } + + case NRF53_TIM_MODE_LOWPOWER: + { + regval = TIM_MODE_LPCOUNTER; + break; + } + + default: + { + tmrerr("ERROR: unsupported TIMER mode %d\n", mode); + ret = -EINVAL; + goto errout; + } + } + + nrf53_tim_putreg(dev, NRF53_TIM_MODE_OFFSET, regval); + + /* Configure TIMER width */ + + switch (width) + { + case NRF53_TIM_WIDTH_16B: + { + regval = TIM_BITMODE_16B; + break; + } + + case NRF53_TIM_WIDTH_8B: + { + regval = TIM_BITMODE_8B; + break; + } + + case NRF53_TIM_WIDTH_24B: + { + regval = TIM_BITMODE_24B; + break; + } + + case NRF53_TIM_WIDTH_32B: + { + regval = TIM_BITMODE_32B; + break; + } + + default: + { + tmrerr("ERROR: unsupported TIMER width %d\n", width); + ret = -EINVAL; + goto errout; + } + } + + nrf53_tim_putreg(dev, NRF53_TIM_BITMODE_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_shorts + ****************************************************************************/ + +static int nrf53_tim_shorts(struct nrf53_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en) +{ + uint32_t regval = 0; + uint32_t val = 0; + int ret = OK; + + regval = nrf53_tim_getreg(dev, NRF53_TIM_SHORTS_OFFSET); + + switch (s) + { + case NRF53_TIM_SHORT_COMPARE_CLEAR: + { + val = TIM_SHORTS_COMPARE_CLEAR(i); + break; + } + + case NRF53_TIM_SHORT_COMPARE_STOP: + { + val = TIM_SHORTS_COMPARE_STOP(i); + break; + } + + default: + { + tmrerr("ERROR: unsupported SHORT %d\n", s); + ret = -EINVAL; + goto errout; + } + } + + if (en == true) + { + regval |= val; + } + else + { + regval &= ~val; + } + + nrf53_tim_putreg(dev, NRF53_TIM_SHORTS_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_count + ****************************************************************************/ + +static int nrf53_tim_count(struct nrf53_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf53_tim_putreg(dev, NRF53_TIM_TASKS_COUNT_OFFSET, TIM_TASKS_COUNT); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_tim_setcc + ****************************************************************************/ + +static int nrf53_tim_setcc(struct nrf53_tim_dev_s *dev, uint8_t i, + uint32_t cc) +{ + struct nrf53_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + + tim = (struct nrf53_tim_priv_s *)dev; + + /* Is the channel supported? */ + + if (i > tim->chan) + { + tmrerr("ERROR: unsupported TIMER channel %d\n", i); + ret = -EINVAL; + goto errout; + } + + nrf53_tim_putreg(dev, NRF53_TIM_CC_OFFSET(i), cc); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_getcc + ****************************************************************************/ + +static int nrf53_tim_getcc(struct nrf53_tim_dev_s *dev, uint8_t i, + uint32_t *cc) +{ + struct nrf53_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + DEBUGASSERT(cc); + + tim = (struct nrf53_tim_priv_s *)dev; + + /* Is the channel supported? */ + + if (i > tim->chan) + { + tmrerr("ERROR: unsupported TIMER channel %d\n", i); + ret = -EINVAL; + goto errout; + } + + *cc = nrf53_tim_getreg(dev, NRF53_TIM_CC_OFFSET(i)); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_setpre + ****************************************************************************/ + +static int nrf53_tim_setpre(struct nrf53_tim_dev_s *dev, uint8_t pre) +{ + int ret = OK; + + DEBUGASSERT(dev); + + if (pre < NRF53_TIM_PRE_16000000 || pre > NRF53_TIM_PRE_31250) + { + tmrerr("ERROR: unsupported TIMER prescaler %d\n", pre); + ret = -EINVAL; + goto errout; + } + + nrf53_tim_putreg(dev, NRF53_TIM_PRESCALER_OFFSET, pre); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_setisr + ****************************************************************************/ + +static int nrf53_tim_setisr(struct nrf53_tim_dev_s *dev, xcpt_t handler, + void *arg) +{ + struct nrf53_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + + tim = (struct nrf53_tim_priv_s *)dev; + + /* Disable interrupt when callback is removed */ + + if (!handler) + { + up_disable_irq(tim->irq); + irq_detach(tim->irq); + ret = OK; + goto errout; + } + + /* Otherwise set callback and enable interrupt */ + + irq_attach(tim->irq, handler, arg); + up_enable_irq(tim->irq); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_enableint + ****************************************************************************/ + +static int nrf53_tim_enableint(struct nrf53_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Get register value for given interrupt source */ + + regval = nrf53_tim_irq2reg(dev, s); + if (regval == 0) + { + ret = -EINVAL; + goto errout; + } + + nrf53_tim_putreg(dev, NRF53_TIM_INTENSET_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_disableint + ****************************************************************************/ + +static int nrf53_tim_disableint(struct nrf53_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Get register value for given interrupt source */ + + regval = nrf53_tim_irq2reg(dev, s); + if (regval == 0) + { + ret = -EINVAL; + goto errout; + } + + nrf53_tim_putreg(dev, NRF53_TIM_INTCLR_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_checkint + ****************************************************************************/ + +static int nrf53_tim_checkint(struct nrf53_tim_dev_s *dev, uint8_t s) +{ + int ret = 0; + + DEBUGASSERT(dev); + + switch (s) + { + case NRF53_TIM_INT_COMPARE0: + { + ret = nrf53_tim_getreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(0)); + break; + } + + case NRF53_TIM_INT_COMPARE1: + { + ret = nrf53_tim_getreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(0)); + break; + } + + case NRF53_TIM_INT_COMPARE2: + { + ret = nrf53_tim_getreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(2)); + break; + } + + case NRF53_TIM_INT_COMPARE3: + { + ret = nrf53_tim_getreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(3)); + break; + } + + case NRF53_TIM_INT_COMPARE4: + { + ret = nrf53_tim_getreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(4)); + break; + } + + case NRF53_TIM_INT_COMPARE5: + { + ret = nrf53_tim_getreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(5)); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_tim_ackint + ****************************************************************************/ + +static int nrf53_tim_ackint(struct nrf53_tim_dev_s *dev, uint8_t s) +{ + int ret = 0; + + DEBUGASSERT(dev); + + switch (s) + { + case NRF53_TIM_INT_COMPARE0: + { + nrf53_tim_putreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(0), 0); + break; + } + + case NRF53_TIM_INT_COMPARE1: + { + nrf53_tim_putreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(1), 0); + break; + } + + case NRF53_TIM_INT_COMPARE2: + { + nrf53_tim_putreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(2), 0); + break; + } + + case NRF53_TIM_INT_COMPARE3: + { + nrf53_tim_putreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(3), 0); + break; + } + + case NRF53_TIM_INT_COMPARE4: + { + nrf53_tim_putreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(4), 0); + break; + } + + case NRF53_TIM_INT_COMPARE5: + { + nrf53_tim_putreg(dev, NRF53_TIM_EVENTS_COMPARE_OFFSET(5), 0); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_tim_init + * + * Description: + * Initialize TIMER device + * + ****************************************************************************/ + +struct nrf53_tim_dev_s *nrf53_tim_init(int timer) +{ + struct nrf53_tim_priv_s *tim = NULL; + + /* Get timer instance */ + + switch (timer) + { +#ifdef CONFIG_NRF53_TIMER0 + case 0: + { + tim = &g_nrf53_tim0_priv; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER1 + case 1: + { + tim = &g_nrf53_tim1_priv; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER2 + case 2: + { + tim = &g_nrf53_tim2_priv; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER3 + case 3: + { + tim = &g_nrf53_tim3_priv; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER4 + case 4: + { + tim = &g_nrf53_tim4_priv; + break; + } +#endif + + default: + { + tmrerr("ERROR: unsupported TIMER %d\n", timer); + goto errout; + } + } + + if (tim->inuse != false) + { + /* Timer already in use */ + + tim = NULL; + } + +errout: + return (struct nrf53_tim_dev_s *)tim; +} + +/**************************************************************************** + * Name: nrf53_tim_deinit + * + * Description: + * Deinit TIMER device + * + ****************************************************************************/ + +int nrf53_tim_deinit(struct nrf53_tim_dev_s *dev) +{ + struct nrf53_tim_priv_s *tim = NULL; + + DEBUGASSERT(dev); + + tim = (struct nrf53_tim_priv_s *)dev; + + tim->inuse = false; + + return OK; +} diff --git a/arch/arm/src/nrf53/nrf53_tim.h b/arch/arm/src/nrf53/nrf53_tim.h new file mode 100644 index 0000000000..1e0841922c --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_tim.h @@ -0,0 +1,172 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_tim.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF53_NRF53_TIM_H +#define __ARCH_ARM_SRC_NRF53_NRF53_TIM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Helpers ******************************************************************/ + +#define NRF53_TIM_START(d) ((d)->ops->start(d)) +#define NRF53_TIM_STOP(d) ((d)->ops->stop(d)) +#define NRF53_TIM_CLEAR(d) ((d)->ops->clear(d)) +#define NRF53_TIM_CONFIGURE(d, m, w) ((d)->ops->configure(d, m, w)) +#define NRF53_TIM_SHORTS(d, s, i, e) ((d)->ops->shorts(d, s, i, e)) +#define NRF53_TIM_COUNT(d) ((d)->ops->count(d)) +#define NRF53_TIM_SETCC(d, i, cc) ((d)->ops->setcc(d, i, cc)) +#define NRF53_TIM_GETCC(d, i, cc) ((d)->ops->getcc(d, i, cc)) +#define NRF53_TIM_SETPRE(d, pre) ((d)->ops->setpre(d, pre)) +#define NRF53_TIM_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg)) +#define NRF53_TIM_ENABLEINT(d, s) ((d)->ops->enableint(d, s)) +#define NRF53_TIM_DISABLEINT(d, s) ((d)->ops->disableint(d, s)) +#define NRF53_TIM_CHECKINT(d, s) ((d)->ops->checkint(d, s)) +#define NRF53_TIM_ACKINT(d, s) ((d)->ops->ackint(d, s)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Timer mode */ + +enum nrf53_tim_mode_e +{ + NRF53_TIM_MODE_UNUSED = 0, + NRF53_TIM_MODE_TIMER = 1, + NRF53_TIM_MODE_COUNTER = 2, + NRF53_TIM_MODE_LOWPOWER = 3, +}; + +/* Timer bit width */ + +enum nrf53_tim_width_e +{ + NRF53_TIM_WIDTH_16B = 0, + NRF53_TIM_WIDTH_8B = 1, + NRF53_TIM_WIDTH_24B = 2, + NRF53_TIM_WIDTH_32B = 3, +}; + +/* Timer CC index */ + +enum nrf53_tim_cc_e +{ + NRF53_TIM_CC0 = 0, + NRF53_TIM_CC1 = 1, + NRF53_TIM_CC2 = 2, + NRF53_TIM_CC3 = 3, + NRF53_TIM_CC4 = 4, + NRF53_TIM_CC5 = 5 +}; + +/* Timer IRQ source */ + +enum nrf53_tim_irq_e +{ + NRF53_TIM_INT_COMPARE0 = 0, + NRF53_TIM_INT_COMPARE1 = 1, + NRF53_TIM_INT_COMPARE2 = 2, + NRF53_TIM_INT_COMPARE3 = 3, + NRF53_TIM_INT_COMPARE4 = 4, + NRF53_TIM_INT_COMPARE5 = 5, +}; + +/* Timer shorts type */ + +enum nrf53_tim_shorts_e +{ + NRF53_TIM_SHORT_COMPARE_CLEAR = 1, + NRF53_TIM_SHORT_COMPARE_STOP = 2 +}; + +/* Timer frequency prescaler */ + +enum nrf53_tim_pre_e +{ + NRF53_TIM_PRE_16000000 = 0, + NRF53_TIM_PRE_8000000 = 1, + NRF53_TIM_PRE_4000000 = 2, + NRF53_TIM_PRE_2000000 = 3, + NRF53_TIM_PRE_1000000 = 4, + NRF53_TIM_PRE_500000 = 5, + NRF53_TIM_PRE_250000 = 6, + NRF53_TIM_PRE_125000 = 7, + NRF53_TIM_PRE_62500 = 8, + NRF53_TIM_PRE_31250 = 9 +}; + +/* NRF53 TIM device */ + +struct nrf53_tim_dev_s +{ + struct nrf53_tim_ops_s *ops; +}; + +/* NRF53 TIM ops */ + +struct nrf53_tim_ops_s +{ + /* Timer tasks */ + + int (*start)(struct nrf53_tim_dev_s *dev); + int (*stop)(struct nrf53_tim_dev_s *dev); + int (*clear)(struct nrf53_tim_dev_s *dev); + + /* Timer configuration */ + + int (*configure)(struct nrf53_tim_dev_s *dev, uint8_t mode, uint8_t width); + int (*shorts)(struct nrf53_tim_dev_s *dev, uint8_t s, uint8_t i, bool en); + + /* Timer operations */ + + int (*count)(struct nrf53_tim_dev_s *dev); + int (*setcc)(struct nrf53_tim_dev_s *dev, uint8_t i, uint32_t cc); + int (*getcc)(struct nrf53_tim_dev_s *dev, uint8_t i, uint32_t *cc); + int (*setpre)(struct nrf53_tim_dev_s *dev, uint8_t pre); + + /* Timer interrupts */ + + int (*setisr)(struct nrf53_tim_dev_s *dev, xcpt_t handler, void *arg); + int (*enableint)(struct nrf53_tim_dev_s *dev, uint8_t source); + int (*disableint)(struct nrf53_tim_dev_s *dev, uint8_t source); + int (*checkint)(struct nrf53_tim_dev_s *dev, uint8_t source); + int (*ackint)(struct nrf53_tim_dev_s *dev, uint8_t source); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct nrf53_tim_dev_s *nrf53_tim_init(int timer); +int nrf53_tim_deinit(struct nrf53_tim_dev_s *dev); + +#endif /* __ARCH_ARM_SRC_NRF53_NRF53_TIM_H */ diff --git a/arch/arm/src/nrf53/nrf53_tim_lowerhalf.c b/arch/arm/src/nrf53/nrf53_tim_lowerhalf.c new file mode 100644 index 0000000000..6af5732b1c --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_tim_lowerhalf.c @@ -0,0 +1,538 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_tim_lowerhalf.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 "arm_internal.h" +#include "nrf53_tim.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* TIMER configuration */ + +#define NRF53_TIMER_CC (NRF53_TIM_CC0) +#define NRF53_TIMER_INT (NRF53_TIM_INT_COMPARE0) +#define NRF53_TIMER_RES (NRF53_TIM_WIDTH_32B) +#define NRF53_TIMER_MAX (0xffffffff) +#define NRF53_TIMER_PRE (NRF53_TIM_PRE_1000000) +#define NRF53_TIMER_PER (1000000) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf53_timer_lowerhalf_s +{ + const struct timer_ops_s *ops; /* Lower half operations */ + struct nrf53_tim_dev_s *tim; /* nrf53 timer driver */ + tccb_t callback; /* Current user interrupt callback */ + void *arg; /* Argument passed to upper half callback */ + bool started; /* True: Timer has been started */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int nrf53_timer_handler(int irq, void *context, void *arg); + +/* "Lower half" driver methods **********************************************/ + +static int nrf53_timer_start(struct timer_lowerhalf_s *lower); +static int nrf53_timer_stop(struct timer_lowerhalf_s *lower); +static int nrf53_timer_getstatus(struct timer_lowerhalf_s *lower, + struct timer_status_s *status); +static int nrf53_timer_settimeout(struct timer_lowerhalf_s *lower, + uint32_t timeout); +static void nrf53_timer_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct timer_ops_s g_nrf53_timer_ops = +{ + .start = nrf53_timer_start, + .stop = nrf53_timer_stop, + .getstatus = nrf53_timer_getstatus, + .settimeout = nrf53_timer_settimeout, + .setcallback = nrf53_timer_setcallback, + .ioctl = NULL, +}; + +#ifdef CONFIG_NRF53_TIMER0 +/* TIMER0 lower-half */ + +static struct nrf53_timer_lowerhalf_s g_nrf53_timer0_lowerhalf = +{ + .ops = &g_nrf53_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER1 +/* TIMER1 lower-half */ + +static struct nrf53_timer_lowerhalf_s g_nrf53_timer1_lowerhalf = +{ + .ops = &g_nrf53_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER2 +/* TIMER2 lower-half */ + +static struct nrf53_timer_lowerhalf_s g_nrf53_timer2_lowerhalf = +{ + .ops = &g_nrf53_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER3 +/* TIMER3 lower-half */ + +static struct nrf53_timer_lowerhalf_s g_nrf53_timer3_lowerhalf = +{ + .ops = &g_nrf53_timer_ops, +}; +#endif + +#ifdef CONFIG_NRF53_TIMER4 +/* TIMER4 lower-half */ + +static struct nrf53_timer_lowerhalf_s g_nrf53_timer4_lowerhalf = +{ + .ops = &g_nrf53_timer_ops, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_timer_handler + * + * Description: + * Timer interrupt handler + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int nrf53_timer_handler(int irq, void *context, void *arg) +{ + struct nrf53_timer_lowerhalf_s *priv = + (struct nrf53_timer_lowerhalf_s *)arg; + uint32_t next_interval_us = 0; + + NRF53_TIM_ACKINT(priv->tim, NRF53_TIMER_INT); + + if (priv->callback(&next_interval_us, priv->arg)) + { + if (next_interval_us > 0) + { + NRF53_TIM_SETCC(priv->tim, NRF53_TIMER_CC, next_interval_us); + } + } + else + { + nrf53_timer_stop((struct timer_lowerhalf_s *)priv); + } + + return OK; +} + +/**************************************************************************** + * Name: nrf53_timer_start + * + * Description: + * Start the timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf53_timer_start(struct timer_lowerhalf_s *lower) +{ + struct nrf53_timer_lowerhalf_s *priv = + (struct nrf53_timer_lowerhalf_s *)lower; + int ret = OK; + + DEBUGASSERT(priv); + + if (priv->started == true) + { + /* Return EBUSY to indicate that the timer was already running */ + + ret = -EBUSY; + goto errout; + } + + /* Configure TIMER mode and resolution */ + + NRF53_TIM_CONFIGURE(priv->tim, NRF53_TIM_MODE_TIMER, NRF53_TIMER_RES); + + /* Clear counter on COMPARE event */ + + NRF53_TIM_SHORTS(priv->tim, NRF53_TIM_SHORT_COMPARE_CLEAR, + NRF53_TIMER_INT, true); + + /* Configure prescaler */ + + NRF53_TIM_SETPRE(priv->tim, NRF53_TIMER_PRE); + + /* Configure callback */ + + if (priv->callback != NULL) + { + NRF53_TIM_SETISR(priv->tim, nrf53_timer_handler, priv); + NRF53_TIM_ENABLEINT(priv->tim, NRF53_TIMER_INT); + } + + NRF53_TIM_CLEAR(priv->tim); + NRF53_TIM_START(priv->tim); + + priv->started = true; + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_timer_stop + * + * Description: + * Stop the timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf53_timer_stop(struct timer_lowerhalf_s *lower) +{ + struct nrf53_timer_lowerhalf_s *priv = + (struct nrf53_timer_lowerhalf_s *)lower; + int ret = OK; + + DEBUGASSERT(priv); + + if (priv->started == false) + { + /* Return ENODEV to indicate that the timer was not running */ + + ret = -ENODEV; + goto errout; + } + + NRF53_TIM_DISABLEINT(priv->tim, NRF53_TIMER_INT); + NRF53_TIM_SETISR(priv->tim, NULL, NULL); + NRF53_TIM_STOP(priv->tim); + + priv->started = false; + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_timer_getstatus + * + * Description: + * get timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * status - The location to return the status information. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf53_timer_getstatus(struct timer_lowerhalf_s *lower, + struct timer_status_s *status) +{ + struct nrf53_timer_lowerhalf_s *priv = + (struct nrf53_timer_lowerhalf_s *)lower; + + DEBUGASSERT(priv); + DEBUGASSERT(status); + + /* Return the status bit */ + + status->flags = 0; + + if (priv->started == true) + { + status->flags |= TCFLAGS_ACTIVE; + } + + if (priv->callback) + { + status->flags |= TCFLAGS_HANDLER; + } + + /* TODO: timeout and time left */ + + status->timeout = 0; + status->timeleft = 0; + + return OK; +} + +/**************************************************************************** + * Name: nrf53_timer_settimeout + * + * Description: + * Set a new timeout value (and reset the timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * timeout - The new timeout value in microseconds. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nrf53_timer_settimeout(struct timer_lowerhalf_s *lower, + uint32_t timeout) +{ + struct nrf53_timer_lowerhalf_s *priv = + (struct nrf53_timer_lowerhalf_s *)lower; + uint64_t cc = 0; + int ret = OK; + + DEBUGASSERT(priv); + + if (priv->started == true) + { + ret = -EPERM; + goto errout; + } + + if (timeout > NRF53_TIMER_MAX) + { + ret = -EINVAL; + goto errout; + } + + cc = (timeout / 1000000) * NRF53_TIMER_PER; + NRF53_TIM_SETCC(priv->tim, NRF53_TIMER_CC, cc); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_setcallback + * + * Description: + * Call this user provided timeout handler. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * callback - The new timer expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * arg - Argument that will be provided in the callback + * + * Returned Value: + * The previous timer expiration function pointer or NULL is there was + * no previous function pointer. + * + ****************************************************************************/ + +static void nrf53_timer_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, void *arg) +{ + struct nrf53_timer_lowerhalf_s *priv = + (struct nrf53_timer_lowerhalf_s *)lower; + irqstate_t flags; + + DEBUGASSERT(priv); + + flags = enter_critical_section(); + + /* Save the new callback */ + + priv->callback = callback; + priv->arg = arg; + + if (callback != NULL && priv->started == true) + { + NRF53_TIM_SETISR(priv->tim, nrf53_timer_handler, priv); + NRF53_TIM_ENABLEINT(priv->tim, NRF53_TIMER_INT); + } + else + { + NRF53_TIM_DISABLEINT(priv->tim, NRF53_TIMER_INT); + NRF53_TIM_SETISR(priv->tim, NULL, NULL); + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_timer_initialize + * + * Description: + * Bind the configuration timer to a timer lower half instance and + * register the timer drivers at 'devpath' + * + * Input Parameters: + * devpath - The full path to the timer device. This should be of the + * form /dev/timer0 + * timer - the timer's number. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int nrf53_timer_initialize(const char *devpath, uint8_t timer) +{ + struct nrf53_timer_lowerhalf_s *lower = NULL; + void *drvr = NULL; + int ret = OK; + + DEBUGASSERT(devpath); + + switch (timer) + { +#ifdef CONFIG_NRF53_TIMER0 + case 0: + { + lower = &g_nrf53_timer0_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER1 + case 1: + { + lower = &g_nrf53_timer1_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER2 + case 2: + { + lower = &g_nrf53_timer2_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER3 + case 3: + { + lower = &g_nrf53_timer3_lowerhalf; + break; + } +#endif + +#ifdef CONFIG_NRF53_TIMER4 + case 4: + { + lower = &g_nrf53_timer4_lowerhalf; + break; + } +#endif + + default: + { + ret = -ENODEV; + goto errout; + } + } + + /* Initialize the elements of lower half state structure */ + + lower->started = false; + lower->callback = NULL; + lower->tim = nrf53_tim_init(timer); + + if (lower->tim == NULL) + { + ret = -EINVAL; + goto errout; + } + + /* Register the timer driver as /dev/timerX. The returned value from + * timer_register is a handle that could be used with timer_unregister(). + * REVISIT: The returned handle is discard here. + */ + + drvr = timer_register(devpath, (struct timer_lowerhalf_s *)lower); + if (drvr == NULL) + { + /* The actual cause of the failure may have been a failure to allocate + * perhaps a failure to register the timer driver (such as if the + * 'depath' were not unique). We know here but we return EEXIST to + * indicate the failure (implying the non-unique devpath). + */ + + ret = -EEXIST; + goto errout; + } + +errout: + return ret; +} diff --git a/arch/arm/src/nrf53/nrf53_tim_lowerhalf.h b/arch/arm/src/nrf53/nrf53_tim_lowerhalf.h new file mode 100644 index 0000000000..02a98c4c6e --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_tim_lowerhalf.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_tim_lowerhalf.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF53_NRF53_TIM_LOWERHALF_H +#define __ARCH_ARM_SRC_NRF53_NRF53_TIM_LOWERHALF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_timer_initialize + ****************************************************************************/ + +int nrf53_timer_initialize(const char *devpath, uint8_t timer); + +#endif /* __ARCH_ARM_SRC_NRF53_NRF53_TIM_LOWERHALF_H */