Skip to content

Commit

Permalink
drivers: rtc: rpi_pico: Add alarm support to RPi Pico RTC driver
Browse files Browse the repository at this point in the history
This adds support for the alarm functionality of the RPi Pico RTC.

Signed-off-by: Andrew Featherstone <[email protected]>
  • Loading branch information
ajf58 committed Nov 16, 2023
1 parent c174795 commit 905e92a
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 4 deletions.
205 changes: 202 additions & 3 deletions drivers/rtc/rtc_rpi_pico.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,70 @@
#include <zephyr/logging/log.h>
#include <zephyr/spinlock.h>

#include <hardware/irq.h>
#include <hardware/rtc.h>
#include <hardware/regs/rtc.h>

#define DT_DRV_COMPAT raspberrypi_pico_rtc

/* struct tm start time: 1st, Jan, 1900 */
#define TM_YEAR_REF 1900

static int rtc_rpi_pico_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
struct rtc_time *timeptr);
struct rtc_rpi_pico_data {
struct k_spinlock lock;

#ifdef CONFIG_RTC_ALARM
struct rtc_time alarm_time;
uint16_t alarm_mask;
rtc_alarm_callback alarm_callback;
void *alarm_user_data;
bool alarm_pending;
#endif /* CONFIG_RTC_ALARM */
};

static struct rtc_rpi_pico_data rtc_data;

LOG_MODULE_REGISTER(rtc_rpi, CONFIG_RTC_LOG_LEVEL);

#ifdef CONFIG_RTC_ALARM
static void rtc_rpi_isr(const struct device *dev)
{
struct rtc_rpi_pico_data *data = dev->data;

rtc_alarm_callback callback;
void *user_data;

rtc_disable_alarm();

k_spinlock_key_t key = k_spin_lock(&data->lock);
callback = data->alarm_callback;

Check warning on line 50 in drivers/rtc/rtc_rpi_pico.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LINE_SPACING

drivers/rtc/rtc_rpi_pico.c:50 Missing a blank line after declarations
user_data = data->alarm_user_data;
k_spin_unlock(&data->lock, key);

if (callback != NULL) {
callback(dev, 0, user_data);
} else {
data->alarm_pending = true;
}
/* re-enable the alarm. */
rtc_enable_alarm();
}
#endif

static int rtc_rpi_pico_init(const struct device *dev)
{
struct rtc_rpi_pico_data *data = dev->data;

#ifdef CONFIG_RTC_ALARM
data->alarm_mask = 0;
data->alarm_callback = NULL;
data->alarm_pending = false;

IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), rtc_rpi_isr, DEVICE_DT_INST_GET(0),
0);
irq_enable(DT_INST_IRQN(0));
#endif
rtc_init();
return 0;
}
Expand Down Expand Up @@ -88,12 +137,162 @@ static int rtc_rpi_pico_get_time(const struct device *dev, struct rtc_time *time
return err;
}

#if defined(CONFIG_RTC_ALARM)
static int rtc_rpi_pico_alarm_get_supported_fields(const struct device *dev, uint16_t id,
uint16_t *supported_fields)
{
if (id != 0) {
return -EINVAL;
}
*supported_fields = RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE |
RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_WEEKDAY |
RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_MONTH |
RTC_ALARM_TIME_MASK_YEAR;

return 0;
}

