m41t80_sqw_register_clk() registers the square wave clock with clk_register() and publishes it with of_clk_add_provider(), but neither is ever torn down again: m41t80_remove() only unregisters the watchdog. The provider therefore keeps a reference to the device node and points at m41t80->sqw, which lives in devm-allocated driver data that is freed when the device is unbound. Resolving the clock afterwards dereferences freed memory. Switch to devm_clk_hw_register() and devm_of_clk_add_hw_provider() so that the clock and its provider are released with the device. The function no longer returns a struct clk pointer, so make it return an int instead. Fixes: 1373e77b4f10 ("rtc: m41t80: add clock provider support") Cc: stable@vger.kernel.org Assisted-by: DeepSeek-V4.1-Flash and OpenAI Codex Signed-off-by: Wentao Liang --- drivers/rtc/rtc-m41t80.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 1385cb43864b..c20b8734cb66 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -563,13 +563,12 @@ static const struct clk_ops m41t80_sqw_ops = { .set_rate = m41t80_sqw_set_rate, }; -static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) +static int m41t80_sqw_register_clk(struct m41t80_data *m41t80) { struct i2c_client *client = m41t80->client; struct device_node *node = client->dev.of_node; struct device_node *fixed_clock; struct clk_init_data init = {}; - struct clk *clk; int ret; fixed_clock = of_get_child_by_name(node, "clock"); @@ -580,17 +579,17 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) * registered automatically when being referenced. */ of_node_put(fixed_clock); - return NULL; + return 0; } /* First disable the clock */ ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (ret < 0) - return ERR_PTR(ret); + return ret; ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret & ~(M41T80_ALMON_SQWE)); if (ret < 0) - return ERR_PTR(ret); + return ret; init.name = "m41t80-sqw"; init.ops = &m41t80_sqw_ops; @@ -604,11 +603,12 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) of_property_read_string(node, "clock-output-names", &init.name); /* register the clock */ - clk = clk_register(&client->dev, &m41t80->sqw); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + ret = devm_clk_hw_register(&client->dev, &m41t80->sqw); + if (ret) + return ret; - return clk; + return devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, + &m41t80->sqw); } #endif -- 2.34.1