mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/3] clocksource/drivers/timer-ti-dm: Add clocksource and clockevent support
@ 2025-12-16 20:03 Markus Schneider-Pargmann (TI.com)
  2025-12-16 20:03 ` [PATCH v2 1/3] clocksource/drivers/timer-ti-dm: Fix property name in comment Markus Schneider-Pargmann (TI.com)
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-12-16 20:03 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

Hi,

this series adds support for both clocksource and clockevent to the TI
Dual-Mode Timer driver. This can be used as a time source for low power
modes in which the CPUs are temporarily not running.

The driver looks for two always on timers in the DT to be used for
clocksource and clockevent. These are then handled as reserved and can
not be used for normal use.

This series is based on v6.19-rc1.

Best
Markus

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
Changes in v2:
- Rebased to v6.19-rc1
- Previous compile issues because of the __init section of
  sched_clock_register() was solved upstream by removing it from the
  __init section in 
  https://lore.kernel.org/r/20250602151853.1942521-8-daniel.lezcano@linaro.org
- Link to v1: https://lore.kernel.org/r/20250623-topic-ti-dm-clkevt-v6-16-v1-0-b00086761ee1@baylibre.com

---
Markus Schneider-Pargmann (TI.com) (3):
      clocksource/drivers/timer-ti-dm: Fix property name in comment
      clocksource/drivers/timer-ti-dm: Add clocksource support
      clocksource/drivers/timer-ti-dm: Add clockevent support

 drivers/clocksource/timer-ti-dm-systimer.c |   2 +-
 drivers/clocksource/timer-ti-dm.c          | 265 ++++++++++++++++++++++++++++-
 2 files changed, 265 insertions(+), 2 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20250623-topic-ti-dm-clkevt-v6-16-b5e6599b7c01

Best regards,
-- 
Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/3] clocksource/drivers/timer-ti-dm: Fix property name in comment
  2025-12-16 20:03 [PATCH v2 0/3] clocksource/drivers/timer-ti-dm: Add clocksource and clockevent support Markus Schneider-Pargmann (TI.com)
@ 2025-12-16 20:03 ` Markus Schneider-Pargmann (TI.com)
  2025-12-16 20:03 ` [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support Markus Schneider-Pargmann (TI.com)
  2025-12-16 20:03 ` [PATCH v2 3/3] clocksource/drivers/timer-ti-dm: Add clockevent support Markus Schneider-Pargmann (TI.com)
  2 siblings, 0 replies; 6+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-12-16 20:03 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

ti,always-on property doesn't exist. ti,timer-alwon is meant here. Fix
this minor bug in the comment.

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
 drivers/clocksource/timer-ti-dm-systimer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
index 985a6d08512b42f499b3e243eb69cc9674bc8e53..fb0a3cc23b5a35e2906a253d36ccef2baccca50a 100644
--- a/drivers/clocksource/timer-ti-dm-systimer.c
+++ b/drivers/clocksource/timer-ti-dm-systimer.c
@@ -226,7 +226,7 @@ static bool __init dmtimer_is_preferred(struct device_node *np)
  * Some omap3 boards with unreliable oscillator must not use the counter_32k
  * or dmtimer1 with 32 KiHz source. Additionally, the boards with unreliable
  * oscillator should really set counter_32k as disabled, and delete dmtimer1
- * ti,always-on property, but let's not count on it. For these quirky cases,
+ * ti,timer-alwon property, but let's not count on it. For these quirky cases,
  * we prefer using the always-on secure dmtimer12 with the internal 32 KiHz
  * clock as the clocksource, and any available dmtimer as clockevent.
  *

-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support
  2025-12-16 20:03 [PATCH v2 0/3] clocksource/drivers/timer-ti-dm: Add clocksource and clockevent support Markus Schneider-Pargmann (TI.com)
  2025-12-16 20:03 ` [PATCH v2 1/3] clocksource/drivers/timer-ti-dm: Fix property name in comment Markus Schneider-Pargmann (TI.com)
@ 2025-12-16 20:03 ` Markus Schneider-Pargmann (TI.com)
  2026-01-20 15:04   ` Daniel Lezcano
  2025-12-16 20:03 ` [PATCH v2 3/3] clocksource/drivers/timer-ti-dm: Add clockevent support Markus Schneider-Pargmann (TI.com)
  2 siblings, 1 reply; 6+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-12-16 20:03 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

