diff --git a/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi b/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi index 95a27d3a00..9c7f1da181 100644 --- a/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi +++ b/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi @@ -24,6 +24,7 @@ }; aliases { + rtc = &rtc; watchdog0 = &wdt0; }; @@ -133,6 +134,11 @@ status = "okay"; }; +&rtc { + clocks = <&clocks RPI_PICO_CLKID_CLK_RTC>; + status = "okay"; +}; + &adc { status = "okay"; pinctrl-0 = <&adc_default>; diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 8bab34ebd3..26ea1a5656 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -19,3 +19,4 @@ zephyr_library_sources_ifdef(CONFIG_RTC_SHELL rtc_shell.c) zephyr_library_sources_ifdef(CONFIG_RTC_FAKE rtc_fake.c) zephyr_library_sources_ifdef(CONFIG_RTC_SMARTBOND rtc_smartbond.c) zephyr_library_sources_ifdef(CONFIG_RTC_ATMEL_SAM rtc_sam.c) +zephyr_library_sources_ifdef(CONFIG_RTC_RPI_PICO rtc_rpi_pico.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 10b228ceea..3b44235b75 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -45,11 +45,12 @@ source "drivers/rtc/Kconfig.am1805" source "drivers/rtc/Kconfig.ds1307" source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.fake" +source "drivers/rtc/Kconfig.mc146818" source "drivers/rtc/Kconfig.pcf8523" source "drivers/rtc/Kconfig.pcf8563" -source "drivers/rtc/Kconfig.mc146818" +source "drivers/rtc/Kconfig.rpi_pico" source "drivers/rtc/Kconfig.sam" -source "drivers/rtc/Kconfig.stm32" source "drivers/rtc/Kconfig.smartbond" +source "drivers/rtc/Kconfig.stm32" endif # RTC diff --git a/drivers/rtc/Kconfig.rpi_pico b/drivers/rtc/Kconfig.rpi_pico new file mode 100644 index 0000000000..24a872258f --- /dev/null +++ b/drivers/rtc/Kconfig.rpi_pico @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Andrew Featherstone +# SPDX-License-Identifier: Apache-2.0 + +config RTC_RPI_PICO + bool "Raspberry Pi Pico RTC driver" + default y + depends on DT_HAS_RASPBERRYPI_PICO_RTC_ENABLED + select PICOSDK_USE_RTC + depends on RESET diff --git a/drivers/rtc/rtc_rpi_pico.c b/drivers/rtc/rtc_rpi_pico.c new file mode 100644 index 0000000000..f628d2e970 --- /dev/null +++ b/drivers/rtc/rtc_rpi_pico.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 Andrew Featherstone + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define DT_DRV_COMPAT raspberrypi_pico_rtc + +#define CLK_DRV DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)) +#define CLK_ID (clock_control_subsys_t) DT_INST_PHA_BY_IDX(0, clocks, 0, clk_id) + +/* struct tm start time: 1st, Jan, 1900 */ +#define TM_YEAR_REF 1900 +/* See section 4.8.1 of the RP2040 datasheet. */ +#define RP2040_RTC_YEAR_MAX 4095 +struct rtc_rpi_pico_data { + struct k_spinlock lock; +}; + +LOG_MODULE_REGISTER(rtc_rpi, CONFIG_RTC_LOG_LEVEL); + +static int rtc_rpi_pico_init(const struct device *dev) +{ + int ret; + + ret = clock_control_on(CLK_DRV, CLK_ID); + if (ret < 0) { + return ret; + } + + rtc_init(); + return 0; +} + +static int rtc_rpi_pico_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + struct rtc_rpi_pico_data *data = dev->data; + int err = 0; + + if (timeptr->tm_year + TM_YEAR_REF > RP2040_RTC_YEAR_MAX) { + return -EINVAL; + } + + if (timeptr->tm_wday == -1) { + /* day of the week is expected */ + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + datetime_t dt = { + .year = timeptr->tm_year + TM_YEAR_REF, + .month = timeptr->tm_mon + 1, + .day = timeptr->tm_mday, + .dotw = timeptr->tm_wday, + .hour = timeptr->tm_hour, + .min = timeptr->tm_min, + .sec = timeptr->tm_sec, + }; + /* Use the validation in the Pico SDK. */ + if (!rtc_set_datetime(&dt)) { + err = -EINVAL; + } + k_spin_unlock(&data->lock, key); + + return err; +} + +static int rtc_rpi_pico_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + struct rtc_rpi_pico_data *data = dev->data; + datetime_t dt; + int err = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!rtc_get_datetime(&dt)) { + err = -ENODATA; + } + + timeptr->tm_sec = dt.sec; + timeptr->tm_min = dt.min; + timeptr->tm_hour = dt.hour; + timeptr->tm_mday = dt.day; + timeptr->tm_mon = dt.month - 1; + timeptr->tm_year = dt.year - TM_YEAR_REF; + timeptr->tm_wday = dt.dotw; + /* unknown values */ + timeptr->tm_yday = -1; + timeptr->tm_isdst = -1; + timeptr->tm_nsec = 0; + k_spin_unlock(&data->lock, key); + + return err; +} + +static const struct rtc_driver_api rtc_rpi_pico_driver_api = { + .set_time = rtc_rpi_pico_set_time, + .get_time = rtc_rpi_pico_get_time, +}; + +static struct rtc_rpi_pico_data rtc_data; + +DEVICE_DT_INST_DEFINE(0, &rtc_rpi_pico_init, NULL, &rtc_data, NULL, POST_KERNEL, + CONFIG_RTC_INIT_PRIORITY, &rtc_rpi_pico_driver_api); diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index 72c71bfcfd..4635aabd75 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -399,6 +399,14 @@ resets = <&reset RPI_PICO_RESETS_RESET_PIO1>; status = "disabled"; }; + + rtc: rtc@4005c000 { + compatible = "raspberrypi,pico-rtc"; + reg = <0x4005c000 DT_SIZE_K(4)>; + interrupts = <25 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + resets = <&reset RPI_PICO_RESETS_RESET_RTC>; + status = "disabled"; + }; }; pinctrl: pin-controller { diff --git a/dts/bindings/rtc/raspberrypi,pico-rtc.yaml b/dts/bindings/rtc/raspberrypi,pico-rtc.yaml new file mode 100644 index 0000000000..b947a9fc6d --- /dev/null +++ b/dts/bindings/rtc/raspberrypi,pico-rtc.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Andrew Featherstone +# SPDX-License-Identifier: Apache-2.0 + +description: RaspberryPi Pico RTC + +compatible: "raspberrypi,pico-rtc" + +include: [rtc.yaml, reset-device.yaml] + +properties: + reg: + required: true diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index 6474b18055..b68c2efdb3 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -113,6 +113,11 @@ if(CONFIG_HAS_RPI_PICO) zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_CLAIM ${rp2_common_dir}/hardware_claim/include) + zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_RTC + ${rp2_common_dir}/hardware_rtc/rtc.c) + zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_RTC + ${rp2_common_dir}/hardware_rtc/include) + # Some flash driver functions must be executed from the RAM. # Originally pico-sdk places them in the RW data section, so this # implementation does the same. diff --git a/modules/hal_rpi_pico/Kconfig b/modules/hal_rpi_pico/Kconfig index 56f92ea427..3c37c84f4c 100644 --- a/modules/hal_rpi_pico/Kconfig +++ b/modules/hal_rpi_pico/Kconfig @@ -49,3 +49,8 @@ config PICOSDK_USE_TIMER bool help Use the TIMER driver from pico-sdk + +config PICOSDK_USE_RTC + bool + help + Use the RTC driver from pico-sdk