* [PATCH v4 0/2] Raspberry Pi 5 RTC driver @ 2026-09-23 13:13 Sander Speetjens 2026-09-23 13:13 ` [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens 2026-09-23 13:13 ` [PATCH v4 2/2] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens 0 siblings, 2 replies; 8+ messages in thread From: Sander Speetjens @ 2026-09-23 13:13 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 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 (2): dt-bindings: rtc: Add property for Raspberry Pi 5 RTC rtc: Add Raspberry Pi 5 RTC driver .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 8 + drivers/firmware/raspberrypi.c | 25 ++ drivers/rtc/Kconfig | 12 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-raspberrypi.c | 242 ++++++++++++++++++ 5 files changed, 288 insertions(+) create mode 100644 drivers/rtc/rtc-raspberrypi.c base-commit: 93f51579e7df248780214094418f205253383cc5 -- 2.55.0 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC 2026-09-23 13:13 [PATCH v4 0/2] Raspberry Pi 5 RTC driver Sander Speetjens @ 2026-09-23 13:13 ` Sander Speetjens 2026-09-23 13:21 ` sashiko-bot 2026-09-23 16:37 ` Conor Dooley 2026-09-23 13:13 ` [PATCH v4 2/2] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens 1 sibling, 2 replies; 8+ messages in thread From: Sander Speetjens @ 2026-09-23 13:13 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 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. Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com> --- 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 | 8 ++++++++ 1 file changed, 8 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..9349fc8908a5 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -133,6 +133,13 @@ properties: required: - compatible + trickle-voltage-millivolt: + allOf: + - $ref: /schemas/rtc/rtc.yaml#/properties/trickle-voltage-millivolt + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 1300 + maximum: 5000 + required: - compatible - mboxes @@ -144,6 +151,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] 8+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC 2026-09-23 13:13 ` [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens @ 2026-09-23 13:21 ` sashiko-bot 2026-09-23 16:37 ` Conor Dooley 1 sibling, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-09-23 13:21 UTC (permalink / raw) To: Sander Speetjens; +Cc: devicetree, Alexandre Belloni, robh, linux-rtc, conor+dt Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] dt-bindings: minimum and maximum constraints are ignored due to array isolation -- commit ff7cdbdeb8fcd609ef36f409f92bd2d94dc107d7 Author: Sander Speetjens <sander.speetjens@gmail.com> dt-bindings: rtc: Add property for Raspberry Pi 5 RTC The Raspberry Pi 5 has a built-in RTC that can be battery-backed via the VBAT pin. Expose the trickle-voltage-millivolt DT property so the driver can program the correct charge voltage for board specific configurations with the attached battery. > diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml > index 983ea80eaec97..9349fc8908a50 100644 > --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml > +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml > @@ -133,6 +133,13 @@ properties: > required: > - compatible > > + trickle-voltage-millivolt: > + allOf: > + - $ref: /schemas/rtc/rtc.yaml#/properties/trickle-voltage-millivolt > + - $ref: /schemas/types.yaml#/definitions/uint32 > + - minimum: 1300 > + maximum: 5000 [Severity: Low] Are the minimum and maximum constraints ignored here due to being placed in a separate dictionary under allOf? In dt-schema, properties using scalar types like uint32 are parsed as arrays. The JSON Schema minimum and maximum keywords only apply to numeric instances, so when applied to an array, they are silently ignored. The dt-schema preprocessor fixes this by pushing constraints into the items schema, but only if they reside in the exact same dictionary as the reference to /schemas/types.yaml#/definitions/uint32. Because minimum and maximum are placed in a separate dictionary within the allOf list, the preprocessor misses them, leaving them ineffective. Out-of-bounds trickle-voltage-millivolt values could silently pass dt_binding_check validation. > + > required: > - compatible > - mboxes -- Sashiko AI review · https://sashiko.dev/#/patchset/20260923131323.1099979-1-sander.speetjens@gmail.com?part=1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC 2026-09-23 13:13 ` [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens 2026-09-23 13:21 ` sashiko-bot @ 2026-09-23 16:37 ` Conor Dooley 2026-09-23 16:46 ` Sander Speetjens 1 sibling, 1 reply; 8+ messages in thread From: Conor Dooley @ 2026-09-23 16:37 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 [-- Attachment #1: Type: text/plain, Size: 2110 bytes --] On Wed, Sep 23, 2026 at 03:13:22PM +0200, Sander Speetjens wrote: > 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. > > Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com> > --- > 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 | 8 ++++++++ > 1 file changed, 8 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..9349fc8908a5 100644 > --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml > +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml > @@ -133,6 +133,13 @@ properties: > required: > - compatible > > + trickle-voltage-millivolt: > + allOf: > + - $ref: /schemas/rtc/rtc.yaml#/properties/trickle-voltage-millivolt > + - $ref: /schemas/types.yaml#/definitions/uint32 Is this actually needed? Shouldn't the type of uint32 come from the same source that the type in rtc.yaml does? Or is this missing in dt-schema? > + - minimum: 1300 > + maximum: 5000 > + > required: > - compatible > - mboxes > @@ -144,6 +151,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 > [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC 2026-09-23 16:37 ` Conor Dooley @ 2026-09-23 16:46 ` Sander Speetjens 2026-09-23 16:49 ` Conor Dooley 0 siblings, 1 reply; 8+ messages in thread From: Sander Speetjens @ 2026-09-23 16:46 UTC (permalink / raw) To: Conor Dooley Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli, Jonathan Bell, Stefan Wahren, linux-rtc, devicetree, linux-rpi-kernel, linux-arm-kernel > Is this actually needed? Shouldn't the type of uint32 come from the same > source that the type in rtc.yaml does? Or is this missing in dt-schema? The rtc.yaml does only provide the description not the type, I also expected the type to be there. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC 2026-09-23 16:46 ` Sander Speetjens @ 2026-09-23 16:49 ` Conor Dooley 0 siblings, 0 replies; 8+ messages in thread From: Conor Dooley @ 2026-09-23 16:49 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 [-- Attachment #1: Type: text/plain, Size: 477 bytes --] On Wed, Sep 23, 2026 at 06:46:00PM +0200, Sander Speetjens wrote: > > Is this actually needed? Shouldn't the type of uint32 come from the same > > source that the type in rtc.yaml does? Or is this missing in dt-schema? > > The rtc.yaml does only provide the description not the type, I also expected > the type to be there. > I think this should be dropped and the type added to property-units.yaml, I don't know where the one in rtc.yaml is getting a type from. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 2/2] rtc: Add Raspberry Pi 5 RTC driver 2026-09-23 13:13 [PATCH v4 0/2] Raspberry Pi 5 RTC driver Sander Speetjens 2026-09-23 13:13 ` [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens @ 2026-09-23 13:13 ` Sander Speetjens 2026-09-23 13:29 ` sashiko-bot 1 sibling, 1 reply; 8+ messages in thread From: Sander Speetjens @ 2026-09-23 13:13 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, Dom Cobley Upstreaming the downstream Raspberry Pi 5 RTC driver. This driver supports the custom DA9091, which is accessed through the firmware mailbox. Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com> Signed-off-by: Dom Cobley <popcornmix@gmail.com> Signed-off-by: Sander Speetjens <sander.speetjens@gmail.com> --- 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 | 25 ++++ drivers/rtc/Kconfig | 12 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-raspberrypi.c | 242 +++++++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+) create mode 100644 drivers/rtc/rtc-raspberrypi.c diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 0aa322e9a2e7..a35f00c6fb2c 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,27 @@ 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 is a Raspberry Pi 5, as the RTC is only present on that model. + const char *model = of_get_property(of_root, "model", NULL); + + if (!model || strncmp(model, "Raspberry Pi 5", 14) != 0) + 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 +327,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 +350,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..88006f83d7bc 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..f67ab156dc46 --- /dev/null +++ b/drivers/rtc/rtc-raspberrypi.c @@ -0,0 +1,244 @@ +// 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 RPI_FIRMWARE_GET_RTC_REG 0x00030087 +#define RPI_FIRMWARE_SET_RTC_REG 0x00038087 + +enum { + RTC_TIME, + RTC_ALARM, + RTC_ALARM_PENDING, + RTC_ALARM_ENABLE, + RTC_BBAT_CHG_VOLTS, + RTC_BBAT_CHG_VOLTS_MIN, + RTC_BBAT_CHG_VOLTS_MAX, + RTC_BBAT_VOLTS +}; + +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; +}; + +static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); + u32 data[2] = { RTC_TIME }; + int err; + + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + rtc_time64_to_tm(data[1], 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); + u32 data[2] = { RTC_TIME, 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); + u32 data[2] = { RTC_ALARM_ENABLE }; + s32 err = 0; + + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + *enabled = data[1] & 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); + u32 data[2] = { RTC_ALARM_ENABLE, 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); + u32 data[2] = { RTC_ALARM_PENDING, 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); + u32 data[2] = { RTC_ALARM }; + s32 err = 0; + + 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(data[1], &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); + u32 data[2] = { RTC_ALARM, rtc_tm_to_time64(&alarm->time) }; + int err; + + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG, + &data, sizeof(data)); + + if (err == 0) + 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); + u32 data[2] = { RTC_BBAT_CHG_VOLTS_MIN }; + + int err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + if (err == 0) + vrtc->bbat_vchg_min_millivolts = data[1] / 1000U; + + data[0] = RTC_BBAT_CHG_VOLTS_MAX; + data[1] = 0; + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + if (err == 0) + vrtc->bbat_vchg_max_millivolts = data[1] / 1000U; +} + +static int rpi_rtc_set_charge_voltage(struct device *dev) +{ + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev); + u32 data[2] = { RTC_BBAT_CHG_VOLTS, 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 -EINVAL; + } + + 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); + + return err; +} + +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); + + 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("GPL"); -- 2.55.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v4 2/2] rtc: Add Raspberry Pi 5 RTC driver 2026-09-23 13:13 ` [PATCH v4 2/2] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens @ 2026-09-23 13:29 ` sashiko-bot 0 siblings, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-09-23 13:29 UTC (permalink / raw) To: Sander Speetjens; +Cc: Alexandre Belloni, linux-rtc, robh, conor+dt, devicetree Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] rtc: dt binding violation by reading property from parent node - [Low] firmware: global device pointer race and leak on multiple probes -- commit f13bdcb7308fe3b9ecc514f418f2d57fa4e0247f Author: Sander Speetjens <sander.speetjens@gmail.com> Subject: rtc: Add Raspberry Pi 5 RTC driver This upstreaming patch introduces support for the downstream Raspberry Pi 5 RTC driver. The driver enables support for the custom DA9091 RTC, which is accessed through the firmware mailbox. > diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c > index 0aa322e9a2e73..a35f00c6fb2c1 100644 > --- a/drivers/firmware/raspberrypi.c > +++ b/drivers/firmware/raspberrypi.c [ ... ] > @@ -231,6 +232,27 @@ static void rpi_register_clk_driver(struct device *dev) [ ... ] > +static void rpi_register_rtc_driver(struct device *dev) > +{ [ ... ] > + rpi_rtc = platform_device_register_data(dev, "raspberrypi-rtc", > + -1, NULL, 0); > +} [Severity: Low] Does locklessly overwriting the global rpi_rtc pointer here risk a resource leak? If multiple probes occur (for example, via a custom Device Tree overlay), it appears the initially registered platform device could be permanently leaked since the pointer is overwritten without synchronization. [ ... ] > @@ -327,6 +350,8 @@ static void rpi_firmware_remove(struct platform_device *pdev) [ ... ] > platform_device_unregister(rpi_clk); > rpi_clk = NULL; > + platform_device_unregister(rpi_rtc); > + rpi_rtc = NULL; > > rpi_firmware_put(fw); > } [Severity: Low] If a secondary probe occurred and overwrote the global pointer as noted above, could this cross-unregister the wrong device during removal in rpi_firmware_remove(), leading to a double-unregister of NULL and a leaked device? > diff --git a/drivers/rtc/rtc-raspberrypi.c b/drivers/rtc/rtc-raspberrypi.c > new file mode 100644 > index 0000000000000..494b949374064 > --- /dev/null > +++ b/drivers/rtc/rtc-raspberrypi.c [ ... ] > +static int rpi_rtc_probe(struct platform_device *pdev) > +{ [ ... ] > + rpi_rtc_alarm_clear_pending(dev); > + > + vrtc->bbat_vchg_millivolts = 0; > + of_property_read_u32(dev->parent->of_node, "trickle-voltage-millivolt", > + &vrtc->bbat_vchg_millivolts); [Severity: Medium] Is it intentional to unconditionally read the trickle-voltage-millivolt property from the parent MFD firmware node instead of the driver's own RTC subnode? If this property is placed correctly in the raspberrypi,firmware-rtc subnode, it seems it would be silently ignored, causing trickle charging to be disabled and breaking standard Device Tree encapsulation. > + > + rpi_rtc_set_limits(dev); > + rpi_rtc_set_charge_voltage(dev); > + > + return devm_rtc_register_device(vrtc->rtc); > +} -- Sashiko AI review · https://sashiko.dev/#/patchset/20260923131323.1099979-1-sander.speetjens@gmail.com?part=2 ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-23 16:49 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-23 13:13 [PATCH v4 0/2] Raspberry Pi 5 RTC driver Sander Speetjens 2026-09-23 13:13 ` [PATCH v4 1/2] dt-bindings: rtc: Add property for Raspberry Pi 5 RTC Sander Speetjens 2026-09-23 13:21 ` sashiko-bot 2026-09-23 16:37 ` Conor Dooley 2026-09-23 16:46 ` Sander Speetjens 2026-09-23 16:49 ` Conor Dooley 2026-09-23 13:13 ` [PATCH v4 2/2] rtc: Add Raspberry Pi 5 RTC driver Sander Speetjens 2026-09-23 13:29 ` sashiko-bot
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).