drivers: rtc: rpi_pico: Add support for the Raspberry Pi Pico RTC

This adds the minimal get_time/set_time support for the rp2040 and
enables support by default on the Pico boards. This doesn't support
configuring the clock source or alarm interrupts yet.

Signed-off-by: Andrew Featherstone <andrew.featherstone@gmail.com>
This commit is contained in:
Andrew Featherstone 2023-11-07 16:14:09 +00:00 committed by Fabio Baltieri
parent 4c880f4b0a
commit df8c89b528
9 changed files with 161 additions and 2 deletions

View file

@ -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>;

View file

@ -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)

View file

@ -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

View file

@ -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

112
drivers/rtc/rtc_rpi_pico.c Normal file
View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2024 Andrew Featherstone
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/rtc.h>
#include <zephyr/irq.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/spinlock.h>
#include <hardware/rtc.h>
#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);

View file

@ -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 {

View file

@ -0,0 +1,12 @@
# Copyright (c) 2024 Andrew Featherstone <andrew.featherstone@gmail.com>
# SPDX-License-Identifier: Apache-2.0
description: RaspberryPi Pico RTC
compatible: "raspberrypi,pico-rtc"
include: [rtc.yaml, reset-device.yaml]
properties:
reg:
required: true

View file

@ -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.

View file

@ -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