static int rtc_rpi_pico_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
const struct rtc_time *alarm)
{
struct rtc_rpi_pico_data *data = dev->data;
int err = 0;

LOG_INF("Setting alarm");

rtc_disable_alarm();
if (mask == 0) {
/* Disable the alarm */
data->alarm_mask = 0;
}
k_spinlock_key_t key = k_spin_lock(&data->lock);

// Only add to setup if it isn't -1

Check failure on line 170 in drivers/rtc/rtc_rpi_pico.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

C99_COMMENTS

drivers/rtc/rtc_rpi_pico.c:170 do not use C99 // comments
rtc_hw->irq_setup_0 =
(mask & RTC_ALARM_TIME_MASK_YEAR
? (((uint32_t)alarm->tm_year + TM_YEAR_REF) << RTC_IRQ_SETUP_0_YEAR_LSB)
: 0) |
(mask & RTC_ALARM_TIME_MASK_MONTH
? (((uint32_t)alarm->tm_mon) << RTC_IRQ_SETUP_0_MONTH_LSB)
: 0) |
(mask & RTC_ALARM_TIME_MASK_MONTHDAY
? (((uint32_t)alarm->tm_mday + 1) << RTC_IRQ_SETUP_0_DAY_LSB)
: 0);
rtc_hw->irq_setup_1 = (mask & RTC_ALARM_TIME_MASK_WEEKDAY
? (((uint32_t)alarm->tm_wday) << RTC_IRQ_SETUP_1_DOTW_LSB)
: 0) |
(mask & RTC_ALARM_TIME_MASK_HOUR
? (((uint32_t)alarm->tm_hour) << RTC_IRQ_SETUP_1_HOUR_LSB)
: 0) |
(mask & RTC_ALARM_TIME_MASK_MINUTE
? (((uint32_t)alarm->tm_min) << RTC_IRQ_SETUP_1_MIN_LSB)
: 0) |
(mask & RTC_ALARM_TIME_MASK_SECOND
? (((uint32_t)alarm->tm_sec) << RTC_IRQ_SETUP_1_SEC_LSB)
: 0);

// Set the match enable bits for things we care about

Check failure on line 194 in drivers/rtc/rtc_rpi_pico.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

C99_COMMENTS

drivers/rtc/rtc_rpi_pico.c:194 do not use C99 // comments
if (mask & RTC_ALARM_TIME_MASK_YEAR) {
hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_YEAR_ENA_BITS);
}
if (mask & RTC_ALARM_TIME_MASK_MONTH) {
hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MONTH_ENA_BITS);
}
if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_DAY_ENA_BITS);
}
if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) {
hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_DOTW_ENA_BITS);
}
if (mask & RTC_ALARM_TIME_MASK_HOUR) {
hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_HOUR_ENA_BITS);
}
if (mask & RTC_ALARM_TIME_MASK_MINUTE) {
hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_MIN_ENA_BITS);
}
if (mask & RTC_ALARM_TIME_MASK_SECOND) {
hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_SEC_ENA_BITS);
}
data->alarm_time = *alarm;
data->alarm_mask = mask;
k_spin_unlock(&data->lock, key);

// Enable the IRQ at the peri

Check failure on line 220 in drivers/rtc/rtc_rpi_pico.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

C99_COMMENTS

drivers/rtc/rtc_rpi_pico.c:220 do not use C99 // comments
rtc_hw->inte = RTC_INTE_RTC_BITS;

rtc_enable_alarm();

return err;
}

static int rtc_rpi_pico_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
struct rtc_time *timeptr)
{
struct rtc_rpi_pico_data *data = dev->data;

if (id != 0) {
return -EINVAL;
}

k_spinlock_key_t key = k_spin_lock(&data->lock);
*timeptr = data->alarm_time;
*mask = data->alarm_mask;
k_spin_unlock(&data->lock, key);

return 0;
}

static int rtc_rpi_pico_alarm_is_pending(const struct device *dev, uint16_t id)
{
struct rtc_rpi_pico_data *data = dev->data;
int ret = 0;

if (id != 0) {
return -EINVAL;
}

K_SPINLOCK(&data->lock)
{
ret = data->alarm_pending ? 1 : 0;
data->alarm_pending = false;
}

return ret;
}

static int rtc_rpi_pico_alarm_set_callback(const struct device *dev, uint16_t id,
rtc_alarm_callback callback, void *user_data)
{
struct rtc_rpi_pico_data *data = dev->data;

if (id != 0) {
return -EINVAL;
}

k_spinlock_key_t key = k_spin_lock(&data->lock);
data->alarm_callback = callback;

Check warning on line 273 in drivers/rtc/rtc_rpi_pico.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LINE_SPACING

drivers/rtc/rtc_rpi_pico.c:273 Missing a blank line after declarations
data->alarm_user_data = user_data;
if ((callback == NULL) && (user_data == NULL)) {
rtc_disable_alarm();
}
k_spin_unlock(&data->lock, key);

return 0;
}

#endif /* CONFIG_RTC_ALARM */

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,
#if defined(CONFIG_RTC_ALARM)
.alarm_get_supported_fields = rtc_rpi_pico_alarm_get_supported_fields,
.alarm_set_time = rtc_rpi_pico_alarm_set_time,
.alarm_get_time = rtc_rpi_pico_alarm_get_time,
.alarm_is_pending = rtc_rpi_pico_alarm_is_pending,
.alarm_set_callback = rtc_rpi_pico_alarm_set_callback,
#endif /* CONFIG_RTC_ALARM */
};

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);
2 changes: 2 additions & 0 deletions dts/arm/rpi_pico/rp2040.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,9 @@
compatible = "raspberrypi,pico-rtc";
reg = <0x4005c000 DT_SIZE_K(4)>;
interrupts = <25 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
interrupt-names = "rtc";
resets = <&reset RPI_PICO_RESETS_RESET_RTC>;
alarms-count = <1>;
status = "disabled";
};
};
Expand Down
2 changes: 1 addition & 1 deletion dts/bindings/rtc/raspberrypi,pico-rtc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: RaspberryPi Pico RTC

compatible: "raspberrypi,pico-rtc"

include: [rtc.yaml, reset-device.yaml]
include: [rtc-device.yaml, reset-device.yaml]

properties:
reg:
Expand Down

0 comments on commit 905e92a

Please sign in to comment.