Merge branch 'clockevents/3.14' of git://git.linaro.org/people/daniel.lezcano/linux...
authorIngo Molnar <mingo@kernel.org>
Sun, 12 Jan 2014 16:28:52 +0000 (17:28 +0100)
committerIngo Molnar <mingo@kernel.org>
Tue, 14 Jan 2014 13:33:29 +0000 (14:33 +0100)
Pull clocksource/clockevent updates from Daniel Lezcano:

  * Axel Lin removed an unused structure defining the ids for the
    bcm kona driver.

  * Ezequiel Garcia enabled the timer divider only when the 25MHz
    timer is not used for the armada 370 XP.

  * Jingoo Han removed a pointless platform data initialization for
    the sh_mtu and sh_mtu2.

  * Laurent Pinchart added the clk_prepare/clk_unprepare for sh_cmt.

  * Linus Walleij added a useful warning in clk_of when no clocks
    are found while the old behavior was to silently hang at boot time.

  * Maxime Ripard added the high speed timer drivers for the
    Allwinner SoCs (A10, A13, A20). He increased the rating, shared the
    irq across all available cpus and fixed the clockevent's irq
    initialization for the sun4i.

  * Michael Opdenacker removed the usage of the IRQF_DISABLED for the
    all the timers driver located in drivers/clocksource.

  * Stephen Boyd switched to sched_clock_register for the
    arm_global_timer, cadence_ttc, sun4i and orion timers.

Conflicts:
drivers/clocksource/clksrc-of.c

Signed-off-by: Ingo Molnar <mingo@kernel.org>
24 files changed:
Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt [new file with mode: 0644]
arch/arm/boot/dts/sun5i-a10s.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/mach-sunxi/Kconfig
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/arm_global_timer.c
drivers/clocksource/bcm_kona_timer.c
drivers/clocksource/cadence_ttc_timer.c
drivers/clocksource/clksrc-of.c
drivers/clocksource/cs5535-clockevt.c
drivers/clocksource/dw_apb_timer.c
drivers/clocksource/nomadik-mtu.c
drivers/clocksource/samsung_pwm_timer.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/clocksource/sun4i_timer.c
drivers/clocksource/tegra20_timer.c
drivers/clocksource/time-armada-370-xp.c
drivers/clocksource/time-orion.c
drivers/clocksource/timer-sun5i.c [new file with mode: 0644]
drivers/clocksource/vt8500_timer.c

diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt
new file mode 100644 (file)
index 0000000..7c26154
--- /dev/null
@@ -0,0 +1,22 @@
+Allwinner SoCs High Speed Timer Controller
+
+Required properties:
+
+- compatible : should be "allwinner,sun5i-a13-hstimer" or
+               "allwinner,sun7i-a20-hstimer"
+- reg : Specifies base physical address and size of the registers.
+- interrupts : The interrupts of these timers (2 for the sun5i IP, 4 for the sun7i
+               one)
+- clocks: phandle to the source clock (usually the AHB clock)
+
+Example:
+
+timer@01c60000 {
+       compatible = "allwinner,sun7i-a20-hstimer";
+       reg = <0x01c60000 0x1000>;
+       interrupts = <0 51 1>,
+                    <0 52 1>,
+                    <0 53 1>,
+                    <0 54 1>;
+       clocks = <&ahb1_gates 19>;
+};
index 52476742a1043e5e9703505d03b2eae5d2a5bc1a..e674c94c720698e70b8a934ef5e560e4b725d0c7 100644 (file)
                        clock-frequency = <100000>;
                        status = "disabled";
                };
+
+               timer@01c60000 {
+                       compatible = "allwinner,sun5i-a13-hstimer";
+                       reg = <0x01c60000 0x1000>;
+                       interrupts = <82>, <83>;
+                       clocks = <&ahb_gates 28>;
+               };
        };
 };
index ce8ef2a45be098a35521db6d7fa41c472cd0b85a..1ccd75d37f49d4aeffbec39f0c518d62fd49b22b 100644 (file)
                        clock-frequency = <100000>;
                        status = "disabled";
                };
+
+               timer@01c60000 {
+                       compatible = "allwinner,sun5i-a13-hstimer";
+                       reg = <0x01c60000 0x1000>;
+                       interrupts = <82>, <83>;
+                       clocks = <&ahb_gates 28>;
+               };
        };
 };
