[PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout
From: A. Sverdlin
Date: Fri Aug 28 2026 - 12:50:22 EST
From: Alexander Sverdlin <alexander.sverdlin@xxxxxxxxxxx>
pcf85063_clkout_register_clk() registered the OF clock provider with the
deprecated of_clk_add_provider() and never removed it, so the provider
kept pointing at freed data after unbind, leading to a use-after-free the
next time the device-tree clock was resolved.
Switch to devm_clk_hw_register() and devm_of_clk_add_hw_provider(): both
the clock and its OF provider are managed resources now, and the provider
is torn down before the clock on unbind.
Register the clock on the parent i2c device instead of the rtc device.
devm_of_clk_add_hw_provider() must use the parent, which owns the
of_node, and the clkout_hw it points at lives in the driver data
allocated on the parent. Tying both to the parent releases them together
on unbind, before the driver data is freed, and keeps their teardown
ordering guaranteed by a single devres list. Registering the clock on the
rtc device instead could defer its unregistration past unbind (e.g. while
a /dev/rtcN fd is open), after clkout_hw has already been freed.
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@xxxxxxxxxxx>
---
Changelog:
v3:
- new patch (pre-exising issue found by Sashiko)
drivers/rtc/rtc-pcf85063.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 8cb9ffc73f6d9..ac9ab1c376c0b 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -495,12 +495,13 @@ static const struct clk_ops pcf85063_clkout_ops = {
.set_rate = pcf85063_clkout_set_rate,
};
-static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
+static int pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
{
- struct clk *clk;
+ struct device *dev = pcf85063->rtc->dev.parent;
struct clk_init_data init = {};
- struct device_node *node = pcf85063->rtc->dev.parent->of_node;
+ struct device_node *node = dev->of_node;
struct device_node *fixed_clock;
+ int ret;
fixed_clock = of_get_child_by_name(node, "clock");
if (fixed_clock) {
@@ -510,7 +511,7 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
* registered automatically when being referenced.
*/
of_node_put(fixed_clock);
- return NULL;
+ return 0;
}
init.name = "pcf85063-clkout";
@@ -524,12 +525,12 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */
- clk = devm_clk_register(&pcf85063->rtc->dev, &pcf85063->clkout_hw);
-
- if (!IS_ERR(clk))
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ ret = devm_clk_hw_register(dev, &pcf85063->clkout_hw);
+ if (ret)
+ return ret;
- return clk;
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &pcf85063->clkout_hw);
}
#endif
--
2.55.0