* [PATCH v1 2/7] drivers/clocksource/rockchip: Use the TIMER_PDEV_DECLARE() macro
2026-03-27 17:55 [PATCH v1 0/7] Timer driver module support Daniel Lezcano
@ 2026-03-27 17:55 ` Daniel Lezcano
2026-03-27 17:55 ` [PATCH v1 5/7] clocksource/drivers/rockchip: " Daniel Lezcano
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Daniel Lezcano @ 2026-03-27 17:55 UTC (permalink / raw)
To: daniel.lezcano, tglx, zhipeng.wang_1
Cc: shawnguo, jstultz, linux-kernel, Heiko Stuebner,
moderated list:ARM/Rockchip SoC support,
open list:ARM/Rockchip SoC support
The previous change introduce the TIMER_PDEV_DECLARE() marco which
allows to use the platform driver to initialize a timer driver with
the benefit of having the devres to rollback automatically in case of
error.
Use this macro and change the function to rely on the devm_ variants,
allowing to cleanup the code.
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
---
drivers/clocksource/timer-rockchip.c | 99 ++++++++++------------------
1 file changed, 34 insertions(+), 65 deletions(-)
diff --git a/drivers/clocksource/timer-rockchip.c b/drivers/clocksource/timer-rockchip.c
index 540a16667145..486bbffba464 100644
--- a/drivers/clocksource/timer-rockchip.c
+++ b/drivers/clocksource/timer-rockchip.c
@@ -124,18 +124,18 @@ static u64 notrace rk_timer_sched_read(void)
return ~readl_relaxed(rk_clksrc->base + TIMER_CURRENT_VALUE0);
}
-static int __init
-rk_timer_probe(struct rk_timer *timer, struct device_node *np)
+static int rk_timer_init(struct rk_timer *timer, struct device *dev)
{
+ struct device_node *np = dev->of_node;
struct clk *timer_clk;
struct clk *pclk;
- int ret = -EINVAL, irq;
+ int irq;
u32 ctrl_reg = TIMER_CONTROL_REG3288;
- timer->base = of_iomap(np, 0);
- if (!timer->base) {
+ timer->base = devm_of_iomap(dev, np, 0, NULL);
+ if (IS_ERR(timer->base)) {
pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
- return -ENXIO;
+ return PTR_ERR(timer->base);
}
if (of_device_is_compatible(np, "rockchip,rk3399-timer"))
@@ -143,31 +143,17 @@ rk_timer_probe(struct rk_timer *timer, struct device_node *np)
timer->ctrl = timer->base + ctrl_reg;
- pclk = of_clk_get_by_name(np, "pclk");
+ pclk = devm_clk_get_enabled(dev, "pclk");
if (IS_ERR(pclk)) {
- ret = PTR_ERR(pclk);
pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
- goto out_unmap;
- }
-
- ret = clk_prepare_enable(pclk);
- if (ret) {
- pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
- goto out_unmap;
+ return PTR_ERR(pclk);
}
timer->pclk = pclk;
- timer_clk = of_clk_get_by_name(np, "timer");
+ timer_clk = devm_clk_get_enabled(dev, "timer");
if (IS_ERR(timer_clk)) {
- ret = PTR_ERR(timer_clk);
pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
- goto out_timer_clk;
- }
-
- ret = clk_prepare_enable(timer_clk);
- if (ret) {
- pr_err("Failed to enable timer clock\n");
- goto out_timer_clk;
+ return PTR_ERR(timer_clk);
}
timer->clk = timer_clk;
@@ -175,47 +161,32 @@ rk_timer_probe(struct rk_timer *timer, struct device_node *np)
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
- ret = -EINVAL;
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
- goto out_irq;
+ return -EINVAL;
}
timer->irq = irq;
rk_timer_interrupt_clear(timer);
rk_timer_disable(timer);
- return 0;
-
-out_irq:
- clk_disable_unprepare(timer_clk);
-out_timer_clk:
- clk_disable_unprepare(pclk);
-out_unmap:
- iounmap(timer->base);
-
- return ret;
-}
-static void __init rk_timer_cleanup(struct rk_timer *timer)
-{
- clk_disable_unprepare(timer->clk);
- clk_disable_unprepare(timer->pclk);
- iounmap(timer->base);
+ return 0;
}
-static int __init rk_clkevt_init(struct device_node *np)
+static int rk_clkevt_init(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct clock_event_device *ce;
int ret = -EINVAL;
- rk_clkevt = kzalloc_obj(struct rk_clkevt);
+ rk_clkevt = devm_kzalloc(dev, sizeof(*rk_clkevt), GFP_KERNEL);
if (!rk_clkevt) {
ret = -ENOMEM;
goto out;
}
- ret = rk_timer_probe(&rk_clkevt->timer, np);
+ ret = rk_timer_init(&rk_clkevt->timer, dev);
if (ret)
- goto out_probe;
+ goto out;
ce = &rk_clkevt->ce;
ce->name = TIMER_NAME;
@@ -233,36 +204,33 @@ static int __init rk_clkevt_init(struct device_node *np)
if (ret) {
pr_err("Failed to initialize '%s': %d\n",
TIMER_NAME, ret);
- goto out_irq;
+ goto out;
}
clockevents_config_and_register(&rk_clkevt->ce,
rk_clkevt->timer.freq, 1, UINT_MAX);
return 0;
-out_irq:
- rk_timer_cleanup(&rk_clkevt->timer);
-out_probe:
- kfree(rk_clkevt);
out:
/* Leave rk_clkevt not NULL to prevent future init */
rk_clkevt = ERR_PTR(ret);
return ret;
}
-static int __init rk_clksrc_init(struct device_node *np)
+static int rk_clksrc_init(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
int ret = -EINVAL;
- rk_clksrc = kzalloc_obj(struct rk_timer);
+ rk_clksrc = devm_kzalloc(dev, sizeof(*rk_clksrc), GFP_KERNEL);
if (!rk_clksrc) {
ret = -ENOMEM;
goto out;
}
- ret = rk_timer_probe(rk_clksrc, np);
+ ret = rk_timer_init(rk_clksrc, dev);
if (ret)
- goto out_probe;
+ goto out;
rk_timer_update_counter(UINT_MAX, rk_clksrc);
rk_timer_enable(rk_clksrc, 0);
@@ -272,33 +240,34 @@ static int __init rk_clksrc_init(struct device_node *np)
clocksource_mmio_readl_down);
if (ret) {
pr_err("Failed to register clocksource\n");
- goto out_clocksource;
+ goto out;
}
sched_clock_register(rk_timer_sched_read, 32, rk_clksrc->freq);
return 0;
-out_clocksource:
- rk_timer_cleanup(rk_clksrc);
-out_probe:
- kfree(rk_clksrc);
out:
/* Leave rk_clksrc not NULL to prevent future init */
rk_clksrc = ERR_PTR(ret);
return ret;
}
-static int __init rk_timer_init(struct device_node *np)
+static int rk_timer_probe(struct platform_device *pdev)
{
if (!rk_clkevt)
- return rk_clkevt_init(np);
+ return rk_clkevt_init(pdev);
if (!rk_clksrc)
- return rk_clksrc_init(np);
+ return rk_clksrc_init(pdev);
pr_err("Too many timer definitions for '%s'\n", TIMER_NAME);
return -EINVAL;
}
-TIMER_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init);
-TIMER_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init);
+static const struct of_device_id rk_timer_match_table[] = {
+ { .compatible = "rockchip,rk3288-timer" },
+ { .compatible = "rockchip,rk3399-timer" },
+ { /* sentinel */ }
+};
+
+TIMER_PDEV_DECLARE(rk_timer, rk_timer_probe, NULL, rk_timer_match_table);
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v1 5/7] clocksource/drivers/rockchip: Use the TIMER_PDEV_DECLARE() macro
2026-03-27 17:55 [PATCH v1 0/7] Timer driver module support Daniel Lezcano
2026-03-27 17:55 ` [PATCH v1 2/7] drivers/clocksource/rockchip: Use the TIMER_PDEV_DECLARE() macro Daniel Lezcano
@ 2026-03-27 17:55 ` Daniel Lezcano
2026-03-27 17:55 ` [PATCH v1 6/7] clocksource/drivers/rockchip: Add rockchip timer module support Daniel Lezcano
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Daniel Lezcano @ 2026-03-27 17:55 UTC (permalink / raw)
To: daniel.lezcano, tglx, zhipeng.wang_1
Cc: shawnguo, jstultz, linux-kernel, Heiko Stuebner,
moderated list:ARM/Rockchip SoC support,
open list:ARM/Rockchip SoC support
The previous changes introduced the TIMER_PDEV_DECLARE() macro which
allows to use the platform driver to initialize a timer driver with
the benefit of having the devres to rollback automatically in case of
error.
Use this macro and change the function to rely on the devm_ variants,
allowing to cleanup the code.
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
---
drivers/clocksource/timer-rockchip.c | 99 ++++++++++------------------
1 file changed, 34 insertions(+), 65 deletions(-)
diff --git a/drivers/clocksource/timer-rockchip.c b/drivers/clocksource/timer-rockchip.c
index 540a16667145..486bbffba464 100644
--- a/drivers/clocksource/timer-rockchip.c
+++ b/drivers/clocksource/timer-rockchip.c
@@ -124,18 +124,18 @@ static u64 notrace rk_timer_sched_read(void)
return ~readl_relaxed(rk_clksrc->base + TIMER_CURRENT_VALUE0);
}
-static int __init
-rk_timer_probe(struct rk_timer *timer, struct device_node *np)
+static int rk_timer_init(struct rk_timer *timer, struct device *dev)
{
+ struct device_node *np = dev->of_node;
struct clk *timer_clk;
struct clk *pclk;
- int ret = -EINVAL, irq;
+ int irq;
u32 ctrl_reg = TIMER_CONTROL_REG3288;
- timer->base = of_iomap(np, 0);
- if (!timer->base) {
+ timer->base = devm_of_iomap(dev, np, 0, NULL);
+ if (IS_ERR(timer->base)) {
pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
- return -ENXIO;
+ return PTR_ERR(timer->base);
}
if (of_device_is_compatible(np, "rockchip,rk3399-timer"))
@@ -143,31 +143,17 @@ rk_timer_probe(struct rk_timer *timer, struct device_node *np)
timer->ctrl = timer->base + ctrl_reg;
- pclk = of_clk_get_by_name(np, "pclk");
+ pclk = devm_clk_get_enabled(dev, "pclk");
if (IS_ERR(pclk)) {
- ret = PTR_ERR(pclk);
pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
- goto out_unmap;
- }
-
- ret = clk_prepare_enable(pclk);
- if (ret) {
- pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
- goto out_unmap;
+ return PTR_ERR(pclk);
}
timer->pclk = pclk;
- timer_clk = of_clk_get_by_name(np, "timer");
+ timer_clk = devm_clk_get_enabled(dev, "timer");
if (IS_ERR(timer_clk)) {
- ret = PTR_ERR(timer_clk);
pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
- goto out_timer_clk;
- }
-
- ret = clk_prepare_enable(timer_clk);
- if (ret) {
- pr_err("Failed to enable timer clock\n");
- goto out_timer_clk;
+ return PTR_ERR(timer_clk);
}
timer->clk = timer_clk;
@@ -175,47 +161,32 @@ rk_timer_probe(struct rk_timer *timer, struct device_node *np)
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
- ret = -EINVAL;
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
- goto out_irq;
+ return -EINVAL;
}
timer->irq = irq;
rk_timer_interrupt_clear(timer);
rk_timer_disable(timer);
- return 0;
-
-out_irq:
- clk_disable_unprepare(timer_clk);
-out_timer_clk:
- clk_disable_unprepare(pclk);
-out_unmap:
- iounmap(timer->base);
-
- return ret;
-}
-static void __init rk_timer_cleanup(struct rk_timer *timer)
-{
- clk_disable_unprepare(timer->clk);
- clk_disable_unprepare(timer->pclk);
- iounmap(timer->base);
+ return 0;
}
-static int __init rk_clkevt_init(struct device_node *np)
+static int rk_clkevt_init(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct clock_event_device *ce;
int ret = -EINVAL;
- rk_clkevt = kzalloc_obj(struct rk_clkevt);
+ rk_clkevt = devm_kzalloc(dev, sizeof(*rk_clkevt), GFP_KERNEL);
if (!rk_clkevt) {
ret = -ENOMEM;
goto out;
}
- ret = rk_timer_probe(&rk_clkevt->timer, np);
+ ret = rk_timer_init(&rk_clkevt->timer, dev);
if (ret)
- goto out_probe;
+ goto out;
ce = &rk_clkevt->ce;
ce->name = TIMER_NAME;
@@ -233,36 +204,33 @@ static int __init rk_clkevt_init(struct device_node *np)
if (ret) {
pr_err("Failed to initialize '%s': %d\n",
TIMER_NAME, ret);
- goto out_irq;
+ goto out;
}
clockevents_config_and_register(&rk_clkevt->ce,
rk_clkevt->timer.freq, 1, UINT_MAX);
return 0;
-out_irq:
- rk_timer_cleanup(&rk_clkevt->timer);
-out_probe:
- kfree(rk_clkevt);
out:
/* Leave rk_clkevt not NULL to prevent future init */
rk_clkevt = ERR_PTR(ret);
return ret;
}
-static int __init rk_clksrc_init(struct device_node *np)
+static int rk_clksrc_init(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
int ret = -EINVAL;
- rk_clksrc = kzalloc_obj(struct rk_timer);
+ rk_clksrc = devm_kzalloc(dev, sizeof(*rk_clksrc), GFP_KERNEL);
if (!rk_clksrc) {
ret = -ENOMEM;
goto out;
}
- ret = rk_timer_probe(rk_clksrc, np);
+ ret = rk_timer_init(rk_clksrc, dev);
if (ret)
- goto out_probe;
+ goto out;
rk_timer_update_counter(UINT_MAX, rk_clksrc);
rk_timer_enable(rk_clksrc, 0);
@@ -272,33 +240,34 @@ static int __init rk_clksrc_init(struct device_node *np)
clocksource_mmio_readl_down);
if (ret) {
pr_err("Failed to register clocksource\n");
- goto out_clocksource;
+ goto out;
}
sched_clock_register(rk_timer_sched_read, 32, rk_clksrc->freq);
return 0;
-out_clocksource:
- rk_timer_cleanup(rk_clksrc);
-out_probe:
- kfree(rk_clksrc);
out:
/* Leave rk_clksrc not NULL to prevent future init */
rk_clksrc = ERR_PTR(ret);
return ret;
}
-static int __init rk_timer_init(struct device_node *np)
+static int rk_timer_probe(struct platform_device *pdev)
{
if (!rk_clkevt)
- return rk_clkevt_init(np);
+ return rk_clkevt_init(pdev);
if (!rk_clksrc)
- return rk_clksrc_init(np);
+ return rk_clksrc_init(pdev);
pr_err("Too many timer definitions for '%s'\n", TIMER_NAME);
return -EINVAL;
}
-TIMER_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init);
-TIMER_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init);
+static const struct of_device_id rk_timer_match_table[] = {
+ { .compatible = "rockchip,rk3288-timer" },
+ { .compatible = "rockchip,rk3399-timer" },
+ { /* sentinel */ }
+};
+
+TIMER_PDEV_DECLARE(rk_timer, rk_timer_probe, NULL, rk_timer_match_table);
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v1 6/7] clocksource/drivers/rockchip: Add rockchip timer module support
2026-03-27 17:55 [PATCH v1 0/7] Timer driver module support Daniel Lezcano
2026-03-27 17:55 ` [PATCH v1 2/7] drivers/clocksource/rockchip: Use the TIMER_PDEV_DECLARE() macro Daniel Lezcano
2026-03-27 17:55 ` [PATCH v1 5/7] clocksource/drivers/rockchip: " Daniel Lezcano
@ 2026-03-27 17:55 ` Daniel Lezcano
2026-03-27 17:55 ` [PATCH v1 7/7] clocksource/drivers/mediatek: Convert to " Daniel Lezcano
2026-03-27 18:02 ` [PATCH v1 0/7] Timer driver " Daniel Lezcano
4 siblings, 0 replies; 6+ messages in thread
From: Daniel Lezcano @ 2026-03-27 17:55 UTC (permalink / raw)
To: daniel.lezcano, tglx, zhipeng.wang_1
Cc: shawnguo, jstultz, linux-kernel, Heiko Stuebner,
moderated list:ARM/Rockchip SoC support,
open list:ARM/Rockchip SoC support
Now the TIMER_PDEV_DECLARE() allows the driver to be compiled as a
module. Add the MODULE_DESCRIPTION and the MODULE_LICENSE left for the
one converting the driver as a module.
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
---
drivers/clocksource/timer-rockchip.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/clocksource/timer-rockchip.c b/drivers/clocksource/timer-rockchip.c
index 486bbffba464..61433b295882 100644
--- a/drivers/clocksource/timer-rockchip.c
+++ b/drivers/clocksource/timer-rockchip.c
@@ -271,3 +271,5 @@ static const struct of_device_id rk_timer_match_table[] = {
};
TIMER_PDEV_DECLARE(rk_timer, rk_timer_probe, NULL, rk_timer_match_table);
+MODULE_DESCRIPTION("Rockchip timer driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v1 7/7] clocksource/drivers/mediatek: Convert to module support
2026-03-27 17:55 [PATCH v1 0/7] Timer driver module support Daniel Lezcano
` (2 preceding siblings ...)
2026-03-27 17:55 ` [PATCH v1 6/7] clocksource/drivers/rockchip: Add rockchip timer module support Daniel Lezcano
@ 2026-03-27 17:55 ` Daniel Lezcano
2026-03-27 18:02 ` [PATCH v1 0/7] Timer driver " Daniel Lezcano
4 siblings, 0 replies; 6+ messages in thread
From: Daniel Lezcano @ 2026-03-27 17:55 UTC (permalink / raw)
To: daniel.lezcano, tglx, zhipeng.wang_1
Cc: shawnguo, jstultz, linux-kernel, Matthias Brugger,
AngeloGioacchino Del Regno,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support
Now the TIMER_PDEV_DECLARE() allows the driver to be compiled as a
module. Add the MODULE_DESCRIPTION and the MODULE_LICENSE left for the
one converting the driver as a module.
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
---
drivers/clocksource/timer-mediatek.c | 29 ++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/clocksource/timer-mediatek.c b/drivers/clocksource/timer-mediatek.c
index 7bcb4a3f26fb..f5de5f397730 100644
--- a/drivers/clocksource/timer-mediatek.c
+++ b/drivers/clocksource/timer-mediatek.c
@@ -215,8 +215,7 @@ static irqreturn_t mtk_gpt_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void
-__init mtk_gpt_setup(struct timer_of *to, u8 timer, u8 option)
+static void mtk_gpt_setup(struct timer_of *to, u8 timer, u8 option)
{
writel(GPT_CTRL_CLEAR | GPT_CTRL_DISABLE,
timer_of_base(to) + GPT_CTRL_REG(timer));
@@ -281,7 +280,7 @@ static struct timer_of to = {
},
};
-static int __init mtk_syst_init(struct device_node *node)
+static int mtk_syst_init(struct device_node *node)
{
int ret;
@@ -302,7 +301,7 @@ static int __init mtk_syst_init(struct device_node *node)
return 0;
}
-static int __init mtk_gpt_init(struct device_node *node)
+static int mtk_gpt_init(struct device_node *node)
{
int ret;
@@ -337,5 +336,23 @@ static int __init mtk_gpt_init(struct device_node *node)
return 0;
}
-TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_gpt_init);
-TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer", mtk_syst_init);
+
+static int mtk_timer_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int (*probe_func)(struct device_node *node);
+
+ probe_func = of_device_get_match_data(&pdev->dev);
+
+ return probe_func(np);
+}
+
+static const struct of_device_id mtk_timer_match_table[] = {
+ { .compatible = "mediatek,mt6577-timer", .data = mtk_gpt_init },
+ { .compatible = "mediatek,mt6765-timer", .data = mtk_syst_init },
+ { /* sentinel */ }
+};
+
+TIMER_PDEV_DECLARE(mtk_timer, mtk_timer_probe, NULL, mtk_timer_match_table);
+MODULE_DESCRIPTION("Mediatek timer driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH v1 0/7] Timer driver module support
2026-03-27 17:55 [PATCH v1 0/7] Timer driver module support Daniel Lezcano
` (3 preceding siblings ...)
2026-03-27 17:55 ` [PATCH v1 7/7] clocksource/drivers/mediatek: Convert to " Daniel Lezcano
@ 2026-03-27 18:02 ` Daniel Lezcano
4 siblings, 0 replies; 6+ messages in thread
From: Daniel Lezcano @ 2026-03-27 18:02 UTC (permalink / raw)
To: Daniel Lezcano, tglx, zhipeng.wang_1
Cc: shawnguo, jstultz, linux-kernel, Matthias Brugger,
AngeloGioacchino Del Regno,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support
On 3/27/26 18:55, Daniel Lezcano wrote:
> Converting the timer driver modules requires a particular care
> because, depending on the platform, that may be not supported.
Sorry this series has been corrupted with a previous draft series.
I'll resend.
^ permalink raw reply [flat|nested] 6+ messages in thread