index 367611a0730bc0c978d24737fa611c1beeac7417..0135039eff96440dfc5b2fbb7813a137bd51122d 100644 (file)
                        status = "disabled";
                };
 
+               hstimer@01c60000 {
+                       compatible = "allwinner,sun7i-a20-hstimer";
+                       reg = <0x01c60000 0x1000>;
+                       interrupts = <0 81 1>,
+                                    <0 82 1>,
+                                    <0 83 1>,
+                                    <0 84 1>;
+                       clocks = <&ahb_gates 28>;
+               };
+
                gic: interrupt-controller@01c81000 {
                        compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
                        reg = <0x01c81000 0x1000>,
index c9e72c89066ad78b4f7890dcdcebc28157835e79..bce0d4277f71974ceefb7a2f9ec8e31ef75ceb9d 100644 (file)
@@ -12,3 +12,4 @@ config ARCH_SUNXI
        select PINCTRL_SUNXI
        select SPARSE_IRQ
        select SUN4I_TIMER
+       select SUN5I_HSTIMER
index 634c4d6dd45a489384d4c6b293e56f0fcc2ba331..cd6950fd8caf063417f6717db581f39d69100ed4 100644 (file)
@@ -37,6 +37,10 @@ config SUN4I_TIMER
        select CLKSRC_MMIO
        bool
 
+config SUN5I_HSTIMER
+       select CLKSRC_MMIO
+       bool
+
 config VT8500_TIMER
        bool
 
index 33621efb91489693a2e1f7cd2e5b3ab423fc8939..358358d87b6dc4f9fe384c9af5158ab43ab3f8ea 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_MOXART)     += moxart_timer.o
 obj-$(CONFIG_ARCH_MXS)         += mxs_timer.o
 obj-$(CONFIG_ARCH_PRIMA2)      += timer-prima2.o
 obj-$(CONFIG_SUN4I_TIMER)      += sun4i_timer.o
+obj-$(CONFIG_SUN5I_HSTIMER)    += timer-sun5i.o
 obj-$(CONFIG_ARCH_TEGRA)       += tegra20_timer.o
 obj-$(CONFIG_VT8500_TIMER)     += vt8500_timer.o
 obj-$(CONFIG_ARCH_NSPIRE)      += zevio-timer.o
index c639b1a9e99686fb3333fc825c65d84e3cc52bae..0fc31d029e52224391dc419d96e9391aa38fff77 100644 (file)
@@ -202,7 +202,7 @@ static struct clocksource gt_clocksource = {
 };
 
 #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
-static u32 notrace gt_sched_clock_read(void)
+static u64 notrace gt_sched_clock_read(void)
 {
        return gt_counter_read();
 }
@@ -217,7 +217,7 @@ static void __init gt_clocksource_init(void)
        writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
 
 #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
-       setup_sched_clock(gt_sched_clock_read, 32, gt_clk_rate);
+       sched_clock_register(gt_sched_clock_read, 64, gt_clk_rate);
 #endif
        clocksource_register_hz(&gt_clocksource, gt_clk_rate);
 }
index 0d7d8c3ed6b2221cded6206291cbb4fa6c453efc..5176e761166b27a0730341ec1688ae5157cf6258 100644 (file)
@@ -98,12 +98,6 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw)
        return;
 }
 
-static const struct of_device_id bcm_timer_ids[] __initconst = {
-       {.compatible = "brcm,kona-timer"},
-       {.compatible = "bcm,kona-timer"}, /* deprecated name */
-       {},
-};
-
 static void __init kona_timers_init(struct device_node *node)
 {
        u32 freq;
index b2bb3a4bc20542199cb4a3eab1bc71bcc5022dfa..8c7382bf260c05762a82353921a9f13ea4038d5d 100644 (file)
@@ -158,7 +158,7 @@ static cycle_t __ttc_clocksource_read(struct clocksource *cs)
                                TTC_COUNT_VAL_OFFSET);
 }
 
-static u32 notrace ttc_sched_clock_read(void)
+static u64 notrace ttc_sched_clock_read(void)
 {
        return __raw_readl(ttc_sched_clock_val_reg);
 }
@@ -306,7 +306,7 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base)
        }
 
        ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET;
-       setup_sched_clock(ttc_sched_clock_read, 16,
+       sched_clock_register(ttc_sched_clock_read, 16,
                        clk_get_rate(ttccs->ttc.clk) / PRESCALE);
 }
 
