clocksource: timer-keystone: Add platform probe support to existing code
authorKeerthy <j-keerthy@ti.com>
Wed, 7 Nov 2018 05:55:06 +0000 (11:25 +0530)
committerTero Kristo <t-kristo@ti.com>
Wed, 7 Nov 2018 07:51:00 +0000 (09:51 +0200)
This patch fixes the case for k2g where in clocks are not
available at the time of keystone_timer_init function call.
K2HK/K2L/K2E devices are left untouched and the old way of
keystone_timer_init is preserved since it is init order sensitive.

On top of the existing code a platform driver is introduced so that
if clock is not yet ready probe can be deferred. This enables hres
timers for k2g.

Signed-off-by: Keerthy <j-keerthy@ti.com>
drivers/clocksource/timer-keystone.c

index f5b2eda30bf336f79fd0b9553b7b6f1ef44f8dd4..dc61be6a466bb982beed82fe94740c252d96a5ca 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/platform_device.h>
 
 #define TIMER_NAME                     "timer-keystone"
 
  * @base: timer memory base address
  * @hz_period: cycles per HZ period
  * @event_dev: event device based on timer
+ * @registered: Flag to keep a track of registration status
  */
 static struct keystone_timer {
        void __iomem *base;
        unsigned long hz_period;
        struct clock_event_device event_dev;
+       bool registered;
 } timer;
 
 static inline u32 keystone_timer_readl(unsigned long rg)
@@ -144,13 +147,14 @@ static int keystone_set_periodic(struct clock_event_device *evt)
        return 0;
 }
 
-static int __init keystone_timer_init(struct device_node *np)
+static int keystone_timer_init(struct device_node *np)
 {
        struct clock_event_device *event_dev = &timer.event_dev;
        unsigned long rate;
        struct clk *clk;
        int irq, error;
 
+       timer.registered = false;
        irq  = irq_of_parse_and_map(np, 0);
        if (!irq) {
                pr_err("%s: failed to map interrupts\n", __func__);
@@ -219,6 +223,7 @@ static int __init keystone_timer_init(struct device_node *np)
        clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX);
 
        pr_info("keystone timer clock @%lu Hz\n", rate);
+       timer.registered = true;
        return 0;
 err:
        clk_put(clk);
@@ -228,3 +233,44 @@ err:
 
 TIMER_OF_DECLARE(keystone_timer, "ti,keystone-timer",
                           keystone_timer_init);
+
+static const struct of_device_id keystone_clocksource_of_match[] = {
+       {.compatible = "ti,keystone-timer", },
+       {},
+};
+
+static int keystone_clocksource_probe(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       if (timer.registered)
+               return 0;
+
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               if (PTR_ERR(clk) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get clock\n");
+               return PTR_ERR(clk);
+       }
+
+       clk_put(clk);
+       keystone_timer_init(pdev->dev.of_node);
+       if (!timer.registered)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct platform_driver keystone_clocksource_driver = {
+       .probe          = keystone_clocksource_probe,
+       .driver         = {
+               .name   = "keystone_clocksource",
+               .of_match_table = keystone_clocksource_of_match,
+       },
+};
+
+static int __init keystone_clocksource_init_driver(void)
+{
+       return platform_driver_register(&keystone_clocksource_driver);
+}
+device_initcall(keystone_clocksource_init_driver);