* [PATCH v10 0/3] Raspberry Pi 5 RTC driver
@ 2026-10-02 10:24 Sander Speetjens
2026-10-02 10:24 ` [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt Sander Speetjens
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Sander Speetjens @ 2026-10-02 10:24 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Jonathan Bell, Stefan Wahren, linux-rtc, devicetree,
linux-rpi-kernel, linux-arm-kernel, sander.speetjens, pbrobinson
The Raspberry Pi 5 has a battery-backed RTC located
on the DA9091 PMIC accessed via the I2C bus[1].
Access to the RTC is provided exclusively through the VideoCore firmware
mailbox interface (not via a direct I2C register interface).
As stated by jamesh on the Rasperry Pi forum [2],
"There are no plans to release a public datasheet for the DA9091."
So we are stuck with the firmware interface for now.
PhilE also states that "The firmware needs full control of the DA9091,
sometimes with extremely low latency,
otherwise there's a risk the supply could just cut the power."
This series adds:
- a DT property for the charging voltage of the RTC battery
- the RTC driver that talks to the firmware
The driver and binding are based on (and largely taken from) the
downstream Raspberry Pi kernel. The main changes for upstream are
the addition of a dt binding property for setting the charging voltage and
binding the driver from the raspberrypi-firmware driver instead of from
the DT.
The driver supports time read/write, alarm, and optional trickle
charging voltage configuration via the device-tree.
Testing
- Hardware: Raspberry Pi 5 Model B revC
- Kernel: v7.2
- dt_binding_check: passed
- Basic RTC operations (read/write time, alarm) verified
[1] https://www.raspberrypi.com/news/introducing-raspberry-pi-5/
[2] https://forums.raspberrypi.com/viewtopic.php?t=359073
Sander Speetjens (3):
dt-bindings: rtc: Add missing type to trickle-voltage-millivolt
dt-bindings: rtc: Add property for Raspberry Pi 5 RTC
rtc: Add Raspberry Pi 5 RTC driver
.../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 6 +
.../devicetree/bindings/rtc/rtc.yaml | 1 +
drivers/firmware/raspberrypi.c | 24 ++
drivers/rtc/Kconfig | 12 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-raspberrypi.c | 276 ++++++++++++++++++
include/soc/bcm2835/raspberrypi-firmware.h | 2 +
7 files changed, 322 insertions(+)
create mode 100644 drivers/rtc/rtc-raspberrypi.c
base-commit: 72d3fcf802c45d00b300f25b848a93c3a2bd7c7e
--
2.55.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt
2026-10-02 10:24 [PATCH v10 0/3] Raspberry Pi 5 RTC driver Sander Speetjens
@ 2026-10-02 10:24 ` Sander Speetjens
2026-10-02 10:26 ` sashiko-bot
2026-10-02 10:24 ` [PATCH v10 2/3] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens
2026-10-02 10:24 ` [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens
2 siblings, 1 reply; 11+ messages in thread
From: Sander Speetjens @ 2026-10-02 10:24 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Jonathan Bell, Stefan Wahren, linux-rtc, devicetree,
linux-rpi-kernel, linux-arm-kernel, sander.speetjens, pbrobinson,
Krzysztof Kozlowski
The trickle-voltage-millivolt property had no associated type.
-millivolt is not a default property unit suffix, so the schema does
not automatically infer uint32. Explicitly reference the uint32
definition so the type is correctly declared.
Suggested-by: Rob Herring <robh@kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
---
V9 -> V10: No changes
Documentation/devicetree/bindings/rtc/rtc.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/rtc/rtc.yaml b/Documentation/devicetree/bindings/rtc/rtc.yaml
index efb66df82782..e46d50b1063e 100644
--- a/Documentation/devicetree/bindings/rtc/rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/rtc.yaml
@@ -51,6 +51,7 @@ properties:
if trickle charger should be enabled.
trickle-voltage-millivolt:
+ $ref: /schemas/types.yaml#/definitions/uint32
description:
Selected voltage for trickle charger. Should be given
if trickle charger should be enabled and the trickle voltage is different
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v10 2/3] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC
2026-10-02 10:24 [PATCH v10 0/3] Raspberry Pi 5 RTC driver Sander Speetjens
2026-10-02 10:24 ` [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt Sander Speetjens
@ 2026-10-02 10:24 ` Sander Speetjens
2026-10-02 10:29 ` sashiko-bot
2026-10-02 10:24 ` [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens
2 siblings, 1 reply; 11+ messages in thread
From: Sander Speetjens @ 2026-10-02 10:24 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Jonathan Bell, Stefan Wahren, linux-rtc, devicetree,
linux-rpi-kernel, linux-arm-kernel, sander.speetjens, pbrobinson,
Conor Dooley, Krzysztof Kozlowski
The Raspberry Pi 5 has a built-in RTC that can be battery-backed
via the VBAT pin. When a rechargeable coin cell is used, the
hardware requires a trickle-charge voltage to keep the battery
topped up.
Expose the trickle-voltage-millivolt DT property so the driver can
program the correct charge voltage for board specific configurations with
the attached battery.
The property is added to the existing raspberrypi,bcm2835-firmware
binding (rather than creating a new RTC node) because the RTC is
accessed exclusively through the firmware mailbox interface.
We only $ref the individual property from rtc.yaml and do not
reference the full schema, because the firmware node name does not
match the $nodename pattern required by rtc.yaml.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
---
V9 -> V10: No changes
V8 -> V9: No changes
V7 -> V8: No changes
V6 -> V7: No changes
V5 -> V6: No changes
V4 -> V5: As discussed with Conor Dooley, the reff to uint32 is removed
and a PR is made on dt-schema adding millivolt to property-units.yaml
V3 -> V4: Add a reff to uint32
V2 -> V3: Fixed the firmware property naming
V1 -> V2: As discussed with Krzysztof Kozlowski, this property is folded into
the existing raspberrypi,bcm2835-firmware properties.
.../bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
index 983ea80eaec9..dc71fd57834e 100644
--- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
+++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
@@ -133,6 +133,11 @@ properties:
required:
- compatible
+ trickle-voltage-millivolt:
+ $ref: /schemas/rtc/rtc.yaml#/properties/trickle-voltage-millivolt
+ minimum: 1300
+ maximum: 5000
+
required:
- compatible
- mboxes
@@ -144,6 +149,7 @@ examples:
firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
mboxes = <&mailbox>;
+ trickle-voltage-millivolt = <3300>;
firmware_clocks: clocks {
compatible = "raspberrypi,firmware-clocks";
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver
2026-10-02 10:24 [PATCH v10 0/3] Raspberry Pi 5 RTC driver Sander Speetjens
2026-10-02 10:24 ` [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt Sander Speetjens
2026-10-02 10:24 ` [PATCH v10 2/3] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens
@ 2026-10-02 10:24 ` Sander Speetjens
2026-10-02 10:37 ` sashiko-bot
` (2 more replies)
2 siblings, 3 replies; 11+ messages in thread
From: Sander Speetjens @ 2026-10-02 10:24 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Jonathan Bell, Stefan Wahren, linux-rtc, devicetree,
linux-rpi-kernel, linux-arm-kernel, sander.speetjens, pbrobinson
Upstreaming the downstream Raspberry Pi 5 RTC driver.
This driver supports the custom DA9091,
which is accessed through the firmware mailbox.
Based on code originally written by Jonathan Bell <jonathan@raspberrypi.com>
and Dom Cobley <popcornmix@gmail.com>
Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
---
V9 -> V10:
- Fix sign-off-by
- Change enum to defines
- Change comment in firmware
V8 -> V9:
- Fix whitespace in Kconfig
- Move RTC regs to firmware header
- Add a warn when getting the min or max charging values fails
- Remove the unused return value of set charge voltage
V7 -> V8:
- Fix whitespacing errors
- Use of_machine_is_compatible instead of strncmp
V6 -> V7:
- Move from u32 array to struct
- Fix encapsulation as mentioned by sashiko-bot
V5 -> V6:
- Add MODULE_ALIAS, as mentioned by sashiko-bot
- Encapsulate the mailbox data in le32_to_cpu or cpu_to_le32, as
mentioned by sashiko-bot. For good practice
V4 -> V5: No changes
V3 -> V4:
- Fix Kconfig depends that disallows having Raspberrypi
firmware built as a module while the rtc driver is built in
- Remove sysfs
- Add limits from firmware properties and check in rpi_rtc_set_charge_voltage
V2 -> V3:
- Move platform check to firmware and abort before registering
a platform device if on another platform
- Add a dependency on the Raspberry Pi firmware to Kconfig
- Check return value of devm_device_init_wakeup
- Fix property name
V1 -> V2:
Instead of the original driver, which was directly bound to the device tree.
This driver is bound to the Raspberry Pi firmware device by creating
a child device in the firmware driver probe function.
The child device is then bound to this driver,
which uses the firmware mailbox to access the RTC.
A couple of minor changes have been made to the driver since it was originally written, including:
- Checking if the model is a Raspberry Pi 5, as the RTC is only present on that model.
- Using the new devm_rpi_firmware_get() and devm_init_wakeup() helper to get the firmware device and avoid leaking memory.
- Using millivolts instead of microvolts for the trickle charge voltage, to match the RTC standard.
- Instead of setting the trickle charge voltage to 0 to disable trickle charging, the property is now optional. If the property is not present, trickle charging is disabled, per the RTC standard.
- Renaming the driver dt match compatible to "raspberrypi,firmware-rtc" to match the other firmware bindings.
- Renaming the driver name to "raspberrypi-rtc" to match the other firmware drivers.
drivers/firmware/raspberrypi.c | 24 ++
drivers/rtc/Kconfig | 12 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-raspberrypi.c | 276 +++++++++++++++++++++
include/soc/bcm2835/raspberrypi-firmware.h | 2 +
5 files changed, 315 insertions(+)
create mode 100644 drivers/rtc/rtc-raspberrypi.c
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index 0aa322e9a2e7..f8c83c25eccc 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -24,6 +24,7 @@
static struct platform_device *rpi_hwmon;
static struct platform_device *rpi_clk;
+static struct platform_device *rpi_rtc;
struct rpi_firmware {
struct mbox_client cl;
@@ -231,6 +232,26 @@ static void rpi_register_clk_driver(struct device *dev)
-1, NULL, 0);
}
+static void rpi_register_rtc_driver(struct device *dev)
+{
+ struct device_node *firmware;
+
+ // Check if our model of Raspberry Pi board is from the 5th gen
+ // as the RTC is only present on that model.
+ if (!of_machine_is_compatible("brcm,bcm2712"))
+ return;
+
+ firmware = of_get_compatible_child(dev->of_node,
+ "raspberrypi,firmware-rtc");
+ if (firmware) {
+ of_node_put(firmware);
+ return;
+ }
+
+ rpi_rtc = platform_device_register_data(dev, "raspberrypi-rtc",
+ -1, NULL, 0);
+}
+
unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id)
{
struct rpi_firmware_clk_rate_request msg =
@@ -305,6 +326,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
rpi_register_clk_driver(dev);
+ rpi_register_rtc_driver(dev);
return 0;
}
@@ -327,6 +349,8 @@ static void rpi_firmware_remove(struct platform_device *pdev)
rpi_hwmon = NULL;
platform_device_unregister(rpi_clk);
rpi_clk = NULL;
+ platform_device_unregister(rpi_rtc);
+ rpi_rtc = NULL;
rpi_firmware_put(fw);
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 05b9233b9418..6dae4c069be2 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1999,6 +1999,18 @@ config RTC_DRV_R7301
This driver can also be built as a module. If so, the module
will be called rtc-r7301.
+config RTC_DRV_RPI
+ tristate "Raspberry Pi RTC"
+ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
+ depends on ARCH_BRCMSTB || COMPILE_TEST
+ default ARCH_BRCMSTB
+ help
+ If you say yes here you get support for the RTC found on
+ Raspberry Pi devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-raspberrypi.
+
config RTC_DRV_STM32
tristate "STM32 RTC"
select REGMAP_MMIO
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0347645b021f..46f1a0fc2416 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
+obj-$(CONFIG_RTC_DRV_RPI) += rtc-raspberrypi.o
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
diff --git a/drivers/rtc/rtc-raspberrypi.c b/drivers/rtc/rtc-raspberrypi.c
new file mode 100644
index 000000000000..0496851cfc30
--- /dev/null
+++ b/drivers/rtc/rtc-raspberrypi.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/**
+ * rtc-raspberrypi.c
+ *
+ * RTC driver using firmware mailbox
+ * Supports battery backed RTC and wake alarms
+ *
+ * Based on rtc-meson-vrtc by Neil Armstrong
+ *
+ * Copyright (c) 2023, Raspberry Pi Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/of.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RTC_TIME 0
+#define RTC_ALARM 1
+#define RTC_ALARM_PENDING 2
+#define RTC_ALARM_ENABLE 3
+#define RTC_BBAT_CHG_VOLTS 4
+#define RTC_BBAT_CHG_VOLTS_MIN 5
+#define RTC_BBAT_CHG_VOLTS_MAX 6
+#define RTC_BBAT_VOLTS 7
+
+struct rpi_rtc_data {
+ struct rtc_device *rtc;
+ struct rpi_firmware *fw;
+ u32 bbat_vchg_millivolts;
+ u32 bbat_vchg_min_millivolts;
+ u32 bbat_vchg_max_millivolts;
+};
+
+struct rpi_rtc_reg {
+ __le32 reg;
+ __le32 val;
+} __packed;
+
+static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_TIME)
+ };
+ int err;
+
+ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ rtc_time64_to_tm(le32_to_cpu(data.val), tm);
+ return err;
+}
+
+static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_TIME),
+ .val = cpu_to_le32(rtc_tm_to_time64(tm))
+ };
+
+ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+}
+
+static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM_ENABLE)
+ };
+ int err;
+
+ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ *enabled = le32_to_cpu(data.val) & 0x1;
+ return err;
+}
+
+static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM_ENABLE),
+ .val = cpu_to_le32(enabled)
+ };
+
+ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+}
+
+static int rpi_rtc_alarm_clear_pending(struct device *dev)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM_PENDING),
+ .val = cpu_to_le32(1)
+ };
+
+ return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+}
+
+static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM)
+ };
+ int err;
+
+ err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled);
+ if (!err)
+ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ rtc_time64_to_tm(le32_to_cpu(data.val), &alarm->time);
+
+ return err;
+}
+
+static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM),
+ .val = cpu_to_le32(rtc_tm_to_time64(&alarm->time))
+ };
+ int err;
+
+ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+
+ if (!err)
+ err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled);
+
+ return err;
+}
+
+static const struct rtc_class_ops rpi_rtc_ops = {
+ .read_time = rpi_rtc_read_time,
+ .set_time = rpi_rtc_set_time,
+ .read_alarm = rpi_rtc_read_alarm,
+ .set_alarm = rpi_rtc_set_alarm,
+ .alarm_irq_enable = rpi_rtc_alarm_irq_enable,
+};
+
+static void rpi_rtc_set_limits(struct device *dev)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS_MIN)
+ };
+
+ int err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ if (!err)
+ vrtc->bbat_vchg_min_millivolts = le32_to_cpu(data.val) / 1000U;
+ else
+ dev_warn(dev, "failed to get minimum trickle charge voltage\n");
+
+ data.reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS_MAX);
+ data.val = cpu_to_le32(0);
+ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ if (!err)
+ vrtc->bbat_vchg_max_millivolts = le32_to_cpu(data.val) / 1000U;
+ else
+ dev_warn(dev, "failed to get maximum trickle charge voltage\n");
+}
+
+static void rpi_rtc_set_charge_voltage(struct device *dev)
+{
+ struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS),
+ .val = cpu_to_le32(vrtc->bbat_vchg_millivolts * 1000U)
+ };
+ int err;
+
+ if (vrtc->bbat_vchg_millivolts != 0 &&
+ (vrtc->bbat_vchg_millivolts < vrtc->bbat_vchg_min_millivolts ||
+ vrtc->bbat_vchg_millivolts > vrtc->bbat_vchg_max_millivolts)) {
+ dev_warn(dev, "trickle charge voltage %umV is outside of the supported range (%umV - %umV)\n",
+ vrtc->bbat_vchg_millivolts,
+ vrtc->bbat_vchg_min_millivolts,
+ vrtc->bbat_vchg_max_millivolts);
+ return;
+ }
+
+ err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+
+ if (err)
+ dev_err(dev, "failed to set trickle charge voltage to %umV: %d\n",
+ vrtc->bbat_vchg_millivolts, err);
+ else if (vrtc->bbat_vchg_millivolts)
+ dev_info(dev, "trickle charging enabled at %umV\n",
+ vrtc->bbat_vchg_millivolts);
+}
+
+static int rpi_rtc_probe(struct platform_device *pdev)
+{
+ struct rpi_rtc_data *vrtc;
+ struct device *dev = &pdev->dev;
+ struct rpi_firmware *firmware;
+ int ret;
+
+ // Get the firmware device from the parent device
+ firmware = devm_rpi_firmware_get(dev, dev->parent->of_node);
+
+ if (!firmware)
+ return -EPROBE_DEFER;
+
+ vrtc = devm_kzalloc(dev, sizeof(*vrtc), GFP_KERNEL);
+ if (!vrtc)
+ return -ENOMEM;
+
+ vrtc->fw = firmware;
+
+ ret = devm_device_init_wakeup(dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, vrtc);
+
+ vrtc->rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(vrtc->rtc))
+ return PTR_ERR(vrtc->rtc);
+
+ vrtc->rtc->range_max = U32_MAX; /* 2106-02-07 */
+
+ set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, vrtc->rtc->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features);
+
+ vrtc->rtc->ops = &rpi_rtc_ops;
+
+ rpi_rtc_alarm_clear_pending(dev);
+
+ /*
+ * The trickle-voltage property lives on the parent firmware node
+ * because we deliberately do not create a DT child node just to
+ * instantiate this driver (see DT maintainer guidance).
+ * The firmware driver registers us as a platform device at runtime.
+ */
+ vrtc->bbat_vchg_millivolts = 0;
+ of_property_read_u32(dev->parent->of_node, "trickle-voltage-millivolt",
+ &vrtc->bbat_vchg_millivolts);
+
+ rpi_rtc_set_limits(dev);
+ rpi_rtc_set_charge_voltage(dev);
+
+ return devm_rtc_register_device(vrtc->rtc);
+}
+
+static const struct of_device_id rpi_rtc_dt_match[] = {
+ { .compatible = "raspberrypi,firmware-rtc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rpi_rtc_dt_match);
+
+static struct platform_driver rpi_rtc_driver = {
+ .driver = {
+ .name = "raspberrypi-rtc",
+ .of_match_table = of_match_ptr(rpi_rtc_dt_match),
+ },
+ .probe = rpi_rtc_probe
+};
+
+module_platform_driver(rpi_rtc_driver);
+
+MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.com>");
+MODULE_AUTHOR("Sander Speetjens <sander.speetjens@gmail.com>");
+MODULE_DESCRIPTION("Raspberry Pi RTC driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:raspberrypi-rtc");
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
index 975bef529854..e13994d8281c 100644
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -75,6 +75,8 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
+ RPI_FIRMWARE_GET_RTC_REG = 0x00030087,
+ RPI_FIRMWARE_SET_RTC_REG = 0x00038087,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt
2026-10-02 10:24 ` [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt Sander Speetjens
@ 2026-10-02 10:26 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-10-02 10:26 UTC (permalink / raw)
To: Sander Speetjens; +Cc: Alexandre Belloni, robh, devicetree, conor+dt, linux-rtc
> The trickle-voltage-millivolt property had no associated type.
> -millivolt is not a default property unit suffix, so the schema does
> not automatically infer uint32. Explicitly reference the uint32
> definition so the type is correctly declared.
>
> Suggested-by: Rob Herring <robh@kernel.org>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261002102419.830595-1-sander.speetjens@gmail.com?part=1
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v10 2/3] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC
2026-10-02 10:24 ` [PATCH v10 2/3] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens
@ 2026-10-02 10:29 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-10-02 10:29 UTC (permalink / raw)
To: Sander Speetjens; +Cc: conor+dt, linux-rtc, devicetree, Alexandre Belloni, robh
> The Raspberry Pi 5 has a built-in RTC that can be battery-backed
> via the VBAT pin. When a rechargeable coin cell is used, the
> hardware requires a trickle-charge voltage to keep the battery
> topped up.
>
> Expose the trickle-voltage-millivolt DT property so the driver can
> program the correct charge voltage for board specific configurations with
> the attached battery.
>
> The property is added to the existing raspberrypi,bcm2835-firmware
> binding (rather than creating a new RTC node) because the RTC is
> accessed exclusively through the firmware mailbox interface.
> We only $ref the individual property from rtc.yaml and do not
> reference the full schema, because the firmware node name does not
> match the $nodename pattern required by rtc.yaml.
>
> Acked-by: Conor Dooley <conor.dooley@microchip.com>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261002102419.830595-1-sander.speetjens@gmail.com?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver
2026-10-02 10:24 ` [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens
@ 2026-10-02 10:37 ` sashiko-bot
2026-10-02 13:58 ` Stefan Wahren
2026-10-02 20:11 ` Gregor Herburger
2 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-10-02 10:37 UTC (permalink / raw)
To: Sander Speetjens; +Cc: Alexandre Belloni, devicetree, robh, conor+dt, linux-rtc
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] kernel panic due to passing ERR_PTR to platform_device_unregister
--
commit 871d9696731b8e115094c715d59226e0d29be3d2
Author: Sander Speetjens <sander.speetjens@gmail.com>
rtc: Add Raspberry Pi 5 RTC driver
This commit adds support for the Raspberry Pi 5 RTC by registering a new
platform device through the existing BCM2835 firmware driver.
> diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
> --- a/drivers/firmware/raspberrypi.c
> +++ b/drivers/firmware/raspberrypi.c
> @@ -231,6 +232,26 @@ static void rpi_register_clk_driver(struct device *dev)
[ ... ]
> +static void rpi_register_rtc_driver(struct device *dev)
> +{
> + struct device_node *firmware;
> +
> + // Check if our model of Raspberry Pi board is from the 5th gen
> + // as the RTC is only present on that model.
> + if (!of_machine_is_compatible("brcm,bcm2712"))
> + return;
> +
> + firmware = of_get_compatible_child(dev->of_node,
> + "raspberrypi,firmware-rtc");
> + if (firmware) {
> + of_node_put(firmware);
> + return;
> + }
> +
> + rpi_rtc = platform_device_register_data(dev, "raspberrypi-rtc",
> + -1, NULL, 0);
> +}
[Severity: High]
If platform_device_register_data() fails (for example, due to an out of
memory condition), it returns an ERR_PTR. Is it safe to store this error
pointer directly in the global rpi_rtc variable without an IS_ERR() check?
[ ... ]
> @@ -327,6 +349,8 @@ static void rpi_firmware_remove(struct platform_device *pdev)
> rpi_hwmon = NULL;
> platform_device_unregister(rpi_clk);
> rpi_clk = NULL;
> + platform_device_unregister(rpi_rtc);
> + rpi_rtc = NULL;
[Severity: High]
Can this cause a kernel panic during unbind or module removal?
If platform_device_register_data() previously failed and returned an
ERR_PTR, rpi_firmware_probe() still returns 0 (success) so the firmware
driver binds successfully. Later, when rpi_firmware_remove() is called,
platform_device_unregister() is invoked on rpi_rtc.
While platform_device_unregister() safely ignores NULL pointers, it
attempts to dereference ERR_PTRs, which would lead to an invalid memory
access. Does this path need a check to ensure rpi_rtc is valid before
unregistering?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261002102419.830595-1-sander.speetjens@gmail.com?part=3
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver
2026-10-02 10:24 ` [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens
2026-10-02 10:37 ` sashiko-bot
@ 2026-10-02 13:58 ` Stefan Wahren
2026-10-02 15:02 ` Sander Speetjens
2026-10-02 20:11 ` Gregor Herburger
2 siblings, 1 reply; 11+ messages in thread
From: Stefan Wahren @ 2026-10-02 13:58 UTC (permalink / raw)
To: Sander Speetjens, Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Jonathan Bell, linux-rtc, devicetree, linux-rpi-kernel,
linux-arm-kernel, pbrobinson
Hello Sander,
Am 02.10.26 um 12:24 schrieb Sander Speetjens:
> Upstreaming the downstream Raspberry Pi 5 RTC driver.
> This driver supports the custom DA9091,
> which is accessed through the firmware mailbox.
>
> Based on code originally written by Jonathan Bell <jonathan@raspberrypi.com>
> and Dom Cobley <popcornmix@gmail.com>
>
> Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
in general this patch looks good except a few nits, maybe wait for
Alexandre's feedback.
After fixing the nits you can add my:
Reviewed-by: Stefan Wahren <wahrenst@gmx.net>
> ---
> V9 -> V10:
> - Fix sign-off-by
> - Change enum to defines
> - Change comment in firmware
>
> V8 -> V9:
> - Fix whitespace in Kconfig
> - Move RTC regs to firmware header
> - Add a warn when getting the min or max charging values fails
> - Remove the unused return value of set charge voltage
>
> V7 -> V8:
> - Fix whitespacing errors
> - Use of_machine_is_compatible instead of strncmp
>
> V6 -> V7:
> - Move from u32 array to struct
> - Fix encapsulation as mentioned by sashiko-bot
>
> V5 -> V6:
> - Add MODULE_ALIAS, as mentioned by sashiko-bot
> - Encapsulate the mailbox data in le32_to_cpu or cpu_to_le32, as
> mentioned by sashiko-bot. For good practice
>
> V4 -> V5: No changes
>
> V3 -> V4:
> - Fix Kconfig depends that disallows having Raspberrypi
> firmware built as a module while the rtc driver is built in
> - Remove sysfs
> - Add limits from firmware properties and check in rpi_rtc_set_charge_voltage
>
> V2 -> V3:
> - Move platform check to firmware and abort before registering
> a platform device if on another platform
> - Add a dependency on the Raspberry Pi firmware to Kconfig
> - Check return value of devm_device_init_wakeup
> - Fix property name
>
> V1 -> V2:
> Instead of the original driver, which was directly bound to the device tree.
> This driver is bound to the Raspberry Pi firmware device by creating
> a child device in the firmware driver probe function.
> The child device is then bound to this driver,
> which uses the firmware mailbox to access the RTC.
>
> A couple of minor changes have been made to the driver since it was originally written, including:
> - Checking if the model is a Raspberry Pi 5, as the RTC is only present on that model.
> - Using the new devm_rpi_firmware_get() and devm_init_wakeup() helper to get the firmware device and avoid leaking memory.
> - Using millivolts instead of microvolts for the trickle charge voltage, to match the RTC standard.
> - Instead of setting the trickle charge voltage to 0 to disable trickle charging, the property is now optional. If the property is not present, trickle charging is disabled, per the RTC standard.
> - Renaming the driver dt match compatible to "raspberrypi,firmware-rtc" to match the other firmware bindings.
> - Renaming the driver name to "raspberrypi-rtc" to match the other firmware drivers.
>
> drivers/firmware/raspberrypi.c | 24 ++
> drivers/rtc/Kconfig | 12 +
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-raspberrypi.c | 276 +++++++++++++++++++++
> include/soc/bcm2835/raspberrypi-firmware.h | 2 +
> 5 files changed, 315 insertions(+)
> create mode 100644 drivers/rtc/rtc-raspberrypi.c
>
> diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
> index 0aa322e9a2e7..f8c83c25eccc 100644
> --- a/drivers/firmware/raspberrypi.c
> +++ b/drivers/firmware/raspberrypi.c
> @@ -24,6 +24,7 @@
>
> static struct platform_device *rpi_hwmon;
> static struct platform_device *rpi_clk;
> +static struct platform_device *rpi_rtc;
>
> struct rpi_firmware {
> struct mbox_client cl;
> @@ -231,6 +232,26 @@ static void rpi_register_clk_driver(struct device *dev)
> -1, NULL, 0);
> }
>
> +static void rpi_register_rtc_driver(struct device *dev)
> +{
> + struct device_node *firmware;
> +
> + // Check if our model of Raspberry Pi board is from the 5th gen
> + // as the RTC is only present on that model.
> + if (!of_machine_is_compatible("brcm,bcm2712"))
> + return;
> +
> + firmware = of_get_compatible_child(dev->of_node,
> + "raspberrypi,firmware-rtc");
> + if (firmware) {
> + of_node_put(firmware);
> + return;
> + }
> +
> + rpi_rtc = platform_device_register_data(dev, "raspberrypi-rtc",
> + -1, NULL, 0);
> +}
> +
> unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id)
> {
> struct rpi_firmware_clk_rate_request msg =
> @@ -305,6 +326,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
> rpi_firmware_print_firmware_revision(fw);
> rpi_register_hwmon_driver(dev, fw);
> rpi_register_clk_driver(dev);
> + rpi_register_rtc_driver(dev);
>
> return 0;
> }
> @@ -327,6 +349,8 @@ static void rpi_firmware_remove(struct platform_device *pdev)
> rpi_hwmon = NULL;
> platform_device_unregister(rpi_clk);
> rpi_clk = NULL;
> + platform_device_unregister(rpi_rtc);
> + rpi_rtc = NULL;
>
> rpi_firmware_put(fw);
> }
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 05b9233b9418..6dae4c069be2 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1999,6 +1999,18 @@ config RTC_DRV_R7301
> This driver can also be built as a module. If so, the module
> will be called rtc-r7301.
>
> +config RTC_DRV_RPI
> + tristate "Raspberry Pi RTC"
> + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
> + depends on ARCH_BRCMSTB || COMPILE_TEST
> + default ARCH_BRCMSTB
> + help
> + If you say yes here you get support for the RTC found on
> + Raspberry Pi devices.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-raspberrypi.
Sorry for my misleading wording. I meant in this case 1 tab and align
the rest with spaces just like the other.
...
> diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
> index 975bef529854..e13994d8281c 100644
> --- a/include/soc/bcm2835/raspberrypi-firmware.h
> +++ b/include/soc/bcm2835/raspberrypi-firmware.h
> @@ -75,6 +75,8 @@ enum rpi_firmware_property_tag {
> RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
> RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
> RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
> + RPI_FIRMWARE_GET_RTC_REG = 0x00030087,
> + RPI_FIRMWARE_SET_RTC_REG = 0x00038087,
Please try to keep the value order. I know it's already messed up,
Gregor Herburger send a patch which already address the existing order
("firmware: raspberrypi: reorder rpi_firmware_property_tag enum").
Best regards
> RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
> RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
> RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver
2026-10-02 13:58 ` Stefan Wahren
@ 2026-10-02 15:02 ` Sander Speetjens
2026-10-02 15:19 ` Stefan Wahren
0 siblings, 1 reply; 11+ messages in thread
From: Sander Speetjens @ 2026-10-02 15:02 UTC (permalink / raw)
To: Stefan Wahren
Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Florian Fainelli, Jonathan Bell, linux-rtc, devicetree,
linux-rpi-kernel, linux-arm-kernel, pbrobinson
Hi stefan,
I was thinking of making the raspberrypi.c firmware a speparate patch,
what would you think of this?
Because it overlays with another patch
(https://lore.kernel.org/linux-arm-kernel/20260919034840.28593-2-triet.hoang.dev@gmail.com/)
Kind regards
On Fri, 2 Oct 2026 at 15:58, Stefan Wahren <wahrenst@gmx.net> wrote:
>
> Hello Sander,
>
> Am 02.10.26 um 12:24 schrieb Sander Speetjens:
> > Upstreaming the downstream Raspberry Pi 5 RTC driver.
> > This driver supports the custom DA9091,
> > which is accessed through the firmware mailbox.
> >
> > Based on code originally written by Jonathan Bell <jonathan@raspberrypi.com>
> > and Dom Cobley <popcornmix@gmail.com>
> >
> > Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com>
> in general this patch looks good except a few nits, maybe wait for
> Alexandre's feedback.
> After fixing the nits you can add my:
>
> Reviewed-by: Stefan Wahren <wahrenst@gmx.net>
> > ---
> > V9 -> V10:
> > - Fix sign-off-by
> > - Change enum to defines
> > - Change comment in firmware
> >
> > V8 -> V9:
> > - Fix whitespace in Kconfig
> > - Move RTC regs to firmware header
> > - Add a warn when getting the min or max charging values fails
> > - Remove the unused return value of set charge voltage
> >
> > V7 -> V8:
> > - Fix whitespacing errors
> > - Use of_machine_is_compatible instead of strncmp
> >
> > V6 -> V7:
> > - Move from u32 array to struct
> > - Fix encapsulation as mentioned by sashiko-bot
> >
> > V5 -> V6:
> > - Add MODULE_ALIAS, as mentioned by sashiko-bot
> > - Encapsulate the mailbox data in le32_to_cpu or cpu_to_le32, as
> > mentioned by sashiko-bot. For good practice
> >
> > V4 -> V5: No changes
> >
> > V3 -> V4:
> > - Fix Kconfig depends that disallows having Raspberrypi
> > firmware built as a module while the rtc driver is built in
> > - Remove sysfs
> > - Add limits from firmware properties and check in rpi_rtc_set_charge_voltage
> >
> > V2 -> V3:
> > - Move platform check to firmware and abort before registering
> > a platform device if on another platform
> > - Add a dependency on the Raspberry Pi firmware to Kconfig
> > - Check return value of devm_device_init_wakeup
> > - Fix property name
> >
> > V1 -> V2:
> > Instead of the original driver, which was directly bound to the device tree.
> > This driver is bound to the Raspberry Pi firmware device by creating
> > a child device in the firmware driver probe function.
> > The child device is then bound to this driver,
> > which uses the firmware mailbox to access the RTC.
> >
> > A couple of minor changes have been made to the driver since it was originally written, including:
> > - Checking if the model is a Raspberry Pi 5, as the RTC is only present on that model.
> > - Using the new devm_rpi_firmware_get() and devm_init_wakeup() helper to get the firmware device and avoid leaking memory.
> > - Using millivolts instead of microvolts for the trickle charge voltage, to match the RTC standard.
> > - Instead of setting the trickle charge voltage to 0 to disable trickle charging, the property is now optional. If the property is not present, trickle charging is disabled, per the RTC standard.
> > - Renaming the driver dt match compatible to "raspberrypi,firmware-rtc" to match the other firmware bindings.
> > - Renaming the driver name to "raspberrypi-rtc" to match the other firmware drivers.
> >
> > drivers/firmware/raspberrypi.c | 24 ++
> > drivers/rtc/Kconfig | 12 +
> > drivers/rtc/Makefile | 1 +
> > drivers/rtc/rtc-raspberrypi.c | 276 +++++++++++++++++++++
> > include/soc/bcm2835/raspberrypi-firmware.h | 2 +
> > 5 files changed, 315 insertions(+)
> > create mode 100644 drivers/rtc/rtc-raspberrypi.c
> >
> > diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
> > index 0aa322e9a2e7..f8c83c25eccc 100644
> > --- a/drivers/firmware/raspberrypi.c
> > +++ b/drivers/firmware/raspberrypi.c
> > @@ -24,6 +24,7 @@
> >
> > static struct platform_device *rpi_hwmon;
> > static struct platform_device *rpi_clk;
> > +static struct platform_device *rpi_rtc;
> >
> > struct rpi_firmware {
> > struct mbox_client cl;
> > @@ -231,6 +232,26 @@ static void rpi_register_clk_driver(struct device *dev)
> > -1, NULL, 0);
> > }
> >
> > +static void rpi_register_rtc_driver(struct device *dev)
> > +{
> > + struct device_node *firmware;
> > +
> > + // Check if our model of Raspberry Pi board is from the 5th gen
> > + // as the RTC is only present on that model.
> > + if (!of_machine_is_compatible("brcm,bcm2712"))
> > + return;
> > +
> > + firmware = of_get_compatible_child(dev->of_node,
> > + "raspberrypi,firmware-rtc");
> > + if (firmware) {
> > + of_node_put(firmware);
> > + return;
> > + }
> > +
> > + rpi_rtc = platform_device_register_data(dev, "raspberrypi-rtc",
> > + -1, NULL, 0);
> > +}
> > +
> > unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id)
> > {
> > struct rpi_firmware_clk_rate_request msg =
> > @@ -305,6 +326,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
> > rpi_firmware_print_firmware_revision(fw);
> > rpi_register_hwmon_driver(dev, fw);
> > rpi_register_clk_driver(dev);
> > + rpi_register_rtc_driver(dev);
> >
> > return 0;
> > }
> > @@ -327,6 +349,8 @@ static void rpi_firmware_remove(struct platform_device *pdev)
> > rpi_hwmon = NULL;
> > platform_device_unregister(rpi_clk);
> > rpi_clk = NULL;
> > + platform_device_unregister(rpi_rtc);
> > + rpi_rtc = NULL;
> >
> > rpi_firmware_put(fw);
> > }
> > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> > index 05b9233b9418..6dae4c069be2 100644
> > --- a/drivers/rtc/Kconfig
> > +++ b/drivers/rtc/Kconfig
> > @@ -1999,6 +1999,18 @@ config RTC_DRV_R7301
> > This driver can also be built as a module. If so, the module
> > will be called rtc-r7301.
> >
> > +config RTC_DRV_RPI
> > + tristate "Raspberry Pi RTC"
> > + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
> > + depends on ARCH_BRCMSTB || COMPILE_TEST
> > + default ARCH_BRCMSTB
> > + help
> > + If you say yes here you get support for the RTC found on
> > + Raspberry Pi devices.
> > +
> > + This driver can also be built as a module. If so, the module
> > + will be called rtc-raspberrypi.
> Sorry for my misleading wording. I meant in this case 1 tab and align
> the rest with spaces just like the other.
> ...
> > diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
> > index 975bef529854..e13994d8281c 100644
> > --- a/include/soc/bcm2835/raspberrypi-firmware.h
> > +++ b/include/soc/bcm2835/raspberrypi-firmware.h
> > @@ -75,6 +75,8 @@ enum rpi_firmware_property_tag {
> > RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
> > RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
> > RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
> > + RPI_FIRMWARE_GET_RTC_REG = 0x00030087,
> > + RPI_FIRMWARE_SET_RTC_REG = 0x00038087,
> Please try to keep the value order. I know it's already messed up,
> Gregor Herburger send a patch which already address the existing order
> ("firmware: raspberrypi: reorder rpi_firmware_property_tag enum").
>
> Best regards
> > RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
> > RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
> > RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver
2026-10-02 15:02 ` Sander Speetjens
@ 2026-10-02 15:19 ` Stefan Wahren
0 siblings, 0 replies; 11+ messages in thread
From: Stefan Wahren @ 2026-10-02 15:19 UTC (permalink / raw)
To: Sander Speetjens
Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Florian Fainelli, Jonathan Bell, linux-rtc, devicetree,
linux-rpi-kernel, linux-arm-kernel, pbrobinson
Hi Sander,
Am 02.10.26 um 17:02 schrieb Sander Speetjens:
> Hi stefan,
> I was thinking of making the raspberrypi.c firmware a speparate patch,
> what would you think of this?
> Because it overlays with another patch
> (https://lore.kernel.org/linux-arm-kernel/20260919034840.28593-2-triet.hoang.dev@gmail.com/)
AFAIK it's not your job to solve these conflicts and sending a separate
patch wouldn't be a solution. The best way would be to get Triet's patch
series applied first. Markus had a objection, which i don't understand.
So I asked him for a explanation.
Best regards
>
> Kind regards
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver
2026-10-02 10:24 ` [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens
2026-10-02 10:37 ` sashiko-bot
2026-10-02 13:58 ` Stefan Wahren
@ 2026-10-02 20:11 ` Gregor Herburger
2 siblings, 0 replies; 11+ messages in thread
From: Gregor Herburger @ 2026-10-02 20:11 UTC (permalink / raw)
To: Sander Speetjens
Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Florian Fainelli, Jonathan Bell, Stefan Wahren, linux-rtc,
devicetree, linux-rpi-kernel, linux-arm-kernel, pbrobinson
Hi,
On Fri, Oct 02, 2026 at 12:24:19PM +0200, Sander Speetjens wrote:
...
>
> +static void rpi_register_rtc_driver(struct device *dev)
> +{
> + struct device_node *firmware;
> +
> + // Check if our model of Raspberry Pi board is from the 5th gen
> + // as the RTC is only present on that model.
Multiline comments should be /* */.
> + if (!of_machine_is_compatible("brcm,bcm2712"))
> + return;
> +
> + firmware = of_get_compatible_child(dev->of_node,
> + "raspberrypi,firmware-rtc");
If you don't have a "raspberrypi,firmware-rtc" compatible this is not needed.
For the other drivers this is here because it needs to be compatible with old devicetrees.
> + if (firmware) {
> + of_node_put(firmware);
> + return;
> + }
> +
> + rpi_rtc = platform_device_register_data(dev, "raspberrypi-rtc",
> + -1, NULL, 0);
> +}
...
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 05b9233b9418..6dae4c069be2 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1999,6 +1999,18 @@ config RTC_DRV_R7301
> This driver can also be built as a module. If so, the module
> will be called rtc-r7301.
>
> +config RTC_DRV_RPI
> + tristate "Raspberry Pi RTC"
> + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
> + depends on ARCH_BRCMSTB || COMPILE_TEST
> + default ARCH_BRCMSTB
> + help
> + If you say yes here you get support for the RTC found on
> + Raspberry Pi devices.
You should mention here on which Raspberry devices.
> +
> + This driver can also be built as a module. If so, the module
> + will be called rtc-raspberrypi.
> +
> config RTC_DRV_STM32
> tristate "STM32 RTC"
> select REGMAP_MMIO
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 0347645b021f..46f1a0fc2416 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
> obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
> obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
> obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
> +obj-$(CONFIG_RTC_DRV_RPI) += rtc-raspberrypi.o
> obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
> obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o
> obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
> diff --git a/drivers/rtc/rtc-raspberrypi.c b/drivers/rtc/rtc-raspberrypi.c
> new file mode 100644
> index 000000000000..0496851cfc30
> --- /dev/null
> +++ b/drivers/rtc/rtc-raspberrypi.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/**
> + * rtc-raspberrypi.c
> + *
> + * RTC driver using firmware mailbox
> + * Supports battery backed RTC and wake alarms
> + *
> + * Based on rtc-meson-vrtc by Neil Armstrong
> + *
> + * Copyright (c) 2023, Raspberry Pi Ltd.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/rtc.h>
> +#include <linux/of.h>
> +#include <soc/bcm2835/raspberrypi-firmware.h>
> +
> +#define RTC_TIME 0
There is a space before a tab. You should run the scripts/checkpatch.pl script
before sending patches.
> +#define RTC_ALARM 1
> +#define RTC_ALARM_PENDING 2
> +#define RTC_ALARM_ENABLE 3
> +#define RTC_BBAT_CHG_VOLTS 4
> +#define RTC_BBAT_CHG_VOLTS_MIN 5
> +#define RTC_BBAT_CHG_VOLTS_MAX 6
> +#define RTC_BBAT_VOLTS 7
> +
> +struct rpi_rtc_data {
> + struct rtc_device *rtc;
> + struct rpi_firmware *fw;
> + u32 bbat_vchg_millivolts;
> + u32 bbat_vchg_min_millivolts;
> + u32 bbat_vchg_max_millivolts;
> +};
> +
> +struct rpi_rtc_reg {
> + __le32 reg;
> + __le32 val;
> +} __packed;
> +
> +static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
I find the name vrtc confusing. It is probably a leftover of that above
mentioned rtc-meson-vrtc driver.
...
> +static int rpi_rtc_probe(struct platform_device *pdev)
> +{
> + struct rpi_rtc_data *vrtc;
> + struct device *dev = &pdev->dev;
> + struct rpi_firmware *firmware;
> + int ret;
> +
> + // Get the firmware device from the parent device
> + firmware = devm_rpi_firmware_get(dev, dev->parent->of_node);
> +
> + if (!firmware)
> + return -EPROBE_DEFER;
> +
> + vrtc = devm_kzalloc(dev, sizeof(*vrtc), GFP_KERNEL);
> + if (!vrtc)
> + return -ENOMEM;
> +
> + vrtc->fw = firmware;
> +
> + ret = devm_device_init_wakeup(dev);
> + if (ret)
> + return ret;
> +
> + platform_set_drvdata(pdev, vrtc);
> +
> + vrtc->rtc = devm_rtc_allocate_device(dev);
> + if (IS_ERR(vrtc->rtc))
> + return PTR_ERR(vrtc->rtc);
> +
> + vrtc->rtc->range_max = U32_MAX; /* 2106-02-07 */
> +
> + set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, vrtc->rtc->features);
> + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features);
> +
> + vrtc->rtc->ops = &rpi_rtc_ops;
> +
> + rpi_rtc_alarm_clear_pending(dev);
> +
> + /*
> + * The trickle-voltage property lives on the parent firmware node
> + * because we deliberately do not create a DT child node just to
> + * instantiate this driver (see DT maintainer guidance).
> + * The firmware driver registers us as a platform device at runtime.
> + */
> + vrtc->bbat_vchg_millivolts = 0;
> + of_property_read_u32(dev->parent->of_node, "trickle-voltage-millivolt",
> + &vrtc->bbat_vchg_millivolts);
> +
> + rpi_rtc_set_limits(dev);
> + rpi_rtc_set_charge_voltage(dev);
> +
> + return devm_rtc_register_device(vrtc->rtc);
> +}
> +
> +static const struct of_device_id rpi_rtc_dt_match[] = {
> + { .compatible = "raspberrypi,firmware-rtc" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, rpi_rtc_dt_match);
Without dt-compatible this is not needed. Checkpatch also complains about this
undocumented compatible string.
I think this should be:
static const struct platform_device_id raspberrypi_rtc_id[] = {
{ "raspberrypi-rtc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, raspberrypi_rtc_id);
This should also construct your alias and you can remove the MODULE_ALIAS.
> +
> +static struct platform_driver rpi_rtc_driver = {
> + .driver = {
> + .name = "raspberrypi-rtc",
> + .of_match_table = of_match_ptr(rpi_rtc_dt_match),
> + },
> + .probe = rpi_rtc_probe
> +};
> +
> +module_platform_driver(rpi_rtc_driver);
> +
> +MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.com>");
> +MODULE_AUTHOR("Sander Speetjens <sander.speetjens@gmail.com>");
> +MODULE_DESCRIPTION("Raspberry Pi RTC driver");
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_ALIAS("platform:raspberrypi-rtc");
> diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
> index 975bef529854..e13994d8281c 100644
> --- a/include/soc/bcm2835/raspberrypi-firmware.h
> +++ b/include/soc/bcm2835/raspberrypi-firmware.h
> @@ -75,6 +75,8 @@ enum rpi_firmware_property_tag {
> RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
> RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
> RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
> + RPI_FIRMWARE_GET_RTC_REG = 0x00030087,
> + RPI_FIRMWARE_SET_RTC_REG = 0x00038087,
> RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
> RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
> RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
Best regards
Gregor Herburger
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-10-02 20:11 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-02 10:24 [PATCH v10 0/3] Raspberry Pi 5 RTC driver Sander Speetjens
2026-10-02 10:24 ` [PATCH v10 1/3] dt-bindings: rtc: Add missing type to trickle-voltage-millivolt Sander Speetjens
2026-10-02 10:26 ` sashiko-bot
2026-10-02 10:24 ` [PATCH v10 2/3] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens
2026-10-02 10:29 ` sashiko-bot
2026-10-02 10:24 ` [PATCH v10 3/3] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens
2026-10-02 10:37 ` sashiko-bot
2026-10-02 13:58 ` Stefan Wahren
2026-10-02 15:02 ` Sander Speetjens
2026-10-02 15:19 ` Stefan Wahren
2026-10-02 20:11 ` Gregor Herburger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).