@@ -388,8 +388,7 @@ static void __init ttc_setup_clockevent(struct clk *clk,
        __raw_writel(0x1,  ttcce->ttc.base_addr + TTC_IER_OFFSET);
 
        err = request_irq(irq, ttc_clock_event_interrupt,
-                         IRQF_DISABLED | IRQF_TIMER,
-                         ttcce->ce.name, ttcce);
+                         IRQF_TIMER, ttcce->ce.name, ttcce);
        if (WARN_ON(err)) {
                kfree(ttcce);
                return;
index b9ddd9e3a2f599e2cc7424c1eac18d4280b2f850..ae2e4278c42abd75358279e937e991497097a2e6 100644 (file)
@@ -28,6 +28,7 @@ void __init clocksource_of_init(void)
        struct device_node *np;
        const struct of_device_id *match;
        clocksource_of_init_fn init_func;
+       unsigned clocksources = 0;
 
        for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
                if (!of_device_is_available(np))
@@ -35,5 +36,8 @@ void __init clocksource_of_init(void)
 
                init_func = match->data;
                init_func(np);
+               clocksources++;
        }
+       if (!clocksources)
+               pr_crit("%s: no matching clocksources found\n", __func__);
 }
index ea210482dd2099af6ce35e31bd234fcc18a4d970..db21052908984c96aa86950d976784a078043374 100644 (file)
@@ -131,7 +131,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
 
 static struct irqaction mfgptirq  = {
        .handler = mfgpt_tick,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED,
        .name = DRV_NAME,
 };
 
index e54ca1062d8e6a827a998591b0b5d58dc59eee76..f3656a6b0382c9982563e0abe84054e98a67dc98 100644 (file)
@@ -243,8 +243,7 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
        dw_ced->irqaction.dev_id        = &dw_ced->ced;
        dw_ced->irqaction.irq           = irq;
        dw_ced->irqaction.flags         = IRQF_TIMER | IRQF_IRQPOLL |
-                                         IRQF_NOBALANCING |
-                                         IRQF_DISABLED;
+                                         IRQF_NOBALANCING;
 
        dw_ced->eoi = apbt_eoi;
        err = setup_irq(irq, &dw_ced->irqaction);
index ed7b73b508e096bb06a3e87a1843aa813f835430..152a3f3875eeab3223a68f4cddc509e5b378a515 100644 (file)
@@ -187,7 +187,7 @@ static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction nmdk_timer_irq = {
        .name           = "Nomadik Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .handler        = nmdk_timer_interrupt,
        .dev_id         = &nmdk_clkevt,
 };
index 85082e8d305298ac41b085df4bdb493aca95c682..5645cfc90c415ecd6108291304610e683579962f 100644 (file)
@@ -264,7 +264,7 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
 
 static struct irqaction samsung_clock_event_irq = {
        .name           = "samsung_time_irq",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = samsung_clock_event_isr,
        .dev_id         = &time_event_device,
 };
index 0965e9848b3d1893df4511f4ed70e1d39ffcbc96..0b1836a6c53975aade352b7f56b815d6c7ce1cb5 100644 (file)
@@ -634,12 +634,18 @@ static int sh_cmt_clock_event_next(unsigned long delta,
 
 static void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
 {
-       pm_genpd_syscore_poweroff(&ced_to_sh_cmt(ced)->pdev->dev);
+       struct sh_cmt_priv *p = ced_to_sh_cmt(ced);
+
+       pm_genpd_syscore_poweroff(&p->pdev->dev);
+       clk_unprepare(p->clk);
 }
 
 static void sh_cmt_clock_event_resume(struct clock_event_device *ced)
 {
-       pm_genpd_syscore_poweron(&ced_to_sh_cmt(ced)->pdev->dev);
+       struct sh_cmt_priv *p = ced_to_sh_cmt(ced);
+
+       clk_prepare(p->clk);
+       pm_genpd_syscore_poweron(&p->pdev->dev);
 }
 
 static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
@@ -726,8 +732,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        p->irqaction.name = dev_name(&p->pdev->dev);
        p->irqaction.handler = sh_cmt_interrupt;
        p->irqaction.dev_id = p;
-       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
-                            IRQF_IRQPOLL  | IRQF_NOBALANCING;
+       p->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING;
 
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "cmt_fck");
@@ -737,6 +742,10 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
                goto err2;
        }
 