Add support for using the TI Dual-Mode Timer as a clocksource. The
driver automatically picks the first timer that is marked as always-on
on with the "ti,timer-alwon" property to be the clocksource.

The timer can then be used for CPU independent time keeping.

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
 drivers/clocksource/timer-ti-dm.c | 137 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 136 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index 793e7cdcb1b16b58db3a81668e3c8144efc7baaf..9617bbe96209b91e58fabc2c275280703ce8af7c 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -20,6 +20,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/clocksource.h>
 #include <linux/cpu_pm.h>
 #include <linux/module.h>
 #include <linux/io.h>
@@ -27,8 +28,10 @@
 #include <linux/err.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/dmtimer-omap.h>
+#include <linux/sched_clock.h>
 
 #include <clocksource/timer-ti-dm.h>
 #include <linux/delay.h>
@@ -142,12 +145,23 @@ struct dmtimer {
 	struct notifier_block nb;
 	struct notifier_block fclk_nb;
 	unsigned long fclk_rate;
+
+	struct dmtimer_clocksource *clksrc;
 };
 
 static u32 omap_reserved_systimers;
 static LIST_HEAD(omap_timer_list);
 static DEFINE_SPINLOCK(dm_timer_lock);
 
+struct dmtimer_clocksource {
+	struct clocksource dev;
+	struct dmtimer *timer;
+	unsigned int loadval;
+};
+
+static resource_size_t omap_dm_timer_clocksource_base;
+static void __iomem *omap_dm_timer_sched_clock_counter;
+
 enum {
 	REQUEST_ANY = 0,
 	REQUEST_BY_ID,
@@ -1185,6 +1199,107 @@ static const struct dev_pm_ops omap_dm_timer_pm_ops = {
 
 static const struct of_device_id omap_timer_match[];
 
+static void omap_dm_timer_find_alwon(void)
+{
+	struct device_node *np;
+
+	for_each_matching_node(np, omap_timer_match) {
+		struct resource res;
+
+		if (!of_device_is_available(np))
+			continue;
+
+		if (!of_property_read_bool(np, "ti,timer-alwon"))
+			continue;
+
+		if (of_address_to_resource(np, 0, &res))
+			continue;
+
+		omap_dm_timer_clocksource_base = res.start;
+
+		of_node_put(np);
+		return;
+	}
+
+	omap_dm_timer_clocksource_base = -1;
+}
+
+static struct dmtimer_clocksource *omap_dm_timer_to_clocksource(struct clocksource *cs)
+{
+	return container_of(cs, struct dmtimer_clocksource, dev);
+}
+
+static u64 omap_dm_timer_read_cycles(struct clocksource *cs)
+{
+	struct dmtimer_clocksource *clksrc = omap_dm_timer_to_clocksource(cs);
+	struct dmtimer *timer = clksrc->timer;
+
+	return (u64)__omap_dm_timer_read_counter(timer);
+}
+
+static u64 notrace omap_dm_timer_read_sched_clock(void)
+{
+	/* Posted mode is not active here, so we can read directly */
+	return readl_relaxed(omap_dm_timer_sched_clock_counter);
+}
+
+static void omap_dm_timer_clocksource_suspend(struct clocksource *cs)
+{
+	struct dmtimer_clocksource *clksrc = omap_dm_timer_to_clocksource(cs);
+	struct dmtimer *timer = clksrc->timer;
+
+	clksrc->loadval = __omap_dm_timer_read_counter(timer);
+	__omap_dm_timer_stop(timer);
+}
+
+static void omap_dm_timer_clocksource_resume(struct clocksource *cs)
+{
+	struct dmtimer_clocksource *clksrc = omap_dm_timer_to_clocksource(cs);
+	struct dmtimer *timer = clksrc->timer;
+
+	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, clksrc->loadval);
+	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR);
+}
+
+static int omap_dm_timer_setup_clocksource(struct dmtimer *timer)
+{
+	struct device *dev = &timer->pdev->dev;
+	struct dmtimer_clocksource *clksrc;
+	int err;
+
+	__omap_dm_timer_init_regs(timer);
+
+	timer->reserved = 1;
+
+	clksrc = devm_kzalloc(dev, sizeof(*clksrc), GFP_KERNEL);
+	if (!clksrc)
+		return -ENOMEM;
+
+	clksrc->timer = timer;
+	timer->clksrc = clksrc;
+
+	clksrc->dev.name = "omap_dm_timer";
+	clksrc->dev.rating = 300;
+	clksrc->dev.read = omap_dm_timer_read_cycles;
+	clksrc->dev.mask = CLOCKSOURCE_MASK(32);
+	clksrc->dev.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+	clksrc->dev.suspend = omap_dm_timer_clocksource_suspend;
+	clksrc->dev.resume = omap_dm_timer_clocksource_resume;
+
+	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, 0);
+	dmtimer_write(timer, OMAP_TIMER_LOAD_REG, 0);
+	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR);
+
+	omap_dm_timer_sched_clock_counter = timer->func_base + _OMAP_TIMER_COUNTER_OFFSET;
+	sched_clock_register(omap_dm_timer_read_sched_clock, 32, timer->fclk_rate);
+
+	err = clocksource_register_hz(&clksrc->dev, timer->fclk_rate);
+	if (err)
+		return dev_err_probe(dev, err, "Could not register as clocksource\n");
+
+	return 0;
+}
+
 /**
  * omap_dm_timer_probe - probe function called for every registered device
  * @pdev:	pointer to current timer platform device
@@ -1198,8 +1313,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
 	struct dmtimer *timer;
 	struct device *dev = &pdev->dev;
 	const struct dmtimer_platform_data *pdata;
+	struct resource *res;
 	int ret;
 
+	if (!omap_dm_timer_clocksource_base)
+		omap_dm_timer_find_alwon();
+
 	pdata = of_device_get_match_data(dev);
 	if (!pdata)
 		pdata = dev_get_platdata(dev);
@@ -1272,6 +1391,16 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
 
 	timer->pdev = pdev;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (omap_dm_timer_clocksource_base && res &&
+	    res->start == omap_dm_timer_clocksource_base &&
+	    !IS_ERR_OR_NULL(timer->fclk)) {
+		ret = omap_dm_timer_setup_clocksource(timer);
+		if (ret)
+			return ret;
+	}
+
 	pm_runtime_enable(dev);
 
 	if (!timer->reserved) {
@@ -1299,6 +1428,9 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
 	return 0;
 
 err_disable:
+	if (timer->clksrc)
+		clocksource_unregister(&timer->clksrc->dev);
+
 	pm_runtime_disable(dev);
 	return ret;
 }
@@ -1313,10 +1445,13 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
  */
 static void omap_dm_timer_remove(struct platform_device *pdev)
 {
-	struct dmtimer *timer;
+	struct dmtimer *timer = dev_get_drvdata(&pdev->dev);
 	unsigned long flags;
 	int ret = -EINVAL;
 
+	if (timer->clksrc)
+		clocksource_unregister(&timer->clksrc->dev);
+
 	spin_lock_irqsave(&dm_timer_lock, flags);
 	list_for_each_entry(timer, &omap_timer_list, node)
 		if (!strcmp(dev_name(&timer->pdev->dev),

-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] clocksource/drivers/timer-ti-dm: Add clockevent support
  2025-12-16 20:03 [PATCH v2 0/3] clocksource/drivers/timer-ti-dm: Add clocksource and clockevent support Markus Schneider-Pargmann (TI.com)
  2025-12-16 20:03 ` [PATCH v2 1/3] clocksource/drivers/timer-ti-dm: Fix property name in comment Markus Schneider-Pargmann (TI.com)
  2025-12-16 20:03 ` [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support Markus Schneider-Pargmann (TI.com)
@ 2025-12-16 20:03 ` Markus Schneider-Pargmann (TI.com)
  2 siblings, 0 replies; 6+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-12-16 20:03 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

Add support for using the TI Dual-Mode Timer for clockevents. The second
always on device with the "ti,timer-alwon" property is selected to be
used for clockevents. The first one is used as clocksource.

This allows clockevents to be setup independently of the CPU.

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
 drivers/clocksource/timer-ti-dm.c | 138 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 133 insertions(+), 5 deletions(-)

diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index 9617bbe96209b91e58fabc2c275280703ce8af7c..fa2c7d19b9e53e3444a86f6b4f8baafd7e669887 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -21,8 +21,10 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <linux/cpu_pm.h>
 #include <linux/module.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -159,7 +161,14 @@ struct dmtimer_clocksource {
 	unsigned int loadval;
 };
 
+struct omap_dm_timer_clockevent {
+	struct clock_event_device dev;
+	struct dmtimer *timer;
+	u32 period;
+};
+
 static resource_size_t omap_dm_timer_clocksource_base;
+static resource_size_t omap_dm_timer_clockevent_base;
 static void __iomem *omap_dm_timer_sched_clock_counter;
 
 enum {
@@ -1203,6 +1212,9 @@ static void omap_dm_timer_find_alwon(void)
 {
 	struct device_node *np;
 
+	if (omap_dm_timer_clocksource_base && omap_dm_timer_clockevent_base)
+		return;
+
 	for_each_matching_node(np, omap_timer_match) {
 		struct resource res;
 
@@ -1215,13 +1227,22 @@ static void omap_dm_timer_find_alwon(void)
 		if (of_address_to_resource(np, 0, &res))
 			continue;
 
-		omap_dm_timer_clocksource_base = res.start;
+		if (!omap_dm_timer_clocksource_base) {
+			omap_dm_timer_clocksource_base = res.start;
+			continue;
+		}
 
-		of_node_put(np);
-		return;
+		if (res.start != omap_dm_timer_clocksource_base) {
+			omap_dm_timer_clockevent_base = res.start;
+
+			of_node_put(np);
+			return;
+		}
 	}
 
-	omap_dm_timer_clocksource_base = -1;
+	if (!omap_dm_timer_clocksource_base)
+		omap_dm_timer_clocksource_base = -1;
+	omap_dm_timer_clockevent_base = -1;
 }
 
 static struct dmtimer_clocksource *omap_dm_timer_to_clocksource(struct clocksource *cs)
@@ -1300,6 +1321,105 @@ static int omap_dm_timer_setup_clocksource(struct dmtimer *timer)
 	return 0;
 }
 
+static struct omap_dm_timer_clockevent *to_dm_timer_clockevent(struct clock_event_device *evt)
+{
+	return container_of(evt, struct omap_dm_timer_clockevent, dev);
+}
+
+static int omap_dm_timer_evt_set_next_event(unsigned long cycles,
+					    struct clock_event_device *evt)
+{
+	struct omap_dm_timer_clockevent *clkevt = to_dm_timer_clockevent(evt);
+	struct dmtimer *timer = clkevt->timer;
+
+	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, 0xffffffff - cycles);
+	dmtimer_write(timer, OMAP_TIMER_CTRL_REG, OMAP_TIMER_CTRL_ST);
+
+	return 0;
+}
+
+static int omap_dm_timer_evt_shutdown(struct clock_event_device *evt)
+{
+	struct omap_dm_timer_clockevent *clkevt = to_dm_timer_clockevent(evt);
+	struct dmtimer *timer = clkevt->timer;
+
+	__omap_dm_timer_stop(timer);
+
+	return 0;
+}
+
+static int omap_dm_timer_evt_set_periodic(struct clock_event_device *evt)
+{
+	struct omap_dm_timer_clockevent *clkevt = to_dm_timer_clockevent(evt);
+	struct dmtimer *timer = clkevt->timer;
+
+	omap_dm_timer_evt_shutdown(evt);
+
+	omap_dm_timer_set_load(&timer->cookie, clkevt->period);
+	dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, clkevt->period);
+	dmtimer_write(timer, OMAP_TIMER_CTRL_REG,
+		      OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST);
+
+	return 0;
+}
+
+static irqreturn_t omap_dm_timer_evt_interrupt(int irq, void *dev_id)
+{
+	struct omap_dm_timer_clockevent *clkevt = dev_id;
+	struct dmtimer *timer = clkevt->timer;
+
+	__omap_dm_timer_write_status(timer, OMAP_TIMER_INT_OVERFLOW);
+
+	clkevt->dev.event_handler(&clkevt->dev);
+
+	return IRQ_HANDLED;
+}
+
+static int omap_dm_timer_setup_clockevent(struct dmtimer *timer)
+{
+	struct device *dev = &timer->pdev->dev;
+	struct omap_dm_timer_clockevent *clkevt;
+	int ret;
+
+	clkevt = devm_kzalloc(dev, sizeof(*clkevt), GFP_KERNEL);
+	if (!clkevt)
+		return -ENOMEM;
+
+	timer->reserved = 1;
+	clkevt->timer = timer;
+
+	clkevt->dev.name = "omap_dm_timer";
+	clkevt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	clkevt->dev.rating = 300;
+	clkevt->dev.set_next_event = omap_dm_timer_evt_set_next_event;
+	clkevt->dev.set_state_shutdown = omap_dm_timer_evt_shutdown;
+	clkevt->dev.set_state_periodic = omap_dm_timer_evt_set_periodic;
+	clkevt->dev.set_state_oneshot = omap_dm_timer_evt_shutdown;
+	clkevt->dev.set_state_oneshot_stopped = omap_dm_timer_evt_shutdown;
+	clkevt->dev.tick_resume = omap_dm_timer_evt_shutdown;
+	clkevt->dev.cpumask = cpu_possible_mask;
+	clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(timer->fclk_rate, HZ);
+
+	__omap_dm_timer_init_regs(timer);
+	__omap_dm_timer_stop(timer);
+	__omap_dm_timer_enable_posted(timer);
+
+	ret = devm_request_irq(dev, timer->irq, omap_dm_timer_evt_interrupt,
+			       IRQF_TIMER, "omap_dm_timer_clockevent", clkevt);
+	if (ret) {
+		dev_err(dev, "Failed to request interrupt: %d\n", ret);
+		return ret;
+	}
+
+	__omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW);
+
+	clockevents_config_and_register(&clkevt->dev, timer->fclk_rate,
+					3,
+					0xffffffff);
+
+	return 0;
+}
+
 /**
  * omap_dm_timer_probe - probe function called for every registered device
  * @pdev:	pointer to current timer platform device
@@ -1316,7 +1436,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
 	struct resource *res;
 	int ret;
 
-	if (!omap_dm_timer_clocksource_base)
+	if (!omap_dm_timer_clocksource_base || !omap_dm_timer_clockevent_base)
 		omap_dm_timer_find_alwon();
 
 	pdata = of_device_get_match_data(dev);
@@ -1393,6 +1513,14 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
+	if (omap_dm_timer_clockevent_base && res &&
+	    res->start == omap_dm_timer_clockevent_base &&
+	    !IS_ERR_OR_NULL(timer->fclk)) {
+		ret = omap_dm_timer_setup_clockevent(timer);
+		if (ret)
+			return ret;
+	}
+
 	if (omap_dm_timer_clocksource_base && res &&
 	    res->start == omap_dm_timer_clocksource_base &&
 	    !IS_ERR_OR_NULL(timer->fclk)) {

-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support
  2025-12-16 20:03 ` [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support Markus Schneider-Pargmann (TI.com)
@ 2026-01-20 15:04   ` Daniel Lezcano
  2026-01-30 15:17     ` Markus Schneider-Pargmann
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Lezcano @ 2026-01-20 15:04 UTC (permalink / raw)
  To: Markus Schneider-Pargmann (TI.com), Thomas Gleixner
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-kernel

On 12/16/25 21:03, Markus Schneider-Pargmann (TI.com) wrote:
> Add support for using the TI Dual-Mode Timer as a clocksource. The
> driver automatically picks the first timer that is marked as always-on
> on with the "ti,timer-alwon" property to be the clocksource.
> 
> The timer can then be used for CPU independent time keeping.
> 
> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
> ---

[ ... ]

> +static int omap_dm_timer_setup_clocksource(struct dmtimer *timer)
> +{
> +	struct device *dev = &timer->pdev->dev;
> +	struct dmtimer_clocksource *clksrc;
> +	int err;
> +
> +	__omap_dm_timer_init_regs(timer);
> +
> +	timer->reserved = 1;
> +
> +	clksrc = devm_kzalloc(dev, sizeof(*clksrc), GFP_KERNEL);
> +	if (!clksrc)
> +		return -ENOMEM;

[ ... ]

> +	clksrc->timer = timer;
> +	timer->clksrc = clksrc;

This is a cyclic dependency which is not desired in general.

I suggest to have struct dmtimer_clocksource containing struct dmtimer timer

[ ... ]


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support
  2026-01-20 15:04   ` Daniel Lezcano
@ 2026-01-30 15:17     ` Markus Schneider-Pargmann
  0 siblings, 0 replies; 6+ messages in thread
From: Markus Schneider-Pargmann @ 2026-01-30 15:17 UTC (permalink / raw)
  To: Daniel Lezcano, Markus Schneider-Pargmann (TI.com), Thomas Gleixner
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1841 bytes --]

Hi Daniel,

On Tue Jan 20, 2026 at 4:04 PM CET, Daniel Lezcano wrote:
> On 12/16/25 21:03, Markus Schneider-Pargmann (TI.com) wrote:
>> Add support for using the TI Dual-Mode Timer as a clocksource. The
>> driver automatically picks the first timer that is marked as always-on
>> on with the "ti,timer-alwon" property to be the clocksource.
>> 
>> The timer can then be used for CPU independent time keeping.
>> 
>> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
>> ---
>
> [ ... ]
>
>> +static int omap_dm_timer_setup_clocksource(struct dmtimer *timer)
>> +{
>> +	struct device *dev = &timer->pdev->dev;
>> +	struct dmtimer_clocksource *clksrc;
>> +	int err;
>> +
>> +	__omap_dm_timer_init_regs(timer);
>> +
>> +	timer->reserved = 1;
>> +
>> +	clksrc = devm_kzalloc(dev, sizeof(*clksrc), GFP_KERNEL);
>> +	if (!clksrc)
>> +		return -ENOMEM;
>
> [ ... ]
>
>> +	clksrc->timer = timer;
>> +	timer->clksrc = clksrc;
>
> This is a cyclic dependency which is not desired in general.
>
> I suggest to have struct dmtimer_clocksource containing struct dmtimer timer

Thank you! Not many timers will probably have the clocksource part
setup, so I didn't like to embed struct dmtimer into
dmtimer_clocksource. I could have used different allocation routines in
probe to use either struct dmtimer_clocksource or struct dmtimer
directly depending on the use of clocksource, but I wasn't convinced by
that either.

For the code here I am only having the timer->clksrc pointer to
unregister the clocksource in cleanup. So I found

  devm_add_action_or_reset()

which can call the clocksource_unregister and eliminate the need for the
pointer. This is also already used in the timer-nxp-stm.c driver.

So if you are happy with that, I would prefer that solution.

Best
Markus

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 289 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-01-30 15:17 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-16 20:03 [PATCH v2 0/3] clocksource/drivers/timer-ti-dm: Add clocksource and clockevent support Markus Schneider-Pargmann (TI.com)
2025-12-16 20:03 ` [PATCH v2 1/3] clocksource/drivers/timer-ti-dm: Fix property name in comment Markus Schneider-Pargmann (TI.com)
2025-12-16 20:03 ` [PATCH v2 2/3] clocksource/drivers/timer-ti-dm: Add clocksource support Markus Schneider-Pargmann (TI.com)
2026-01-20 15:04   ` Daniel Lezcano
2026-01-30 15:17     ` Markus Schneider-Pargmann
2025-12-16 20:03 ` [PATCH v2 3/3] clocksource/drivers/timer-ti-dm: Add clockevent support Markus Schneider-Pargmann (TI.com)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®