From 55f45b9851ea14d4aec683d24432e849e44c64dc Mon Sep 17 00:00:00 2001 From: Daniel Kampert Date: Tue, 28 May 2024 14:08:25 +0200 Subject: [PATCH] - Update bosch_bmi270_types.h - Add RV-8263-C8 driver - Couple smaller changes --- .../zswatch_nrf5340_cpuapp_5.conf | 6 +- .../zswatch_nrf5340_cpuapp_5.overlay | 3 +- app/drivers/rtc/CMakeLists.txt | 2 +- app/drivers/rtc/rv8263c8/CMakeLists.txt | 8 +- app/drivers/rtc/rv8263c8/Kconfig | 113 ++- .../microcrystal_rv8263c8_interrupt.c | 70 -- .../microcrystal_rv8263c8_interrupt.h | 15 - .../rtc/rv8263c8/microcrystal_rv8263c8.c | 814 ++++++++++++++---- .../rtc/rv8263c8/microcrystal_rv8263c8.h | 22 - .../private/microcrystal_rv8263c8_types.h | 36 - app/drivers/sensor/apds9306/Kconfig | 2 +- app/drivers/sensor/bmi270/Kconfig | 2 +- .../bmi270/private/bosch_bmi270_types.h | 28 +- app/drivers/sensor/bmp581/Kconfig | 2 +- .../bindings/rtc/microcrystal,rv-8263-c8.yml | 20 +- 15 files changed, 754 insertions(+), 389 deletions(-) delete mode 100644 app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.c delete mode 100644 app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.h delete mode 100644 app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.h delete mode 100644 app/drivers/rtc/rv8263c8/private/microcrystal_rv8263c8_types.h diff --git a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf index 20ce8c79..97ef031a 100644 --- a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf +++ b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.conf @@ -48,4 +48,8 @@ CONFIG_NVS=y CONFIG_DEBUG_COREDUMP_BACKEND_OTHER=y CONFIG_RTC=y -CONFIG_RTC_ALARM=y \ No newline at end of file +CONFIG_RTC_ALARM=y +CONFIG_RTC_RV8263_ALARM_OWN_THREAD=y +CONFIG_RTC_UPDATE=y +CONFIG_RTC_RV8263_UPDATE_OWN_THREAD=y +CONFIG_RTC_CALIBRATION=y \ No newline at end of file diff --git a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay index 935d6b40..ad548e8f 100644 --- a/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay +++ b/app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_cpuapp_5.overlay @@ -193,7 +193,8 @@ compatible = "microcrystal,rv-8263-c8"; reg = <0xA2>; status = "okay"; - clkout = <7>; + clkout = <0>; + int-gpios = <&gpio1 13 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; }; bmi270: bmi270@68 { diff --git a/app/drivers/rtc/CMakeLists.txt b/app/drivers/rtc/CMakeLists.txt index a095c974..720d23ca 100644 --- a/app/drivers/rtc/CMakeLists.txt +++ b/app/drivers/rtc/CMakeLists.txt @@ -3,4 +3,4 @@ # SPDX-License-Identifier: Apache-2.0 # -add_subdirectory_ifdef(CONFIG_RV_8263_C8 rv8263c8) \ No newline at end of file +add_subdirectory_ifdef(CONFIG_RTC_RV8263 rv8263c8) \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/CMakeLists.txt b/app/drivers/rtc/rv8263c8/CMakeLists.txt index 900aa7a5..6c34f57d 100644 --- a/app/drivers/rtc/rv8263c8/CMakeLists.txt +++ b/app/drivers/rtc/rv8263c8/CMakeLists.txt @@ -1,7 +1,5 @@ -# Copyright (c) 2024, Daniel Kampert -# # SPDX-License-Identifier: Apache-2.0 -# +# Copyright (c) 2024 Daniel Kampert +# Author: Daniel Kampert -zephyr_sources(microcrystal_rv8263c8.c) -zephyr_sources(interrupt/microcrystal_rv8263c8_interrupt.c) \ No newline at end of file +zephyr_sources(microcrystal_rv8263c8.c) \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/Kconfig b/app/drivers/rtc/rv8263c8/Kconfig index 6befd40b..c93738bf 100644 --- a/app/drivers/rtc/rv8263c8/Kconfig +++ b/app/drivers/rtc/rv8263c8/Kconfig @@ -1,58 +1,83 @@ -# RV-8263-C8 RTC configuration options. - -# Copyright (c) 240, Daniel Kampert -# # SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Daniel Kampert +# Author: Daniel Kampert -menuconfig RV_8263_C8 - bool "RV-8263-C8 RTC" - depends on DT_HAS_MICROCRYSTAL_RV_8263_C8_ENABLED - default y - select I2C - help - Enable the driver for the RV-8263-C8 RTC. - -if RV_8263_C8 +config RTC_RV8263 + bool "Micro Crystal RV-8263-C8 RTC driver" + default y + depends on DT_HAS_MICROCRYSTAL_RV_8263_C8_ENABLED + select I2C + help + Micro Crystal RV-8263-C8 RTC driver. -module = MICROCRYSTAL_RV_8263_C8 -module-str = MICROCRYSTAL_RV_8263_C8 -source "subsys/logging/Kconfig.template.log_config" +if RTC_RV8263 + menu "RV8263 Update" + depends on RTC_UPDATE - config RV_8263_C8_THREAD_STACK_SIZE - int "RTC delayed work thread stack size" - depends on RV_8263_C8_INTERRUPT_OWN_THREAD - default 1024 + choice + prompt "RV-8263-C8 update handling mode" + default RTC_RV8263_UPDATE_GLOBAL_THREAD - config RV_8263_C8_THREAD_PRIORITY - int "RV-8263-C8 thread priority" - depends on RV_8263_C8_INTERRUPT_OWN_THREAD - default 10 + config RTC_RV8263_UPDATE_GLOBAL_THREAD + depends on GPIO + bool "Use workqueue" + help + Use the global workqueue to process the updates from the RV-8263-C8. - choice - prompt "RV-8263-C8 interrupt mode" - default RV_8263_C8_INTERRUPT_NONE + config RTC_RV8263_UPDATE_OWN_THREAD + depends on GPIO + bool "Use driver thread" + help + Use a separate thread to process the updates from the RV-8263-C8. + endchoice - config RV_8263_C8_INTERRUPT_NONE - bool "No interrupt" + config RTC_RV8263_UPDATE_THREAD_STACK_SIZE + int "Stack size for the RV-8263-C8 update thread" + depends on RTC_RV8263_UPDATE_OWN_THREAD + default 512 help - Disable the INTERRUPT interface. + Size of the stack used for the thread handling RTC updates and dispatching callbacks. - config RV_8263_C8_INTERRUPT_GLOBAL_THREAD - depends on GPIO - select RV_8263_C8_INTERRUPT - bool "Use workqueue" + config RTC_RV8263_UPDATE_THREAD_PRIORITY + int "RV-8263-C8 update thread priority" + depends on RTC_RV8263_UPDATE_OWN_THREAD + default 0 help - Use the global workqueue to process the interrupts from the RV-8263-C8. + Priority level for the thread handling RTC updates and dispatching callbacks. + endmenu - config RV_8263_C8_INTERRUPT_OWN_THREAD - depends on GPIO - select RV_8263_C8_INTERRUPT - bool "Use driver thread" - help - Use a separate thread to process the interrupts from the RV-8263-C8. - endchoice + menu "RV8263 Alarm" + depends on RTC_ALARM + + choice + prompt "RV-8263-C8 alarm handling mode" + default RTC_RV8263_ALARM_GLOBAL_THREAD - config RV_8263_C8_INTERRUPT - bool + config RTC_RV8263_ALARM_GLOBAL_THREAD + depends on GPIO + bool "Use workqueue" + help + Use the global workqueue to process the interrupts from the RV-8263-C8. + config RTC_RV8263_ALARM_OWN_THREAD + depends on GPIO + bool "Use driver thread" + help + Use a separate thread to process the alarms from the RV-8263-C8. + endchoice + + config RTC_RV8263_ALARM_THREAD_STACK_SIZE + int "Stack size for the RV-8263-C8 interrupt thread" + depends on RTC_RV8263_ALARM_OWN_THREAD + default 512 + help + Size of the stack used for the thread handling alarms and dispatching callbacks. + + config RTC_RV8263_ALARM_THREAD_PRIORITY + int "RV-8263-C8 alarm thread priority" + depends on RTC_RV8263_ALARM_OWN_THREAD + default 0 + help + Priority level for the thread handling alarms and dispatching callbacks. + endmenu endif \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.c b/app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.c deleted file mode 100644 index 4e4c20f2..00000000 --- a/app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.c +++ /dev/null @@ -1,70 +0,0 @@ -/* microcrystal_rv8263c8_interrupt.c - Driver for Micro Crystal RV-8263-C8 RTC. */ - -/* - * Copyright (c) 2024, Daniel Kampert - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include "../microcrystal_rv8263c8.h" -#include "../private/microcrystal_rv8263c8_types.h" - -LOG_MODULE_REGISTER(microcrystal_rv8263c8_interrupt, CONFIG_MICROCRYSTAL_RV_8263_C8_LOG_LEVEL); - -#ifdef CONFIG_RV_8263_C8_TRIGGER_OWN_THREAD -static K_KERNEL_STACK_DEFINE(rv8263c8_thread_stack, CONFIG_RV_8263_C8_THREAD_STACK_SIZE); -static struct k_thread rv8263c8_thread; -#endif - -/** @brief - * @param p_dev - * @param p_cb - * @param pins -*/ -static void rv8263c8_gpio_on_interrupt_callback(const struct device *p_dev, struct gpio_callback *p_cb, uint32_t pins) -{ - ARG_UNUSED(pins); - ARG_UNUSED(p_dev); -} - -int rv8263c8_init_interrupt(const struct device *p_dev) -{ - struct rv8263c8_data *data = p_dev->data; - const struct rv8263c8_config *config = p_dev->config; - - LOG_DBG("Initialize interrupts..."); - - if (!gpio_is_ready_dt(&config->int_gpio)) { - LOG_ERR("INT GPIO device not ready!"); - return -ENODEV; - } - - if (gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT)) { - return -EFAULT; - } - /* - data->dev = p_dev; - - #ifdef CONFIG_RV_8263_C8_TRIGGER_OWN_THREAD - k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT); - - k_thread_create(&bmi2_thread, bmi2_thread_stack, CONFIG_RV_8263_C8_THREAD_STACK_SIZE, - bmi2_worker_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_RV_8263_C8_THREAD_PRIORITY), - 0, K_NO_WAIT); - #else - data->work.handler = bmi2_worker; - #endif - - gpio_init_callback(&data->gpio_handler, rv8263c8_gpio_on_interrupt_callback, BIT(config->int_gpio.pin)); - - if (gpio_add_callback(config->int_gpio.port, &data->gpio_handler)) { - return -EFAULT; - } - - LOG_DBG("Interrupts ready!"); - */ - return 0; -} \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.h b/app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.h deleted file mode 100644 index 37287b7a..00000000 --- a/app/drivers/rtc/rv8263c8/interrupt/microcrystal_rv8263c8_interrupt.h +++ /dev/null @@ -1,15 +0,0 @@ -/* microcrystal_rv8263c8_interrupt.c - Driver for Micro Crystal RV-8263-C8 RTC. */ - -/* - * Copyright (c) 2024, Daniel Kampert - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -/** @brief - * @param p_dev - * @return 0 when successful -*/ -int rv8263c8_init_interrupt(const struct device *p_dev); \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.c b/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.c index 78acd90a..b776723f 100644 --- a/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.c +++ b/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.c @@ -1,17 +1,21 @@ -/* microcrystal_rv8263c8.c - Driver for Micro Crystal RV-8263-C8 RTC. */ - -/* - * Copyright (c) 2024, Daniel Kampert +/* microcrystal_rv8263c8.c - Driver for Micro Crystal RV-8263-C8 RTC. * - * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Daniel Kampert + * Author: Daniel Kampert */ -#include "microcrystal_rv8263c8.h" -#include "private/microcrystal_rv8263c8_types.h" -#include "interrupt/microcrystal_rv8263c8_interrupt.h" - -#define RV8263C8_REGISTER_CONTROL1 0x00 -#define RV8263C8_REGISTER_CONTROL2 0x01 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RV8263C8_REGISTER_CONTROL_1 0x00 +#define RV8263C8_REGISTER_CONTROL_2 0x01 #define RV8263C8_REGISTER_OFFSET 0x02 #define RV8263C8_REGISTER_RAM 0x03 #define RV8263C8_REGISTER_SECONDS 0x04 @@ -29,19 +33,22 @@ #define RV8263C8_REGISTER_TIMER_VALUE 0x10 #define RV8263C8_REGISTER_TIMER_MODE 0x11 -#define RV8263C8_24H_MODE_ENABLE (0x00 << 0x01) -#define RV8263C8_24H_MODE_DISABLE (0x00 << 0x01) -#define RV8263C8_CLOCK_ENABLE (0x00 << 0x05) -#define RV8263C8_CLOCK_DISABLE (0x01 << 0x05) -#define RV8263C8_ALARM_INT_ENABLE (0x01 << 0x07) -#define RV8263C8_ALARM_INT_DISABLE (0x00 << 0x05) -#define RV8263C8_MINUTE_INT_ENABLE (0x01 << 0x05) -#define RV8263C8_MINUTE_INT_DISABLE (0x00 << 0x05) -#define RV8263C8_HALF_MINUTE_INT_ENABLE (0x01 << 0x04) -#define RV8263C8_HALF_MINUTE_INT_DISABLE (0x00 << 0x04) -#define RV8263C8_ALARM_ENABLE (0x00 << 0x07) -#define RV8263C8_ALARM_DISABLE (0x01 << 0x07) -#define RV8263C8_SOFTWARE_RESET (0x58) +#define RV8263C8_BM_24H_MODE_ENABLE (0x00 << 1) +#define RV8263C8_BM_24H_MODE_DISABLE (0x00 << 1) +#define RV8263C8_BM_CLOCK_ENABLE (0x00 << 5) +#define RV8263C8_BM_CLOCK_DISABLE (0x01 << 5) +#define RV8263C8_BM_ALARM_INT_ENABLE (0x01 << 7) +#define RV8263C8_BM_ALARM_INT_DISABLE (0x00 << 7) +#define RV8263C8_BM_MINUTE_INT_ENABLE (0x01 << 5) +#define RV8263C8_BM_MINUTE_INT_DISABLE (0x00 << 5) +#define RV8263C8_BM_HALF_MINUTE_INT_ENABLE (0x01 << 4) +#define RV8263C8_BM_HALF_MINUTE_INT_DISABLE (0x00 << 4) +#define RV8263C8_BM_ALARM_ENABLE (0x00 << 7) +#define RV8263C8_BM_ALARM_DISABLE (0x01 << 7) +#define RV8263C8_BM_AF (0x01 << 6) +#define RV8263C8_BM_TF (0x01 << 3) +#define RV8263_BM_MODE (0x01 << 7) +#define RV8263C8_BM_SOFTWARE_RESET (0x58) #define SECONDS_BITS GENMASK(6, 0) #define MINUTES_BITS GENMASK(7, 0) @@ -69,55 +76,355 @@ #define DT_DRV_COMPAT microcrystal_rv_8263_c8 -LOG_MODULE_REGISTER(microcrystal_rv8263c8, CONFIG_MICROCRYSTAL_RV_8263_C8_LOG_LEVEL); +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) +#define RV8263_USE_INT 1 +/** + * @brief RV-8263-C8 "int_gpios" property must be in the devicetree in order to use the RTC_ALARM or RTC_UPDATE feature. + */ +#if !DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) +#error int-gpios property not available in devicetree! +#endif +#endif + +#ifdef CONFIG_RTC_CALIBRATION +/** + * @brief RV-8263-C8 "offset" property must be in the devicetree in order to use the RTC_CALIBRATION feature. + */ +#if !DT_ANY_INST_HAS_PROP_STATUS_OKAY(offset) +#error offset-property not available in devicetree! +#endif +#endif + +#ifdef CONFIG_RTC_CALIBRATION +/** + * @brief RV-8263-C8 "fast_mode" property must be in the devicetree in order to use the RTC_CALIBRATION feature. + */ +#if !DT_ANY_INST_HAS_PROP_STATUS_OKAY(fast_mode) +#error fast-mode-property not available in devicetree! +#endif +#endif + +LOG_MODULE_REGISTER(microcrystal_rv8263c8, CONFIG_RTC_LOG_LEVEL); + +struct rv8263c8_config { + struct i2c_dt_spec i2c_bus; + uint8_t clkout; + bool fast_mode; + int8_t offset; + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) + struct gpio_dt_spec int_gpio; +#endif +}; + +struct rv8263c8_data { + struct k_spinlock lock; + +#if defined(CONFIG_RTC_RV8263_ALARM_GLOBAL_THREAD) || defined(CONFIG_RTC_RV8263_UPDATE_GLOBAL_THREAD) + const struct device *dev; +#endif + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) + struct gpio_callback gpio_cb; +#endif + +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_cb; + void *alarm_cb_data; + bool is_alarm_pending; + +#if defined(CONFIG_RTC_RV8263_ALARM_OWN_THREAD) + struct k_sem alarm_sem; +#elif defined(CONFIG_RTC_RV8263_ALARM_GLOBAL_THREAD) + struct k_work alarm_work; +#endif +#endif -static void rv8263c8_isr(const struct device *p_dev) +#ifdef CONFIG_RTC_UPDATE + rtc_update_callback update_cb; + void *update_cb_data; + +#if defined(CONFIG_RTC_RV8263_UPDATE_OWN_THREAD) + struct k_sem update_sem; +#elif defined(CONFIG_RTC_RV8263_UPDATE_GLOBAL_THREAD) + struct k_work update_work; +#endif +#endif +}; + +#ifdef CONFIG_RTC_RV8263_ALARM_OWN_THREAD +static K_KERNEL_STACK_MEMBER(rv8263c8_alarm_stack, CONFIG_RTC_RV8263_ALARM_THREAD_STACK_SIZE); +static struct k_thread rv8263c8_alarm_thread; +#endif + +#ifdef CONFIG_RTC_RV8263_UPDATE_OWN_THREAD +static K_KERNEL_STACK_MEMBER(rv8263c8_update_stack, CONFIG_RTC_RV8263_UPDATE_THREAD_STACK_SIZE); +static struct k_thread rv8263c8_update_thread; +#endif + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) +/** + * @brief + * + * @param p_port + * @param p_cb + * @param pins + */ +static void rv8263c8_gpio_callback_handler(const struct device *p_port, struct gpio_callback *p_cb, + gpio_port_pins_t pins) { - struct rv8263c8_data *const dev_data = p_dev->data; + ARG_UNUSED(pins); + ARG_UNUSED(p_port); + + struct rv8263c8_data *data = CONTAINER_OF(p_cb, struct rv8263c8_data, gpio_cb); + +#if defined(CONFIG_RTC_RV8263_ALARM_OWN_THREAD) + k_sem_give(&data->alarm_sem); +#elif defined(CONFIG_RTC_RV8263_ALARM_GLOBAL_THREAD) + k_work_submit(&data->alarm_work); +#endif + +#if defined(CONFIG_RTC_RV8263_UPDATE_OWN_THREAD) + k_sem_give(&data->update_sem); +#elif defined(CONFIG_RTC_RV8263_UPDATE_GLOBAL_THREAD) + k_work_submit(&data->update_work); +#endif +} +#endif + +#ifdef CONFIG_RTC_ALARM +/** + * @brief + * + * @param p_dev + */ +static void rv8263_process_alarm(const struct device *p_dev) +{ + struct rv8263c8_data *data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; + + data->is_alarm_pending = true; + + if (data->alarm_cb != NULL) { + LOG_DBG("Calling alarm callback"); + data->alarm_cb(p_dev, 0, data->alarm_cb_data); + } + + i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, RV8263C8_BM_AF, RV8263C8_BM_AF); } -static int rv8263c8_set_time(const struct device *p_dev, const struct rtc_time *p_tm) +#ifdef CONFIG_RTC_RV8263_ALARM_OWN_THREAD +/** + * @brief + * + * @param p_arg1 + * @param p_arg2 + * @param p_arg3 + */ +static void rv8263c8_alarm_thread_func(void *p_arg1, void *p_arg2, void *p_arg3) { - int err; - uint8_t regs[7]; + const struct device *dev = p_arg1; + struct rv8263c8_data *data = dev->data; + while (1) { + k_sem_take(&data->alarm_sem, K_FOREVER); + rv8263_process_alarm(dev); + } +} +#else +/** + * @brief + * + * @param p_work + */ +static void rv8263c8_alarm_worker(struct k_work *p_work) +{ + struct rv8263c8_data *data = CONTAINER_OF(p_work, struct rv8263c8_data, alarm_work); + + LOG_DBG("Process alarm interrupt from worker"); + + rv8263_process_alarm(data->dev); +} +#endif + +/** + * @brief + * + * @param p_timeptr + * @param mask + * @return true + * @return false + */ +static bool rv8263c8_validate_alarm(const struct rtc_time *p_timeptr, uint32_t mask) +{ + if ((mask & RTC_ALARM_TIME_MASK_SECOND) && + (p_timeptr->tm_sec < MIN_SEC || p_timeptr->tm_sec > MAX_SEC)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MINUTE) && + (p_timeptr->tm_min < MIN_MIN || p_timeptr->tm_min > MAX_MIN)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_HOUR) && + (p_timeptr->tm_hour < MIN_HOUR || p_timeptr->tm_hour > MAX_HOUR)) { + return false; + } + + return true; +} +#endif + +#ifdef CONFIG_RTC_UPDATE +/** + * @brief This function configures and enables the countdown timer. + * + * @param p_dev Pointer to device strucure + * @return int 0 when successful + */ +static int rv8263c8_update_enable_timer(const struct device *p_dev) +{ + int err; + uint8_t regs; struct rv8263c8_data *data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; + if (p_dev == NULL) { + return -EINVAL; + } + + regs = 0; k_spinlock_key_t key = k_spin_lock(&data->lock); + err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_VALUE, ®s, sizeof(regs)); + if (err < 0) { + goto rv8263c8_update_enable_timer_exit; + } + + // Configure the countdown timer for 1 Hz and enable pulse interrupts. + regs = (0x02 << 3) | (0x01 << 2) | (0x01 << 1) | (0x01 << 0); + err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_MODE, ®s, sizeof(regs)); + +rv8263c8_update_enable_timer_exit: + k_spin_unlock(&data->lock, key); + + return err; +} + +/** + * @brief + * + * @param p_dev + */ +static void rv8263_process_update(const struct device *p_dev) +{ + struct rv8263c8_data *data = p_dev->data; + const struct rv8263c8_config *config = p_dev->config; + + if (data->update_cb != NULL) { + LOG_DBG("Calling update callback"); + data->update_cb(p_dev, data->update_cb_data); + } + + rv8263c8_update_enable_timer(p_dev); + i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, RV8263C8_BM_TF, RV8263C8_BM_TF); +} + +#ifdef CONFIG_RTC_RV8263_UPDATE_OWN_THREAD +/** + * @brief + * + * @param p_arg1 + * @param p_arg2 + * @param p_arg3 + */ +static void rv8263c8_update_thread_func(void *p_arg1, void *p_arg2, void *p_arg3) +{ + const struct device *dev = p_arg1; + struct rv8263c8_data *data = dev->data; + + while (1) { + k_sem_take(&data->update_sem, K_FOREVER); + rv8263_process_update(dev); + } +} +#else +/** + * @brief + * + * @param p_work + */ +static void rv8263c8_update_worker(struct k_work *p_work) +{ + struct rv8263c8_data *data = CONTAINER_OF(p_work, struct rv8263c8_data, alarm_work); + + LOG_DBG("Process update interrupt from worker"); + + rv8263_process_update(data->dev); +} +#endif +#endif + +/** + * @brief Set time function for RTC API. + * + * @param p_dev Pointer to device strucure + * @param p_timeptr + * @return int 0 when successful + */ +static int rv8263c8_time_set(const struct device *p_dev, const struct rtc_time *p_timeptr) +{ + int err; + uint8_t regs[7]; + struct rv8263c8_data *data = p_dev->data; + const struct rv8263c8_config *config = p_dev->config; + + if ((p_dev == NULL) || (p_timeptr == NULL)) { + return -EINVAL; + } LOG_DBG("Set time: year = %u, mon = %u, mday = %u, wday = %u, hour = %u, min = %u, sec = %u", - p_tm->tm_year, p_tm->tm_mon, p_tm->tm_mday, p_tm->tm_wday, p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec); + p_timeptr->tm_year, p_timeptr->tm_mon, p_timeptr->tm_mday, p_timeptr->tm_wday, p_timeptr->tm_hour, p_timeptr->tm_min, + p_timeptr->tm_sec); - regs[0] = bin2bcd(p_tm->tm_sec) & SECONDS_BITS; - regs[1] = bin2bcd(p_tm->tm_min); - regs[2] = bin2bcd(p_tm->tm_hour); - regs[3] = bin2bcd(p_tm->tm_wday); - regs[4] = bin2bcd(p_tm->tm_mday); - regs[5] = bin2bcd(p_tm->tm_mon); - regs[6] = bin2bcd((p_tm->tm_year % 100)); + regs[0] = bin2bcd(p_timeptr->tm_sec) & SECONDS_BITS; + regs[1] = bin2bcd(p_timeptr->tm_min); + regs[2] = bin2bcd(p_timeptr->tm_hour); + regs[3] = bin2bcd(p_timeptr->tm_wday); + regs[4] = bin2bcd(p_timeptr->tm_mday); + regs[5] = bin2bcd(p_timeptr->tm_mon); + regs[6] = bin2bcd((p_timeptr->tm_year % 100)); + k_spinlock_key_t key = k_spin_lock(&data->lock); err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, regs, sizeof(regs)); - k_spin_unlock(&data->lock, key); return err; } -static int rv8263c8_get_time(const struct device *p_dev, struct rtc_time *p_timeptr) +/** + * @brief Get time function for RTC API. + * + * @param p_dev Pointer to device strucure + * @param p_timeptr + * @return int 0 when successful + */ +static int rv8263c8_time_get(const struct device *p_dev, struct rtc_time *p_timeptr) { int err; uint8_t regs[7]; - struct rv8263c8_data *data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; - k_spinlock_key_t key = k_spin_lock(&data->lock); + if ((p_dev == NULL) || (p_timeptr == NULL)) { + return -EINVAL; + } + k_spinlock_key_t key = k_spin_lock(&data->lock); err = i2c_burst_read_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, regs, sizeof(regs)); - if (err != 0) { - goto rv8263c8_get_time_exit; + k_spin_unlock(&data->lock, key); + if (err < 0) { + return err; } p_timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS); @@ -136,28 +443,35 @@ static int rv8263c8_get_time(const struct device *p_dev, struct rtc_time *p_time // Validate the chip in 24hr mode if (regs[2] & VALIDATE_24HR) { - err = -ENODATA; - goto rv8263c8_get_time_exit; + return -ENODATA; } - LOG_DBG("get time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, min = %d, sec = %d", + LOG_DBG("get time: year = %u, mon = %u, mday = %u, wday = %u, hour = %u, min = %u, sec = %u", p_timeptr->tm_year, p_timeptr->tm_mon, p_timeptr->tm_mday, p_timeptr->tm_wday, p_timeptr->tm_hour, p_timeptr->tm_min, p_timeptr->tm_sec); -rv8263c8_get_time_exit: - k_spin_unlock(&data->lock, key); - - return err; + return 0; } +/** + * @brief Init function for RTC API. + * + * @param p_dev Pointer to device strucure + * @return int 0 when successful + */ static int rv8263c8_init(const struct device *p_dev) { int err; + int temp; struct rv8263c8_data *data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; + if (p_dev == NULL) { + return -EINVAL; + } + if (!i2c_is_ready_dt(&config->i2c_bus)) { - LOG_ERR("I2C bus not ready"); + LOG_ERR("I2C bus not ready!"); return -ENODEV; } @@ -169,108 +483,159 @@ static int rv8263c8_init(const struct device *p_dev) k_spinlock_key_t key = k_spin_lock(&data->lock); // Configure the first config register - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL1, - RV8263C8_24H_MODE_DISABLE | RV8263C8_CLOCK_ENABLE); + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_1, + RV8263C8_BM_24H_MODE_DISABLE | RV8263C8_BM_CLOCK_ENABLE); if (err < 0) { - LOG_ERR("Error while writing CONTROL1! Error: %i", err); + LOG_ERR("Error while writing CONTROL_1! Error: %i", err); goto rv8263c8_init_exit; } +#ifdef CONFIG_RTC_CALIBRATION + err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_OFFSET, RV8263_BM_MODE, config->fast_mode << 7); + if (err < 0) { + LOG_ERR("Error while setting OFFSET mode! Error: %i", err); + goto rv8263c8_init_exit; + } +#endif + // Configure the second config register - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL2, - RV8263C8_ALARM_INT_ENABLE | RV8263C8_MINUTE_INT_DISABLE | RV8263C8_HALF_MINUTE_INT_DISABLE | (config->clkout << 0x00)); + temp = RV8263C8_BM_MINUTE_INT_DISABLE | RV8263C8_BM_HALF_MINUTE_INT_DISABLE | (config->clkout << 0x00); + +#ifdef CONFIG_RTC_ALARM + temp |= RV8263C8_BM_ALARM_INT_ENABLE; +#endif + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, temp); if (err < 0) { - LOG_ERR("Error while writing CONTROL2! Error: %i", err); + LOG_ERR("Error while writing CONTROL_2! Error: %i", err); goto rv8263c8_init_exit; } - // Configure the offset register - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_OFFSET, - config->fast_mode << 0x07 | (config->offset & 0x7F)); +#ifdef CONFIG_RTC_UPDATE + uint8_t regs = 0; + err = i2c_burst_write_dt(&config->i2c_bus, RV8263C8_REGISTER_TIMER_MODE, ®s, sizeof(regs)); if (err < 0) { LOG_ERR("Error while writing CONTROL2! Error: %i", err); + goto rv8263c8_init_exit; } +#endif - if (config->int_gpio.port) { - if (rv8263c8_init_interrupt(p_dev)) { - LOG_ERR("Could not initialize interrupts!"); - return -EFAULT; - } +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("GPIO not ready!"); + goto rv8263c8_init_exit; } -rv8263c8_init_exit: - k_spin_unlock(&data->lock, key); - - return err; -} - -#ifdef CONFIG_RTC_ALARM -static bool rv8263c8_validate_alarm(const struct rtc_time *p_timeptr, uint32_t mask) -{ - if ((mask & RTC_ALARM_TIME_MASK_SECOND) && - (p_timeptr->tm_sec < MIN_SEC || p_timeptr->tm_sec > MAX_SEC)) { - return false; + err = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (err < 0) { + LOG_ERR("Failed to configure GPIO! Error: %u", err); + goto rv8263c8_init_exit; } - if ((mask & RTC_ALARM_TIME_MASK_MINUTE) && - (p_timeptr->tm_min < MIN_MIN || p_timeptr->tm_min > MAX_MIN)) { - return false; + err = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_INACTIVE); + if (err < 0) { + LOG_ERR("Failed to configure interrupt! Error: %u", err); + goto rv8263c8_init_exit; } - if ((mask & RTC_ALARM_TIME_MASK_HOUR) && - (p_timeptr->tm_hour < MIN_HOUR || p_timeptr->tm_hour > MAX_HOUR)) { - return false; + gpio_init_callback(&data->gpio_cb, rv8263c8_gpio_callback_handler, BIT(config->int_gpio.pin)); + + err = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb); + if (err < 0) { + LOG_ERR("Failed to add GPIO callback! Error: %u", err); + goto rv8263c8_init_exit; } +#endif - return true; +#ifdef CONFIG_RTC_ALARM +#if defined(CONFIG_RTC_RV8263_ALARM_OWN_THREAD) + k_sem_init(&data->alarm_sem, 0, K_SEM_MAX_LIMIT); + k_thread_create(&rv8263c8_alarm_thread, rv8263c8_alarm_stack, + K_THREAD_STACK_SIZEOF(rv8263c8_alarm_stack), + rv8263c8_alarm_thread_func, (struct device *)p_dev, NULL, + NULL, CONFIG_RTC_RV8263_ALARM_THREAD_PRIORITY, 0, K_NO_WAIT); +#elif defined(CONFIG_RTC_RV8263_ALARM_GLOBAL_THREAD) + data->alarm_work.handler = rv8263c8_alarm_worker; +#endif +#endif + +#ifdef CONFIG_RTC_UPDATE +#if defined(CONFIG_RTC_RV8263_UPDATE_OWN_THREAD) + k_sem_init(&data->update_sem, 0, K_SEM_MAX_LIMIT); + k_thread_create(&rv8263c8_update_thread, rv8263c8_update_stack, + K_THREAD_STACK_SIZEOF(rv8263c8_update_stack), + rv8263c8_update_thread_func, (struct device *)p_dev, NULL, + NULL, CONFIG_RTC_RV8263_UPDATE_THREAD_PRIORITY, 0, K_NO_WAIT); +#elif defined(CONFIG_RTC_RV8263_UPDATE_GLOBAL_THREAD) + data->update_work.handler = rv8263c8_update_worker; +#endif +#endif + +#if defined(CONFIG_RTC_RV8263_ALARM_GLOBAL_THREAD) || defined(CONFIG_RTC_RV8263_UPDATE_GLOBAL_THREAD) + data->dev = p_dev; +#endif + +rv8263c8_init_exit: + k_spin_unlock(&data->lock, key); + return err; } +#ifdef CONFIG_RTC_ALARM +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param id + * @param p_mask + * @return int 0 when successful + */ static int rv8263c8_alarm_get_supported_fields(const struct device *p_dev, uint16_t id, uint16_t *p_mask) { ARG_UNUSED(p_dev); - if (id != 0) { + if ((p_dev == NULL) || (id != 0)) { return -EINVAL; } - (*p_mask) = (RTC_ALARM_TIME_MASK_SECOND - | RTC_ALARM_TIME_MASK_MINUTE - | RTC_ALARM_TIME_MASK_HOUR); + (*p_mask) = (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | + RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_WEEKDAY); return 0; } +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param id + * @param mask + * @param p_timeptr + * @return int 0 when successful + */ static int rv8263c8_alarm_set_time(const struct device *p_dev, uint16_t id, uint16_t mask, const struct rtc_time *p_timeptr) { int err; - struct rv8263c8_data *const dev_data = p_dev->data; + struct rv8263c8_data *const data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - if (id != 0) { - err = -EINVAL; - goto rv8263c8_alarm_set_time_exit; + if ((p_dev == NULL) || (p_timeptr == NULL) || (id != 0) || ((mask > 0) && (p_timeptr == NULL))) { + return -EINVAL; } - if ((mask > 0) && (p_timeptr == NULL)) { - err = -EINVAL; - goto rv8263c8_alarm_set_time_exit; - } + k_spinlock_key_t key = k_spin_lock(&data->lock); // Check time valid - if (!rv8263c8_validate_alarm(p_timeptr, mask)) { - err = -EINVAL; + err = rv8263c8_validate_alarm(p_timeptr, mask); + if (err < 0) { goto rv8263c8_alarm_set_time_exit; } if (mask & RTC_ALARM_TIME_MASK_SECOND) { err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, - RV8263C8_ALARM_ENABLE | p_timeptr->tm_sec); + RV8263C8_BM_ALARM_ENABLE | p_timeptr->tm_sec); } else { - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, RV8263C8_ALARM_DISABLE); + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, RV8263C8_BM_ALARM_DISABLE); } if (err < 0) { @@ -279,10 +644,10 @@ static int rv8263c8_alarm_set_time(const struct device *p_dev, uint16_t id, uint } if (mask & RTC_ALARM_TIME_MASK_MINUTE) { - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, - RV8263C8_ALARM_ENABLE | p_timeptr->tm_min); + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_MINUTES_ALARM, + RV8263C8_BM_ALARM_ENABLE | p_timeptr->tm_min); } else { - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, RV8263C8_ALARM_DISABLE); + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_MINUTES_ALARM, RV8263C8_BM_ALARM_DISABLE); } if (err < 0) { @@ -291,10 +656,10 @@ static int rv8263c8_alarm_set_time(const struct device *p_dev, uint16_t id, uint } if (mask & RTC_ALARM_TIME_MASK_HOUR) { - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, - RV8263C8_ALARM_ENABLE | p_timeptr->tm_hour); + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_HOURS_ALARM, + RV8263C8_BM_ALARM_ENABLE | p_timeptr->tm_hour); } else { - err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, RV8263C8_ALARM_DISABLE); + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_HOURS_ALARM, RV8263C8_BM_ALARM_DISABLE); } if (err < 0) { @@ -302,47 +667,61 @@ static int rv8263c8_alarm_set_time(const struct device *p_dev, uint16_t id, uint goto rv8263c8_alarm_set_time_exit; } - err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL2, 0x01 << 0x07, RV8263C8_ALARM_INT_ENABLE); + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM, + RV8263C8_BM_ALARM_ENABLE | p_timeptr->tm_mday); + } else { + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM, RV8263C8_BM_ALARM_DISABLE); + } + if (err < 0) { - LOG_ERR("Error while writing CONTROL2! Error: %i", err); + LOG_ERR("Error while writing MONTHDAY alarm! Error: %i", err); goto rv8263c8_alarm_set_time_exit; } - err = 0; + if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) { + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM, + RV8263C8_BM_ALARM_ENABLE | p_timeptr->tm_wday); + } else { + err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM, RV8263C8_BM_ALARM_DISABLE); + } + + if (err < 0) { + LOG_ERR("Error while writing WEEKDAY alarm! Error: %i", err); + goto rv8263c8_alarm_set_time_exit; + } rv8263c8_alarm_set_time_exit: - k_spin_unlock(&dev_data->lock, key); + k_spin_unlock(&data->lock, key); return err; } +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param id + * @param p_mask + * @param p_timeptr + * @return int 0 when successful + */ static int rv8263c8_alarm_get_time(const struct device *p_dev, uint16_t id, uint16_t *p_mask, struct rtc_time *p_timeptr) { int err; - struct rv8263c8_data *const dev_data = p_dev->data; + struct rv8263c8_data *const data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; - - rtc_alarm_callback cb; - void *cb_data; - rtc_update_callback update_cb; - void *update_cb_data; uint8_t value; - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - if (id != 0) { - err = -EINVAL; - goto rv8263c8_alarm_get_time_exit; - } - - if (p_timeptr == NULL) { - err = -EINVAL; - goto rv8263c8_alarm_get_time_exit; + if ((p_dev == NULL) || (p_timeptr == NULL) || (id != 0)) { + return -EINVAL; } (*p_mask) = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, &value); if (err < 0) { LOG_ERR("Error while reading SECONDS! Error: %i", err); @@ -361,7 +740,7 @@ static int rv8263c8_alarm_get_time(const struct device *p_dev, uint16_t id, uint } if (value <= MAX_MIN) { - p_timeptr->tm_hour = value; + p_timeptr->tm_min = value; (*p_mask) |= RTC_ALARM_TIME_MASK_MINUTE; } @@ -376,37 +755,68 @@ static int rv8263c8_alarm_get_time(const struct device *p_dev, uint16_t id, uint (*p_mask) |= RTC_ALARM_TIME_MASK_HOUR; } - err = 0; + err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM, &value); + if (err < 0) { + LOG_ERR("Error while reading SECONDS! Error: %i", err); + goto rv8263c8_alarm_get_time_exit; + } + + if (value <= MAX_MDAY) { + p_timeptr->tm_mday = value; + (*p_mask) |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + + err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM, &value); + if (err < 0) { + LOG_ERR("Error while reading SECONDS! Error: %i", err); + goto rv8263c8_alarm_get_time_exit; + } + + if (value <= MAX_WDAY) { + p_timeptr->tm_hour = value; + (*p_mask) |= RTC_ALARM_TIME_MASK_WEEKDAY; + } rv8263c8_alarm_get_time_exit: - k_spin_unlock(&dev_data->lock, key); + k_spin_unlock(&data->lock, key); return err; } +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param id + * @param callback RTC Alarm callback + * @param p_user_data Pointer to user data for alarm callback + * @return int 0 when successful + */ static int rv8263c8_alarm_set_callback(const struct device *p_dev, uint16_t id, rtc_alarm_callback callback, void *p_user_data) { int err; - struct rv8263c8_data *const dev_data = p_dev->data; + struct rv8263c8_data *const data = p_dev->data; const struct rv8263c8_config *config = p_dev->config; - if (id != 0) { + if ((p_dev == NULL) || (id != 0)) { return -EINVAL; } - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + k_spinlock_key_t key = k_spin_lock(&data->lock); - dev_data->cb = callback; - dev_data->cb_data = p_user_data; + data->alarm_cb = callback; + data->alarm_cb_data = p_user_data; if (callback != NULL) { - err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL2, 0x01 << 0x07, RV8263C8_ALARM_INT_ENABLE); + err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, RV8263C8_BM_ALARM_INT_ENABLE, + RV8263C8_BM_ALARM_INT_ENABLE); } else { - err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL2, 0x01 << 0x07, RV8263C8_ALARM_INT_DISABLE); + err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, RV8263C8_BM_ALARM_INT_ENABLE, + RV8263C8_BM_ALARM_INT_DISABLE); } - k_spin_unlock(&dev_data->lock, key); + k_spin_unlock(&data->lock, key); if (err < 0) { LOG_ERR("Error while writing CONTROL2! Error: %i", err); @@ -416,54 +826,121 @@ static int rv8263c8_alarm_set_callback(const struct device *p_dev, uint16_t id, return 0; } +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param id + * @return int 0 when successful + */ static int rv8263c8_alarm_is_pending(const struct device *p_dev, uint16_t id) { int ret; - struct rv8263c8_data *const dev_data = p_dev->data; + struct rv8263c8_data *const data = p_dev->data; - if (id != 0) { + if ((p_dev == NULL) || (id != 0)) { return -EINVAL; } - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - ret = dev_data->alarm_pending ? 1 : 0; - dev_data->alarm_pending = false; - - k_spin_unlock(&dev_data->lock, key); + k_spinlock_key_t key = k_spin_lock(&data->lock); + ret = data->is_alarm_pending ? 1 : 0; + data->is_alarm_pending = false; + k_spin_unlock(&data->lock, key); return ret; } #endif #ifdef CONFIG_RTC_UPDATE -static int rv8263c8_update_set_callback(const struct device *p_dev, - rtc_update_callback callback, void *p_user_data) +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param callback RTC update callback + * @param p_user_data Pointer to user data for update callback + * @return int 0 when successful + */ +int rv8263_update_callback(const struct device *p_dev, rtc_update_callback callback, void *p_user_data) { - struct rv8263c8_data *const dev_data = p_dev->data; + struct rv8263c8_data *const data = p_dev->data; -#error Not supported + if (p_dev == NULL) { + return -EINVAL; + } - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + k_spinlock_key_t key = k_spin_lock(&data->lock); + data->update_cb = callback; + data->update_cb_data = p_user_data; + k_spin_unlock(&data->lock, key); - dev_data->update_cb = callback; - dev_data->update_cb_data = p_user_data; + return rv8263c8_update_enable_timer(p_dev); +} +#endif - if (callback != NULL) { - // TODO: Enable - } else { - // TODO: Disable +#ifdef CONFIG_RTC_CALIBRATION +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param calibration + * @return int 0 when successful + */ +int rv8263c8_calibration_set(const struct device *p_dev, int32_t calibration) +{ + int err; + int8_t reg; + struct rv8263c8_data *const data = p_dev->data; + const struct rv8263c8_config *config = p_dev->config; + + if (p_dev == NULL) { + return -EINVAL; } - k_spin_unlock(&dev_data->lock, key); + reg = calibration & 0x7F; + reg = bin2bcd(reg); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_OFFSET, 0x7F, reg); + k_spin_unlock(&data->lock, key); + + return err; +} + +/** + * @brief + * + * @param p_dev Pointer to device strucure + * @param p_calibration + * @return int 0 when successful + */ +int rv8263c8_calibration_get(const struct device *p_dev, int32_t *p_calibration) +{ + int err; + uint8_t value; + struct rv8263c8_data *const data = p_dev->data; + const struct rv8263c8_config *config = p_dev->config; + + if ((p_dev == NULL) || (p_calibration == NULL)) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_OFFSET, &value); + k_spin_unlock(&data->lock, key); + if (err < 0) { + LOG_ERR("Error while reading OFFSET! Error: %i", err); + return err; + } + + *p_calibration = bcd2bin(value & 0x7F); return 0; } #endif static const struct rtc_driver_api rv8263c8_driver_api = { - .set_time = rv8263c8_set_time, - .get_time = rv8263c8_get_time, + .set_time = rv8263c8_time_set, + .get_time = rv8263c8_time_get, #ifdef CONFIG_RTC_ALARM .alarm_get_supported_fields = rv8263c8_alarm_get_supported_fields, .alarm_set_time = rv8263c8_alarm_set_time, @@ -471,24 +948,27 @@ static const struct rtc_driver_api rv8263c8_driver_api = { .alarm_is_pending = rv8263c8_alarm_is_pending, .alarm_set_callback = rv8263c8_alarm_set_callback, #endif - #ifdef CONFIG_RTC_UPDATE - .update_set_callback = rv8263c8_update_set_callback, + .update_set_callback = rv8263_update_callback, +#endif +#ifdef CONFIG_RTC_CALIBRATION + .set_calibration = rv8263c8_calibration_set, + .get_calibration = rv8263c8_calibration_get, #endif }; -#define RV_8263_C8_DEFINE(inst) \ +#define RV8263_DEFINE(inst) \ static struct rv8263c8_data rv8263c8_data_##inst; \ static const struct rv8263c8_config rv8263c8_config_##inst = { \ .i2c_bus = I2C_DT_SPEC_INST_GET(inst), \ .clkout = DT_INST_PROP(inst, clkout), \ .fast_mode = DT_INST_PROP(inst, fast_mode), \ .offset = DT_INST_PROP(inst, offset), \ - IF_ENABLED(CONFIG_BMI270_PLUS_TRIGGER, \ + IF_ENABLED(RV8263_USE_INT, \ (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),)) \ }; \ DEVICE_DT_INST_DEFINE(inst, &rv8263c8_init, NULL, &rv8263c8_data_##inst, \ &rv8263c8_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ &rv8263c8_driver_api); -DT_INST_FOREACH_STATUS_OKAY(RV_8263_C8_DEFINE) \ No newline at end of file +DT_INST_FOREACH_STATUS_OKAY(RV8263_DEFINE) \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.h b/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.h deleted file mode 100644 index 23fc1068..00000000 --- a/app/drivers/rtc/rv8263c8/microcrystal_rv8263c8.h +++ /dev/null @@ -1,22 +0,0 @@ -/* microcrystal_rv8263c8.h - Driver for Micro Crystal RV-8263-C8 RTC. */ - -/* - * Copyright (c 2024, Daniel Kampert - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -/** @brief -*/ -typedef enum { - RV8263C8_OUT_32KHZ = 0, - RV8263C8_OUT_16KHZ, - RV8263C8_OUT_8KHZ, - RV8263C8_OUT_4KHZ, - RV8263C8_OUT_2KHZ, - RV8263C8_OUT_1KHZ, - RV8263C8_OUT_1HZ, - RV8263C8_OUT_LOW, -} rv_8263_c8_clkout_t; \ No newline at end of file diff --git a/app/drivers/rtc/rv8263c8/private/microcrystal_rv8263c8_types.h b/app/drivers/rtc/rv8263c8/private/microcrystal_rv8263c8_types.h deleted file mode 100644 index 660c5919..00000000 --- a/app/drivers/rtc/rv8263c8/private/microcrystal_rv8263c8_types.h +++ /dev/null @@ -1,36 +0,0 @@ -/* microcrystal_rv8263c8_types.h - Driver for Micro Crystal RV-8263-C8 RTC. */ - -/* - * Copyright (c 2024, Daniel Kampert - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct rv8263c8_config { - struct i2c_dt_spec i2c_bus; - rv_8263_c8_clkout_t clkout; - bool fast_mode; - int8_t offset; - struct gpio_dt_spec int_gpio; -}; - -struct rv8263c8_data { - struct k_spinlock lock; - bool alarm_pending; - rtc_alarm_callback cb; - void *cb_data; - rtc_update_callback update_cb; - void *update_cb_data; -}; \ No newline at end of file diff --git a/app/drivers/sensor/apds9306/Kconfig b/app/drivers/sensor/apds9306/Kconfig index 60af26e3..ea704e35 100644 --- a/app/drivers/sensor/apds9306/Kconfig +++ b/app/drivers/sensor/apds9306/Kconfig @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig APDS9306 - bool "APDS9306 Sensor" + bool "Avago APDS9306 Sensor" default y depends on DT_HAS_AVAGO_APDS9306_ENABLED select I2C diff --git a/app/drivers/sensor/bmi270/Kconfig b/app/drivers/sensor/bmi270/Kconfig index 7c3fa5e4..4c7f01a4 100644 --- a/app/drivers/sensor/bmi270/Kconfig +++ b/app/drivers/sensor/bmi270/Kconfig @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig BMI270_PLUS - bool "BMI270 Plus Sensor" + bool "Bosch BMI270 Plus Sensor" depends on DT_HAS_BOSCH_BMI270_PLUS_ENABLED default y select I2C diff --git a/app/drivers/sensor/bmi270/private/bosch_bmi270_types.h b/app/drivers/sensor/bmi270/private/bosch_bmi270_types.h index 22759684..a47ca631 100644 --- a/app/drivers/sensor/bmi270/private/bosch_bmi270_types.h +++ b/app/drivers/sensor/bmi270/private/bosch_bmi270_types.h @@ -19,7 +19,7 @@ /** @brief */ struct bmi270_config { - struct i2c_dt_spec i2c; + struct i2c_dt_spec i2c; #ifdef CONFIG_BMI270_PLUS_TRIGGER struct gpio_dt_spec int_gpio; #endif @@ -48,25 +48,23 @@ struct bmi270_data { sensor_trigger_handler_t motion; #endif -#ifdef CONFIG_BMI270_PLUS_TRIGGER_OWN_THREAD +#if defined(CONFIG_BMI270_PLUS_TRIGGER_OWN_THREAD) struct k_sem sem; -#endif - -#ifdef CONFIG_BMI270_PLUS_TRIGGER_GLOBAL_THREAD +#elif defined(CONFIG_BMI270_PLUS_TRIGGER_GLOBAL_THREAD) struct k_work work; #endif int16_t ax; - int16_t ay; - int16_t az; - int16_t gx; - int16_t gy; - int16_t gz; - uint16_t temp; + int16_t ay; + int16_t az; + int16_t gx; + int16_t gy; + int16_t gz; + uint16_t temp; uint8_t acc_range; - uint8_t acc_odr; + uint8_t acc_odr; uint16_t gyr_range; - uint8_t gyr_odr; - uint8_t gyr_osr; + uint8_t gyr_odr; + uint8_t gyr_osr; struct bmi2_dev bmi2; -}; \ No newline at end of file +}; diff --git a/app/drivers/sensor/bmp581/Kconfig b/app/drivers/sensor/bmp581/Kconfig index 6c8eef94..2ba582c5 100644 --- a/app/drivers/sensor/bmp581/Kconfig +++ b/app/drivers/sensor/bmp581/Kconfig @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig BMP581 - bool "BMP581 Sensor" + bool "Bosch BMP581 Sensor" depends on DT_HAS_BOSCH_BMP581_ENABLED default y select I2C diff --git a/app/dts/bindings/rtc/microcrystal,rv-8263-c8.yml b/app/dts/bindings/rtc/microcrystal,rv-8263-c8.yml index 9383be82..1c998e3e 100644 --- a/app/dts/bindings/rtc/microcrystal,rv-8263-c8.yml +++ b/app/dts/bindings/rtc/microcrystal,rv-8263-c8.yml @@ -13,26 +13,28 @@ properties: fast_mode: type: boolean + required: false description: | Enable fast offset mode (Offset every 4 minutes). offset: type: int + required: false default: 0 description: Offset for timer compensation. clkout: type: int - default: 7 + required: false + default: 0 enum: - - 0 + - 32768 + - 8192 + - 1024 + - 64 + - 32 - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 + - 0 description: - CLKOUT frequency selection. Set to 7 to disable it. \ No newline at end of file + CLKOUT frequency selection. Set to 0 to disable the CLKOUT signal (CLKOUT pin is LOW). \ No newline at end of file