+       ret = clk_prepare(p->clk);
+       if (ret < 0)
+               goto err3;
+
        if (res2 && (resource_size(res2) == 4)) {
                /* assume both CMSTR and CMCSR to be 32-bit */
                p->read_control = sh_cmt_read32;
@@ -773,19 +782,21 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
                              cfg->clocksource_rating);
        if (ret) {
                dev_err(&p->pdev->dev, "registration failed\n");
-               goto err3;
+               goto err4;
        }
        p->cs_enabled = false;
 
        ret = setup_irq(irq, &p->irqaction);
        if (ret) {
                dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
-               goto err3;
+               goto err4;
        }
 
        platform_set_drvdata(pdev, p);
 
        return 0;
+err4:
+       clk_unprepare(p->clk);
 err3:
        clk_put(p->clk);
 err2:
index 3cf12834681e8335fa7f49dd032eb3cb57ad128a..e30d76e0a6fae9dab56a1b4ebc15ee769dd2fca3 100644 (file)
@@ -302,8 +302,7 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
        p->irqaction.handler = sh_mtu2_interrupt;
        p->irqaction.dev_id = p;
        p->irqaction.irq = irq;
-       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
-                            IRQF_IRQPOLL  | IRQF_NOBALANCING;
+       p->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING;
 
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
@@ -358,7 +357,6 @@ static int sh_mtu2_probe(struct platform_device *pdev)
        ret = sh_mtu2_setup(p, pdev);
        if (ret) {
                kfree(p);
-               platform_set_drvdata(pdev, NULL);
                pm_runtime_idle(&pdev->dev);
                return ret;
        }
index 63557cda0a7d599e352c402f2db23b348481e365..ecd7b60bfdfa9d2323053f325b8f9d4447988c9d 100644 (file)
@@ -462,8 +462,7 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
        p->irqaction.handler = sh_tmu_interrupt;
        p->irqaction.dev_id = p;
        p->irqaction.irq = irq;
-       p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
-                            IRQF_IRQPOLL  | IRQF_NOBALANCING;
+       p->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING;
 
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "tmu_fck");
@@ -523,7 +522,6 @@ static int sh_tmu_probe(struct platform_device *pdev)
        ret = sh_tmu_setup(p, pdev);
        if (ret) {
                kfree(p);
-               platform_set_drvdata(pdev, NULL);
                pm_runtime_idle(&pdev->dev);
                return ret;
        }
index a4f6119aafd814efe2839f416bbe8fe99bc41554..bf497afba9ad1ef0c6c8ec57c9761f05d3acf799 100644 (file)
@@ -114,7 +114,7 @@ static int sun4i_clkevt_next_event(unsigned long evt,
 
 static struct clock_event_device sun4i_clockevent = {
        .name = "sun4i_tick",
-       .rating = 300,
+       .rating = 350,
        .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .set_mode = sun4i_clkevt_mode,
        .set_next_event = sun4i_clkevt_next_event,
@@ -138,7 +138,7 @@ static struct irqaction sun4i_timer_irq = {
        .dev_id = &sun4i_clockevent,
 };
 
-static u32 sun4i_timer_sched_read(void)
+static u64 notrace sun4i_timer_sched_read(void)
 {
        return ~readl(timer_base + TIMER_CNTVAL_REG(1));
 }
@@ -170,9 +170,9 @@ static void __init sun4i_timer_init(struct device_node *node)
               TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
               timer_base + TIMER_CTL_REG(1));
 
-       setup_sched_clock(sun4i_timer_sched_read, 32, rate);
+       sched_clock_register(sun4i_timer_sched_read, 32, rate);
        clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name,
-                             rate, 300, 32, clocksource_mmio_readl_down);
+                             rate, 350, 32, clocksource_mmio_readl_down);
 
        ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
@@ -190,7 +190,8 @@ static void __init sun4i_timer_init(struct device_node *node)
        val = readl(timer_base + TIMER_IRQ_EN_REG);
        writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
 
-       sun4i_clockevent.cpumask = cpumask_of(0);
+       sun4i_clockevent.cpumask = cpu_possible_mask;
+       sun4i_clockevent.irq = irq;
 
        clockevents_config_and_register(&sun4i_clockevent, rate,
                                        TIMER_SYNC_TICKS, 0xffffffff);
index 642849256d82ecabd0d7222d8a960280ce3f3e24..d1869f02051cbe9ccfa23a0dec7d235d5d0d3f02 100644 (file)
@@ -149,7 +149,7 @@ static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction tegra_timer_irq = {
        .name           = "timer0",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH,
+       .flags          = IRQF_TIMER | IRQF_TRIGGER_HIGH,
        .handler        = tegra_timer_interrupt,
        .dev_id         = &tegra_clockevent,
 };
