From c6317650f9a4e540b2290dc7c71685cc77da14ee Mon Sep 17 00:00:00 2001 From: "Virus.V" Date: Wed, 26 May 2021 14:19:29 +0800 Subject: [PATCH] risc-v/bl602: Add RTC support --- arch/risc-v/src/bl602/Kconfig | 8 + arch/risc-v/src/bl602/Make.defs | 3 + arch/risc-v/src/bl602/bl602_hbn.c | 233 ++++++ arch/risc-v/src/bl602/bl602_hbn.h | 123 ++++ arch/risc-v/src/bl602/bl602_rtc.c | 187 +++++ arch/risc-v/src/bl602/bl602_rtc.h | 170 +++++ arch/risc-v/src/bl602/bl602_rtc_lowerhalf.c | 689 ++++++++++++++++++ .../risc-v/bl602/bl602evb/src/bl602_bringup.c | 29 + 8 files changed, 1442 insertions(+) create mode 100644 arch/risc-v/src/bl602/bl602_rtc.c create mode 100644 arch/risc-v/src/bl602/bl602_rtc.h create mode 100644 arch/risc-v/src/bl602/bl602_rtc_lowerhalf.c diff --git a/arch/risc-v/src/bl602/Kconfig b/arch/risc-v/src/bl602/Kconfig index b68dab4070..5d97addcfe 100644 --- a/arch/risc-v/src/bl602/Kconfig +++ b/arch/risc-v/src/bl602/Kconfig @@ -45,6 +45,14 @@ config BL602_I2C0 config BL602_SPI0 bool "SPI0" +config BL602_RTC + bool "RTC" + +config BL602_RTC_USE_XTAL32K + bool "Select enable RTC XTAL32K clock source, otherwise use internal RC32K" + default n + depends on BL602_RTC + config BL602_SPIFLASH bool "SPI Flash" default n diff --git a/arch/risc-v/src/bl602/Make.defs b/arch/risc-v/src/bl602/Make.defs index cddc3a8c25..f0af3cb0a5 100644 --- a/arch/risc-v/src/bl602/Make.defs +++ b/arch/risc-v/src/bl602/Make.defs @@ -75,6 +75,9 @@ endif ifeq ($(CONFIG_BL602_SPIFLASH),y) CHIP_CSRCS += bl602_flash.c bl602_spiflash.c endif +ifeq ($(CONFIG_RTC_DRIVER),y) +CHIP_CSRCS += bl602_rtc.c bl602_rtc_lowerhalf.c +endif CHIP_CSRCS += bl602_glb.c bl602_gpio.c bl602_hbn.c bl602_systemreset.c diff --git a/arch/risc-v/src/bl602/bl602_hbn.c b/arch/risc-v/src/bl602/bl602_hbn.c index 10726adf78..7573871690 100644 --- a/arch/risc-v/src/bl602/bl602_hbn.c +++ b/arch/risc-v/src/bl602/bl602_hbn.c @@ -22,9 +22,85 @@ * Included Files ****************************************************************************/ +#include "nuttx/arch.h" #include "hardware/bl602_hbn.h" +#include "bl602_hbn.h" +#include "bl602_rtc.h" #include "riscv_arch.h" +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct bl602_hbn_info_s +{ + bl602_hbn_cb_t out0_callback[3]; + void *out0_arg[3]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct bl602_hbn_info_s g_bl602_hbn_info; + +/**************************************************************************** + * Name: bl602_hbn_irq + ****************************************************************************/ + +static int bl602_hbn_irq(int irq, void *context, void *p_arg) +{ + bl602_hbn_cb_t isr_cb; + void *arg; + + /* GPIO7 GPIO8 and RTC */ + + if (bl602_hbn_get_int_state(BL602_HBN_INT_GPIO7)) + { + /* gpio7 sync/async mode */ + + bl602_hbn_clear_irq(BL602_HBN_INT_GPIO7); + + isr_cb = g_bl602_hbn_info.out0_callback[BL602_HBN_OUT0_INT_GPIO7]; + arg = g_bl602_hbn_info.out0_arg[BL602_HBN_OUT0_INT_GPIO7]; + + if (isr_cb) + { + isr_cb(arg); + } + } + + if (bl602_hbn_get_int_state(BL602_HBN_INT_GPIO8)) + { + /* gpio8 sync/async mode */ + + bl602_hbn_clear_irq(BL602_HBN_INT_GPIO8); + + isr_cb = g_bl602_hbn_info.out0_callback[BL602_HBN_OUT0_INT_GPIO8]; + arg = g_bl602_hbn_info.out0_arg[BL602_HBN_OUT0_INT_GPIO8]; + + if (isr_cb) + { + isr_cb(arg); + } + } + + if (bl602_hbn_get_int_state(BL602_HBN_INT_RTC)) + { + bl602_hbn_clear_irq(BL602_HBN_INT_RTC); + bl602_hbn_clear_rtc_int(); + + isr_cb = g_bl602_hbn_info.out0_callback[BL602_HBN_OUT0_INT_RTC]; + arg = g_bl602_hbn_info.out0_arg[BL602_HBN_OUT0_INT_RTC]; + + if (isr_cb) + { + isr_cb(arg); + } + } + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -64,3 +140,160 @@ void bl602_aon_pad_iesmt_cfg(uint8_t pad_cfg) modifyreg32(BL602_HBN_IRQ_MODE, HBN_IRQ_MODE_REG_AON_PAD_IE_SMT, pad_cfg << 8); } + +/**************************************************************************** + * Name: bl602_hbn_get_int_state + * + * Description: + * HBN get interrupt status. + * + * Input Parameters: + * irq_type: HBN interrupt type + * + * Returned Value: + * true or false + * + ****************************************************************************/ + +bool bl602_hbn_get_int_state(uint8_t irq_type) +{ + uint32_t tmp_val; + + /* Check the parameters */ + + tmp_val = getreg32(BL602_HBN_IRQ_STAT); + + if (tmp_val & (1 << irq_type)) + { + return true; + } + + return false; +} + +/**************************************************************************** + * Name: bl602_hbn_clear_irq + * + * Description: + * HBN clear interrupt status. + * + * Input Parameters: + * hbn_int_type: HBN interrupt type + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bl602_hbn_clear_irq(uint8_t hbn_int_type) +{ + modifyreg32(BL602_HBN_IRQ_CLR, 0, 1 << hbn_int_type); + modifyreg32(BL602_HBN_IRQ_CLR, 1 << hbn_int_type, 0); +} + +/**************************************************************************** + * Name: bl602_hbn_out0_int_register + * + * Description: + * HBN out0 interrupt cllback register. + * + * Input Parameters: + * irq_type: HBN interrupt type + * isr_cb: callback + * arg: callback arg + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +int bl602_hbn_out0_int_register(uint8_t irq_type, bl602_hbn_cb_t isr_cb, + void *arg) +{ + irqstate_t flags; + + if (irq_type > 2) + { + return -EINVAL; + } + + flags = enter_critical_section(); + g_bl602_hbn_info.out0_callback[irq_type] = isr_cb; + g_bl602_hbn_info.out0_arg[irq_type] = arg; + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: bl602_hbn_out0_int_unregister + * + * Description: + * HBN out0 interrupt cllback unregister. + * + * Input Parameters: + * irq_type: HBN interrupt type + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +int bl602_hbn_out0_int_unregister(uint8_t irq_type) +{ + irqstate_t flags; + + if (irq_type > 2) + { + return -EINVAL; + } + + flags = enter_critical_section(); + g_bl602_hbn_info.out0_callback[irq_type] = NULL; + g_bl602_hbn_info.out0_arg[irq_type] = NULL; + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: bl602_hbn_out0_int_enable + * + * Description: + * HBN out0 interrupt enable. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_out0_int_enable(void) +{ + irq_attach(BL602_IRQ_HBN_OUT0, bl602_hbn_irq, NULL); + up_enable_irq(BL602_IRQ_HBN_OUT0); +} + +/**************************************************************************** + * Name: bl602_hbn_out0_int_disable + * + * Description: + * HBN out0 interrupt disable. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_out0_int_disable(void) +{ + irq_detach(BL602_IRQ_HBN_OUT0); + up_disable_irq(BL602_IRQ_HBN_OUT0); +} diff --git a/arch/risc-v/src/bl602/bl602_hbn.h b/arch/risc-v/src/bl602/bl602_hbn.h index b6808e1010..d09248cb25 100644 --- a/arch/risc-v/src/bl602/bl602_hbn.h +++ b/arch/risc-v/src/bl602/bl602_hbn.h @@ -26,7 +26,11 @@ ****************************************************************************/ #include +#include +#include +#include +#include #include /**************************************************************************** @@ -44,6 +48,24 @@ extern "C" #define EXTERN extern #endif +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BL602_HBN_OUT0_INT_GPIO7 (0) /* HBN out 0 interrupt type: GPIO7 */ +#define BL602_HBN_OUT0_INT_GPIO8 (1) /* HBN out 0 interrupt type: GPIO8 */ +#define BL602_HBN_OUT0_INT_RTC (2) /* HBN out 0 interrupt type: RTC */ + +#define BL602_HBN_INT_GPIO7 (0) /* HBN interrupt type: GPIO7 */ +#define BL602_HBN_INT_GPIO8 (1) /* HBN interrupt type: GPIO8 */ +#define BL602_HBN_INT_RTC (16) /* HBN interrupt type: RTC */ +#define BL602_HBN_INT_PIR (17) /* HBN interrupt type: PIR */ +#define BL602_HBN_INT_BOR (18) /* HBN interrupt type: BOR */ +#define BL602_HBN_INT_ACOMP0 (20) /* HBN interrupt type: ACOMP0 */ +#define BL602_HBN_INT_ACOMP1 (22) /* HBN interrupt type: ACOMP1 */ + +typedef CODE int (*bl602_hbn_cb_t)(FAR void *arg); + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -68,6 +90,107 @@ extern "C" void bl602_set_uart_clk_sel(int clk_sel); +/**************************************************************************** + * Name: bl602_hbn_get_int_state + * + * Description: + * HBN get interrupt status. + * + * Input Parameters: + * irq_type: HBN interrupt type + * + * Returned Value: + * true or false + * + ****************************************************************************/ + +bool bl602_hbn_get_int_state(uint8_t irq_type); + +/**************************************************************************** + * Name: bl602_hbn_clear_irq + * + * Description: + * HBN clear interrupt status. + * + * Input Parameters: + * hbn_int_type: HBN interrupt type + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bl602_hbn_clear_irq(uint8_t hbn_int_type); + +/**************************************************************************** + * Name: bl602_hbn_out0_int_register + * + * Description: + * HBN out0 interrupt cllback register. + * + * Input Parameters: + * irq_type: HBN interrupt type + * isr_cb: callback + * arg: callback arg + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +int bl602_hbn_out0_int_register(uint8_t irq_type, bl602_hbn_cb_t isr_cb, + void *arg); + +/**************************************************************************** + * Name: bl602_hbn_out0_int_unregister + * + * Description: + * HBN out0 interrupt cllback unregister. + * + * Input Parameters: + * irq_type: HBN interrupt type + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +int bl602_hbn_out0_int_unregister(uint8_t irq_type); + +/**************************************************************************** + * Name: bl602_hbn_out0_int_enable + * + * Description: + * HBN out0 interrupt enable. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_out0_int_enable(void); + +/**************************************************************************** + * Name: bl602_hbn_out0_int_disable + * + * Description: + * HBN out0 interrupt disable. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_out0_int_disable(void); + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/risc-v/src/bl602/bl602_rtc.c b/arch/risc-v/src/bl602/bl602_rtc.c new file mode 100644 index 0000000000..7392f1ebea --- /dev/null +++ b/arch/risc-v/src/bl602/bl602_rtc.c @@ -0,0 +1,187 @@ +/**************************************************************************** + * arch/risc-v/src/bl602/bl602_rtc.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 "riscv_arch.h" + +#include "chip.h" +#include "hardware/bl602_hbn.h" +#include "bl602_rtc.h" + +#define ROM_APITABLE ((uint32_t *)0x21010800) +#define ROMAPI_HBN_32K_SEL (ROM_APITABLE + 66) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef void (*bl602_romapi_hbn_sel_t)(uint8_t clk_type); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bl602_hbn_sel + * + * Description: + * HBN select 32K + * + * Input Parameters: + * clk_type: HBN 32k clock type + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_sel(uint8_t clk_type) +{ + modifyreg32(BL602_HBN_GLB, + HBN_GLB_HBN_F32K_SEL_MASK, + clk_type << HBN_GLB_HBN_F32K_SEL_SHIFT); +} + +/**************************************************************************** + * Name: bl602_hbn_clear_rtc_int + * + * Description: + * HBN clear RTC timer interrupt,this function must be called to clear + * delayed rtc IRQ + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_clear_rtc_int(void) +{ + /* Clear RTC commpare:bit1-3 for clearing Delayed RTC IRQ */ + + modifyreg32(BL602_HBN_CTL, 0x7 << 1, 0); +} + +/**************************************************************************** + * Name: bl602_hbn_set_rtc_timer + * + * Description: + * HBN set RTC timer configuration + * + * Input Parameters: + * delay: RTC interrupt delay 32 clocks + * compval_low: RTC interrupt commpare value low 32 bits + * compval_high: RTC interrupt commpare value high 32 bits + * comp_mode: RTC interrupt commpare + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_set_rtc_timer(uint8_t delay_type, uint32_t compval_low, + uint32_t compval_high, uint8_t comp_mode) +{ + putreg32(compval_low, BL602_HBN_TIME_L); + putreg32(compval_high & 0xff, BL602_HBN_TIME_H); + + modifyreg32(BL602_HBN_CTL, + HBN_CTL_RTC_DLY_OPTION | (0x7 << 1), + delay_type | (comp_mode << 1)); +} + +/**************************************************************************** + * Name: bl602_hbn_clear_rtc_counter + * + * Description: + * HBN set RTC timer configuration + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_clear_rtc_counter(void) +{ + modifyreg32(BL602_HBN_CTL, 1, 0); +} + +/**************************************************************************** + * Name: bl602_hbn_enable_rtc_counter + * + * Description: + * HBN clear RTC timer counter + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_enable_rtc_counter(void) +{ + modifyreg32(BL602_HBN_CTL, 0, 1); +} + +/**************************************************************************** + * Name: bl602_hbn_get_rtc_timer_val + * + * Description: + * HBN get RTC timer count value + * + * Input Parameters: + * val_low: RTC count value pointer for low 32 bits + * val_high: RTC count value pointer for high 8 bits + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_hbn_get_rtc_timer_val(uint32_t *val_low, uint32_t *val_high) +{ + modifyreg32(BL602_HBN_RTC_TIME_H, 0, HBN_RTC_TIME_H_RTC_TIME_LATCH); + + modifyreg32(BL602_HBN_RTC_TIME_H, HBN_RTC_TIME_H_RTC_TIME_LATCH, 0); + + *val_low = getreg32(BL602_HBN_RTC_TIME_L); + *val_high = getreg32(BL602_HBN_RTC_TIME_H) & 0xff; +} + diff --git a/arch/risc-v/src/bl602/bl602_rtc.h b/arch/risc-v/src/bl602/bl602_rtc.h new file mode 100644 index 0000000000..c6cfe500a8 --- /dev/null +++ b/arch/risc-v/src/bl602/bl602_rtc.h @@ -0,0 +1,170 @@ +/**************************************************************************** + * arch/risc-v/src/bl602/bl602_rtc.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_RISCV_SRC_BL602_RTC_LOWERHALF_H +#define __ARCH_RISCV_SRC_BL602_RTC_LOWERHALF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BL602_HBN_32K_RC 0 /* HBN use rc 32k */ +#define BL602_HBN_32K_XTAL 1 /* HBN use xtal 32k */ +#define BL602_HBN_32K_DIG 3 /* HBN use dig 32k */ + +#define BL602_HBN_RTC_INT_DELAY_32T 0 /* HBN RTC int delay 32T */ +#define BL602_HBN_RTC_INT_DELAY_0T 1 /* HBN RTC int delay 0T */ + +#define BL602_HBN_RTC_COMP_BIT0_39 0x01 /* RTC COMP mode bit0-39 */ +#define BL602_HBN_RTC_COMP_BIT0_23 0x02 /* RTC COMP mode bit0-23 */ +#define BL602_HBN_RTC_COMP_BIT13_39 0x04 /* RTC COMP mode bit13-39 */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: bl602_hbn_sel + * + * Description: + * HBN select 32K + * + * Input Parameters: + * clk_type: HBN 32k clock type + * + * Returned Value: + * None. + * + ****************************************************************************/ + +FAR void bl602_hbn_sel(uint8_t clk_type); + +/**************************************************************************** + * Name: bl602_hbn_clear_rtc_int + * + * Description: + * HBN clear RTC timer interrupt,this function must be called to clear + * delayed rtc IRQ + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +FAR void bl602_hbn_clear_rtc_int(void); + +/**************************************************************************** + * Name: bl602_hbn_set_rtc_timer + * + * Description: + * HBN set RTC timer configuration + * + * Input Parameters: + * delay: RTC interrupt delay 32 clocks + * compval_low: RTC interrupt commpare value low 32 bits + * compval_high: RTC interrupt commpare value high 32 bits + * comp_mode: RTC interrupt commpare + * + * Returned Value: + * None. + * + ****************************************************************************/ + +FAR void bl602_hbn_set_rtc_timer(uint8_t delay_type, uint32_t compval_low, + uint32_t compval_high, uint8_t comp_mode); + +/**************************************************************************** + * Name: bl602_hbn_clear_rtc_counter + * + * Description: + * HBN set RTC timer configuration + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +FAR void bl602_hbn_clear_rtc_counter(void); + +/**************************************************************************** + * Name: bl602_hbn_enable_rtc_counter + * + * Description: + * HBN clear RTC timer counter + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +FAR void bl602_hbn_enable_rtc_counter(void); + +/**************************************************************************** + * Name: bl602_hbn_get_rtc_timer_val + * + * Description: + * HBN get RTC timer count value + * + * Input Parameters: + * val_low: RTC count value pointer for low 32 bits + * val_high: RTC count value pointer for high 8 bits + * + * Returned Value: + * None. + * + ****************************************************************************/ + +FAR void bl602_hbn_get_rtc_timer_val(uint32_t *val_low, uint32_t *val_high); + +/**************************************************************************** + * Name: bl602_rtc_lowerhalf_initialize + * + * Description: + * None. + * + * Input Parameters: + * pwm - A number identifying the pwm instance. + * + * Returned Value: + * On success, a pointer to the BL602 lower half PWM driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *bl602_rtc_lowerhalf_initialize(void); + +#endif /* __ARCH_RISCV_SRC_BL602_RTC_LOWERHALF_H */ diff --git a/arch/risc-v/src/bl602/bl602_rtc_lowerhalf.c b/arch/risc-v/src/bl602/bl602_rtc_lowerhalf.c new file mode 100644 index 0000000000..dc178b7fa4 --- /dev/null +++ b/arch/risc-v/src/bl602/bl602_rtc_lowerhalf.c @@ -0,0 +1,689 @@ +/**************************************************************************** + * arch/risc-v/src/bl602/bl602_rtc_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 "riscv_arch.h" + +#include "chip.h" +#include "hardware/bl602_hbn.h" +#include "bl602_hbn.h" +#include "bl602_rtc.h" +#include "time.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +struct bl602_cbinfo_s +{ + rtc_alarm_callback_t cb; /* Callback when the alarm expires */ + FAR void *priv; /* Private argument to accompany callback */ +}; +#endif + +/* This is the private type for the RTC state. It must be cast compatible + * with struct rtc_lowerhalf_s. + */ + +struct bl602_lowerhalf_s +{ + /* This is the contained reference to the read-only, lower-half + * operations vtable (which may lie in FLASH or ROM) + */ + + FAR const struct rtc_ops_s *ops; + + /* Data following is private to this driver and not visible outside of + * this file. + */ + + sem_t devsem; /* Threads can only exclusively access the RTC */ + + struct rtc_time rtc_base; + struct rtc_time rtc_alarm; + +#ifdef CONFIG_RTC_ALARM + /* Alarm callback information */ + + struct bl602_cbinfo_s cbinfo; +#endif + +#ifdef CONFIG_RTC_PERIODIC + /* Periodic wakeup information */ + + uint8_t periodic_enable; + struct lower_setperiodic_s periodic; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Prototypes for static methods in struct rtc_ops_s */ + +static int bl602_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime); +static int bl602_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime); +static bool bl602_havesettime(FAR struct rtc_lowerhalf_s *lower); + +#ifdef CONFIG_RTC_ALARM +static int bl602_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo); +static int bl602_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo); +static int bl602_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid); +static int bl602_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo); +#endif + +#ifdef CONFIG_RTC_PERIODIC +static int bl602_setperiodic(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setperiodic_s *alarminfo); +static int bl602_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* BL602 RTC driver operations */ + +static const struct rtc_ops_s g_rtc_ops = +{ + .rdtime = bl602_rdtime, + .settime = bl602_settime, + .havesettime = bl602_havesettime, +#ifdef CONFIG_RTC_ALARM + .setalarm = bl602_setalarm, + .setrelative = bl602_setrelative, + .cancelalarm = bl602_cancelalarm, + .rdalarm = bl602_rdalarm, +#endif +#ifdef CONFIG_RTC_PERIODIC + .setperiodic = bl602_setperiodic, + .cancelperiodic = bl602_cancelperiodic, +#endif +#ifdef CONFIG_RTC_IOCTL + .ioctl = NULL, +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + .destroy = NULL, +#endif +}; + +/* BL602 RTC device state */ + +static struct bl602_lowerhalf_s g_rtc_lowerhalf = +{ + .ops = &g_rtc_ops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint64_t bl602_rtc_get_timestamp_ms(void) +{ + uint64_t cnt; + uint32_t val_low; + uint32_t val_high; + + bl602_hbn_get_rtc_timer_val(&val_low, &val_high); + + cnt = (uint64_t)val_high << 32 | val_low; + + /* cnt * 1000 / 32768 */ + + return (cnt >> 5) - (cnt >> 11) - (cnt >> 12); +} + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_PERIODIC) +static void bl602_rtc_set_timestamp_ms(uint64_t ms) +{ + ms += bl602_rtc_get_timestamp_ms(); + ms = ms * 32768 / 1000; + + bl602_hbn_set_rtc_timer(BL602_HBN_RTC_INT_DELAY_0T, + (uint32_t)ms, + (uint32_t)(ms >> 32), + BL602_HBN_RTC_COMP_BIT0_39); +} +#endif + +/**************************************************************************** + * Name: bl602_alarm_callback + * + * Description: + * This is the function that is called from the RTC driver when the alarm + * goes off. It just invokes the upper half drivers callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_PERIODIC) +static int bl602_alarm_callback(void *arg) +{ + struct bl602_lowerhalf_s *priv = (struct bl602_lowerhalf_s *)arg; + struct bl602_cbinfo_s *cbinfo = &priv->cbinfo; + + rtc_alarm_callback_t cb = (rtc_alarm_callback_t)cbinfo->cb; + FAR void *p_arg = (FAR void *)cbinfo->priv; + +#ifdef CONFIG_RTC_PERIODIC + if (priv->periodic_enable) + { + uint64_t time_stamp_s; + struct timespec *tm_spec = &priv->periodic.period; + + time_stamp_s = tm_spec->tv_sec; + + if (time_stamp_s) + { + bl602_rtc_set_timestamp_ms(time_stamp_s * 1000); + bl602_hbn_out0_int_enable(); + } + + if (priv->periodic.cb) + { + priv->periodic.cb(priv->periodic.priv, priv->periodic.id); + } + } +#endif + + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(p_arg, 0); + } + + return OK; +} +#endif /* CONFIG_RTC_ALARM */ + +/**************************************************************************** + * Name: bl602_rdtime + * + * Description: + * Implements the rdtime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The location in which to return the current RTC time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int bl602_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime) +{ + struct bl602_lowerhalf_s *priv; + uint64_t time_stamp_s; + struct rtc_time tim; + + priv = (FAR struct bl602_lowerhalf_s *)lower; + time_stamp_s = bl602_rtc_get_timestamp_ms() / 1000; + + tim = priv->rtc_base; + + if (tim.tm_year >= 1900) + { + tim.tm_year -= 1900; + } + + time_stamp_s += mktime((FAR struct tm *)&tim); + gmtime_r((const time_t *)&time_stamp_s, (FAR struct tm *)&rtctime); + + return OK; +} + +/**************************************************************************** + * Name: bl602_settime + * + * Description: + * Implements the settime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The new time to set + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int bl602_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime) +{ + struct bl602_lowerhalf_s *priv = (FAR struct bl602_lowerhalf_s *)lower; + + if (rtctime->tm_year < 1900) + { + return -ETIME; + } + + priv->rtc_base = *rtctime; + + return OK; +} + +/**************************************************************************** + * Name: bl602_havesettime + * + * Description: + * Implements the havesettime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +static bool bl602_havesettime(FAR struct rtc_lowerhalf_s *lower) +{ + struct bl602_lowerhalf_s *priv = (FAR struct bl602_lowerhalf_s *)lower; + + return (priv->rtc_base.tm_year != 0); +} + +/**************************************************************************** + * Name: bl602_setalarm + * + * Description: + * Set a new alarm. This function implements the setalarm() method of the + * RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int bl602_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo) +{ + FAR struct bl602_lowerhalf_s *priv; + FAR struct bl602_cbinfo_s *cbinfo; + int ret; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0); + priv = (FAR struct bl602_lowerhalf_s *)lower; + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + + ret = -EINVAL; + if (alarminfo->id == 0) + { + uint64_t time_stamp_s; + + /* Convert the RTC time to a timespec */ + + time_stamp_s = mktime((FAR struct tm *)&alarminfo->time); + priv->rtc_alarm = alarminfo->time; + + /* Remember the callback information */ + + cbinfo = &priv->cbinfo; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + + /* And set the alarm */ + + bl602_rtc_set_timestamp_ms(time_stamp_s * 1000); + + bl602_hbn_out0_int_enable(); + + ret = OK; + } + + nxsem_post(&priv->devsem); + + return ret; +} +#endif + +/**************************************************************************** + * Name: bl602_setrelative + * + * Description: + * Set a new alarm relative to the current time. This function implements + * the setrelative() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int bl602_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo) +{ + FAR struct bl602_lowerhalf_s *priv; + struct lower_setalarm_s setalarm; + struct rtc_time *time; + time_t seconds; + int ret = -EINVAL; + + priv = (FAR struct bl602_lowerhalf_s *)lower; + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + + if (alarminfo->id == 0 && alarminfo->reltime > 0) + { + /* Get the current time in broken out format */ + + time = &priv->rtc_base; + + /* Convert to seconds since the epoch */ + + seconds = mktime((struct tm *)time); + + /* Add the seconds offset. Add one to the number of seconds + * because we are unsure of the phase of the timer. + */ + + seconds += (alarminfo->reltime + 1); + + /* And convert the time back to broken out format */ + + gmtime_r(&seconds, (FAR struct tm *)&setalarm.time); + + /* The set the alarm using this absolute time */ + + setalarm.id = alarminfo->id; + setalarm.cb = alarminfo->cb; + setalarm.priv = alarminfo->priv; + + ret = bl602_setalarm(lower, &setalarm); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: bl602_cancelalarm + * + * Description: + * Cancel the current alarm. This function implements the cancelalarm() + * method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int bl602_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid) +{ + FAR struct bl602_lowerhalf_s *priv; + FAR struct bl602_cbinfo_s *cbinfo; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(alarmid == 0); + priv = (FAR struct bl602_lowerhalf_s *)lower; + + /* Nullify callback information to reduce window for race conditions */ + + cbinfo = &priv->cbinfo; + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + memset(&priv->rtc_alarm, 0, sizeof(priv->rtc_alarm)); + + /* Then cancel the alarm */ + + bl602_hbn_out0_int_unregister(BL602_HBN_OUT0_INT_RTC); + bl602_hbn_out0_int_disable(); + + return OK; +} +#endif + +/**************************************************************************** + * Name: bl602_rdalarm + * + * Description: + * Query the RTC alarm. + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to query the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int bl602_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo) +{ + FAR struct bl602_lowerhalf_s *priv; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->time != NULL); + priv = (FAR struct bl602_lowerhalf_s *)lower; + + if (alarminfo->id == 0) + { + *alarminfo->time = priv->rtc_alarm; + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: bl602_setperiodic + * + * Description: + * Set a new periodic wakeup relative to the current time, with a given + * period. This function implements the setperiodic() method of the RTC + * driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the wakeup activity + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int bl602_setperiodic(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setperiodic_s *alarminfo) +{ + FAR struct bl602_lowerhalf_s *priv; + irqstate_t flags; + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + priv = (FAR struct bl602_lowerhalf_s *)lower; + + flags = enter_critical_section(); + priv->periodic = *alarminfo; + priv->periodic_enable = 1; + memcpy(&priv->periodic, alarminfo, sizeof(struct lower_setperiodic_s)); + leave_critical_section(flags); + + return OK; +} +#endif + +/**************************************************************************** + * Name: bl602_cancelperiodic + * + * Description: + * Cancel the current periodic wakeup activity. This function implements + * the cancelperiodic() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int bl602_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id) +{ + FAR struct bl602_lowerhalf_s *priv; + irqstate_t flags; + + DEBUGASSERT(lower != NULL); + priv = (FAR struct bl602_lowerhalf_s *)lower; + + DEBUGASSERT(id == 0); + + flags = enter_critical_section(); + priv->periodic_enable = 0; + leave_critical_section(flags); + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected configuration. This + * function is called once during the OS initialization sequence + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_initialize(void) +{ +#ifdef CONFIG_BL602_RTC_USE_XTAL32K + bl602_hbn_sel(BL602_HBN_32K_XTAL); +#else + bl602_hbn_sel(BL602_HBN_32K_RC); +#endif + + bl602_hbn_clear_rtc_counter(); + bl602_hbn_enable_rtc_counter(); + + bl602_hbn_out0_int_register(BL602_HBN_OUT0_INT_RTC, + bl602_alarm_callback, + (void *)&g_rtc_lowerhalf); + return OK; +} + +/**************************************************************************** + * Name: bl602_rtc_lowerhalf_initialize + * + * Description: + * Instantiate the RTC lower half driver for the BL602. General usage: + * + * #include + * #include "bl602_rtc.h" + * + * struct rtc_lowerhalf_s *lower; + * lower = bl602_rtc_lowerhalf_initialize(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *bl602_rtc_lowerhalf_initialize(void) +{ + nxsem_init(&g_rtc_lowerhalf.devsem, 0, 1); + +#ifdef CONFIG_RTC_PERIODIC + g_rtc_lowerhalf.periodic_enable = 0; +#endif + memset(&g_rtc_lowerhalf.rtc_base, 0, sizeof(g_rtc_lowerhalf.rtc_base)); + + return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf; +} diff --git a/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c b/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c index 80dfbf9b45..91994fa213 100644 --- a/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c +++ b/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #if defined(CONFIG_BL602_SPIFLASH) #include @@ -275,6 +277,33 @@ int bl602_bringup(void) bl602_net_initialize(0); #endif +#ifdef CONFIG_RTC_DRIVER + /* Instantiate the BL602 lower-half RTC driver */ + + FAR struct rtc_lowerhalf_s *lower; + + lower = bl602_rtc_lowerhalf_initialize(); + if (!lower) + { + syslog(LOG_ERR, + "ERROR: Failed to instantiate the RTC lower-half driver\n"); + } + else + { + /* Bind the lower half driver and register the combined RTC driver + * as /dev/rtc0 + */ + + ret = rtc_initialize(0, lower); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to bind/register the RTC driver: %d\n", + ret); + } + } +#endif + #if defined(CONFIG_BL602_BLE_CONTROLLER) bl602_hci_uart_init(0);