index 4e7f6802e840ba9379eb42d733801526d173e89e..ee8691b89944e3fcbc3dbf7eeaadf00ec38ffd93 100644 (file)
@@ -76,6 +76,7 @@
 static void __iomem *timer_base, *local_base;
 static unsigned int timer_clk;
 static bool timer25Mhz = true;
+static u32 enable_mask;
 
 /*
  * Number of timer ticks per jiffy.
@@ -121,8 +122,7 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
        /*
         * Enable the timer.
         */
-       local_timer_ctrl_clrset(TIMER0_RELOAD_EN,
-                               TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT));
+       local_timer_ctrl_clrset(TIMER0_RELOAD_EN, enable_mask);
        return 0;
 }
 
@@ -141,9 +141,7 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
                /*
                 * Enable timer.
                 */
-               local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN |
-                                          TIMER0_EN |
-                                          TIMER0_DIV(TIMER_DIVIDER_SHIFT));
+               local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
        } else {
                /*
                 * Disable timer.
@@ -240,10 +238,13 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
        WARN_ON(!timer_base);
        local_base = of_iomap(np, 1);
 
-       if (timer25Mhz)
+       if (timer25Mhz) {
                set = TIMER0_25MHZ;             
-       else
+               enable_mask = TIMER0_EN;
+       } else {
                clr = TIMER0_25MHZ;
+               enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT);
+       }
        timer_ctrl_clrset(clr, set);
        local_timer_ctrl_clrset(clr, set);
 
@@ -262,8 +263,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
        writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
        writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
 
-       timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
-                            TIMER0_DIV(TIMER_DIVIDER_SHIFT));
+       timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
 
        /*
         * Set scale and timer for sched_clock.
index 9c7f018a67cad356a2e85cfe270117a6404ac547..20066222f3f29cdb052c2282eafd1dadb8519d8b 100644 (file)
@@ -53,7 +53,7 @@ EXPORT_SYMBOL(orion_timer_ctrl_clrset);
 /*
  * Free-running clocksource handling.
  */
-static u32 notrace orion_read_sched_clock(void)
+static u64 notrace orion_read_sched_clock(void)
 {
        return ~readl(timer_base + TIMER0_VAL);
 }
@@ -135,7 +135,7 @@ static void __init orion_timer_init(struct device_node *np)
        clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
                              clk_get_rate(clk), 300, 32,
                              clocksource_mmio_readl_down);
-       setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk));
+       sched_clock_register(orion_read_sched_clock, 32, clk_get_rate(clk));
 
        /* setup timer1 as clockevent timer */
        if (setup_irq(irq, &orion_clkevt_irq))
diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c
new file mode 100644 (file)
index 0000000..bddc522
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Allwinner SoCs hstimer driver.
+ *
+ * Copyright (C) 2013 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/sched_clock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TIMER_IRQ_EN_REG               0x00
+#define TIMER_IRQ_EN(val)                      BIT(val)
+#define TIMER_IRQ_ST_REG               0x04
+#define TIMER_CTL_REG(val)             (0x20 * (val) + 0x10)
+#define TIMER_CTL_ENABLE                       BIT(0)
+#define TIMER_CTL_RELOAD                       BIT(1)
+#define TIMER_CTL_CLK_PRES(val)                        (((val) & 0x7) << 4)
+#define TIMER_CTL_ONESHOT                      BIT(7)
+#define TIMER_INTVAL_LO_REG(val)       (0x20 * (val) + 0x14)
+#define TIMER_INTVAL_HI_REG(val)       (0x20 * (val) + 0x18)
+#define TIMER_CNTVAL_LO_REG(val)       (0x20 * (val) + 0x1c)
+#define TIMER_CNTVAL_HI_REG(val)       (0x20 * (val) + 0x20)
+
+#define TIMER_SYNC_TICKS       3
+
+static void __iomem *timer_base;
+static u32 ticks_per_jiffy;
+
+/*
+ * When we disable a timer, we need to wait at least for 2 cycles of
+ * the timer source clock. We will use for that the clocksource timer
+ * that is already setup and runs at the same frequency than the other
+ * timers, and we never will be disabled.
+ */
+static void sun5i_clkevt_sync(void)
+{
+       u32 old = readl(timer_base + TIMER_CNTVAL_LO_REG(1));
+
+       while ((old - readl(timer_base + TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS)
+               cpu_relax();
+}
+
+static void sun5i_clkevt_time_stop(u8 timer)
+{
+       u32 val = readl(timer_base + TIMER_CTL_REG(timer));
+       writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer));
+
+       sun5i_clkevt_sync();
+}
+
+static void sun5i_clkevt_time_setup(u8 timer, u32 delay)
+{
+       writel(delay, timer_base + TIMER_INTVAL_LO_REG(timer));
+}
+
+static void sun5i_clkevt_time_start(u8 timer, bool periodic)
+{
+       u32 val = readl(timer_base + TIMER_CTL_REG(timer));
+
+       if (periodic)
+               val &= ~TIMER_CTL_ONESHOT;
+       else
+               val |= TIMER_CTL_ONESHOT;
+
+       writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
+              timer_base + TIMER_CTL_REG(timer));
+}
+
+static void sun5i_clkevt_mode(enum clock_event_mode mode,
+                             struct clock_event_device *clk)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               sun5i_clkevt_time_stop(0);
+               sun5i_clkevt_time_setup(0, ticks_per_jiffy);
+               sun5i_clkevt_time_start(0, true);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               sun5i_clkevt_time_stop(0);
+               sun5i_clkevt_time_start(0, false);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               sun5i_clkevt_time_stop(0);
+               break;
+       }
+}
+
+static int sun5i_clkevt_next_event(unsigned long evt,
+                                  struct clock_event_device *unused)
+{
+       sun5i_clkevt_time_stop(0);
+       sun5i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS);
+       sun5i_clkevt_time_start(0, false);
+
+       return 0;
+}
+
+static struct clock_event_device sun5i_clockevent = {
+       .name = "sun5i_tick",
+       .rating = 340,
+       .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode = sun5i_clkevt_mode,
+       .set_next_event = sun5i_clkevt_next_event,
+};
+
+
+static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = (struct clock_event_device *)dev_id;
+
+       writel(0x1, timer_base + TIMER_IRQ_ST_REG);
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction sun5i_timer_irq = {
+       .name = "sun5i_timer0",
+       .flags = IRQF_TIMER | IRQF_IRQPOLL,
+       .handler = sun5i_timer_interrupt,
+       .dev_id = &sun5i_clockevent,
+};
+
+static u32 sun5i_timer_sched_read(void)
+{
+       return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1));
+}
+
+static void __init sun5i_timer_init(struct device_node *node)
+{
+       unsigned long rate;
+       struct clk *clk;
+       int ret, irq;
+       u32 val;
+
+       timer_base = of_iomap(node, 0);
+       if (!timer_base)
+               panic("Can't map registers");
+
+       irq = irq_of_parse_and_map(node, 0);
+       if (irq <= 0)
+               panic("Can't parse IRQ");
+
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk))
+               panic("Can't get timer clock");
+       clk_prepare_enable(clk);
+       rate = clk_get_rate(clk);
+
+       writel(~0, timer_base + TIMER_INTVAL_LO_REG(1));
+       writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
+              timer_base + TIMER_CTL_REG(1));
+
+       setup_sched_clock(sun5i_timer_sched_read, 32, rate);
+       clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name,
+                             rate, 340, 32, clocksource_mmio_readl_down);
+
+       ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
+
+       ret = setup_irq(irq, &sun5i_timer_irq);
+       if (ret)
+               pr_warn("failed to setup irq %d\n", irq);
+
+       /* Enable timer0 interrupt */
+       val = readl(timer_base + TIMER_IRQ_EN_REG);
+       writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
+
+       sun5i_clockevent.cpumask = cpu_possible_mask;
+       sun5i_clockevent.irq = irq;
+
+       clockevents_config_and_register(&sun5i_clockevent, rate,
+                                       TIMER_SYNC_TICKS, 0xffffffff);
+}
+CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
+                      sun5i_timer_init);
+CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
+                      sun5i_timer_init);
index ad3c0e83a77956431541315108b093f2ca282b52..1098ed3b9b89f2663fbf8a989017d0a7621a9504 100644 (file)
@@ -124,7 +124,7 @@ static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq = {
        .name    = "vt8500_timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags   = IRQF_TIMER | IRQF_IRQPOLL,
        .handler = vt8500_timer_interrupt,
        .dev_id  = &clockevent,
 };