diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-16 16:10:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-16 16:10:26 -0400 |
commit | a4ae54f90e0a7063799eb90852aa8648ccfbb791 (patch) | |
tree | 88fd7f7920c8849fed99c782ab1fc605da69a375 /drivers | |
parent | 3369d116934b70bd2755cdd8b2af9741d18a4047 (diff) | |
parent | 63ce2cc474ce962d936ae6dfaa6ae2354b1db5b2 (diff) |
Merge branch 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer code update from Thomas Gleixner:
- armada SoC clocksource overhaul with a trivial merge conflict
- Minor improvements to various SoC clocksource drivers
* 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
clocksource: armada-370-xp: Add detailed clock requirements in devicetree binding
clocksource: armada-370-xp: Get reference fixed-clock by name
clocksource: armada-370-xp: Replace WARN_ON with BUG_ON
clocksource: armada-370-xp: Fix device-tree binding
clocksource: armada-370-xp: Introduce new compatibles
clocksource: armada-370-xp: Use CLOCKSOURCE_OF_DECLARE
clocksource: armada-370-xp: Simplify TIMER_CTRL register access
clocksource: armada-370-xp: Use BIT()
ARM: timer-sp: Set dynamic irq affinity
ARM: nomadik: add dynamic irq flag to the timer
clocksource: sh_cmt: 32-bit control register support
clocksource: em_sti: Convert to devm_* managed helpers
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clocksource/em_sti.c | 49 | ||||
-rw-r--r-- | drivers/clocksource/nomadik-mtu.c | 3 | ||||
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 50 | ||||
-rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 131 |
4 files changed, 129 insertions, 104 deletions
diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 4329a29a5310..b9c81b7c3a3b 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c | |||
@@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev) | |||
315 | { | 315 | { |
316 | struct em_sti_priv *p; | 316 | struct em_sti_priv *p; |
317 | struct resource *res; | 317 | struct resource *res; |
318 | int irq, ret; | 318 | int irq; |
319 | 319 | ||
320 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 320 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); |
321 | if (p == NULL) { | 321 | if (p == NULL) { |
322 | dev_err(&pdev->dev, "failed to allocate driver data\n"); | 322 | dev_err(&pdev->dev, "failed to allocate driver data\n"); |
323 | ret = -ENOMEM; | 323 | return -ENOMEM; |
324 | goto err0; | ||
325 | } | 324 | } |
326 | 325 | ||
327 | p->pdev = pdev; | 326 | p->pdev = pdev; |
328 | platform_set_drvdata(pdev, p); | 327 | platform_set_drvdata(pdev, p); |
329 | 328 | ||
330 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
331 | if (!res) { | ||
332 | dev_err(&pdev->dev, "failed to get I/O memory\n"); | ||
333 | ret = -EINVAL; | ||
334 | goto err0; | ||
335 | } | ||
336 | |||
337 | irq = platform_get_irq(pdev, 0); | 329 | irq = platform_get_irq(pdev, 0); |
338 | if (irq < 0) { | 330 | if (irq < 0) { |
339 | dev_err(&pdev->dev, "failed to get irq\n"); | 331 | dev_err(&pdev->dev, "failed to get irq\n"); |
340 | ret = -EINVAL; | 332 | return -EINVAL; |
341 | goto err0; | ||
342 | } | 333 | } |
343 | 334 | ||
344 | /* map memory, let base point to the STI instance */ | 335 | /* map memory, let base point to the STI instance */ |
345 | p->base = ioremap_nocache(res->start, resource_size(res)); | 336 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
346 | if (p->base == NULL) { | 337 | p->base = devm_ioremap_resource(&pdev->dev, res); |
347 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); | 338 | if (IS_ERR(p->base)) |
348 | ret = -ENXIO; | 339 | return PTR_ERR(p->base); |
349 | goto err0; | ||
350 | } | ||
351 | 340 | ||
352 | /* get hold of clock */ | 341 | /* get hold of clock */ |
353 | p->clk = clk_get(&pdev->dev, "sclk"); | 342 | p->clk = devm_clk_get(&pdev->dev, "sclk"); |
354 | if (IS_ERR(p->clk)) { | 343 | if (IS_ERR(p->clk)) { |
355 | dev_err(&pdev->dev, "cannot get clock\n"); | 344 | dev_err(&pdev->dev, "cannot get clock\n"); |
356 | ret = PTR_ERR(p->clk); | 345 | return PTR_ERR(p->clk); |
357 | goto err1; | ||
358 | } | 346 | } |
359 | 347 | ||
360 | if (request_irq(irq, em_sti_interrupt, | 348 | if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, |
361 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, | 349 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, |
362 | dev_name(&pdev->dev), p)) { | 350 | dev_name(&pdev->dev), p)) { |
363 | dev_err(&pdev->dev, "failed to request low IRQ\n"); | 351 | dev_err(&pdev->dev, "failed to request low IRQ\n"); |
364 | ret = -ENOENT; | 352 | return -ENOENT; |
365 | goto err2; | ||
366 | } | 353 | } |
367 | 354 | ||
368 | raw_spin_lock_init(&p->lock); | 355 | raw_spin_lock_init(&p->lock); |
369 | em_sti_register_clockevent(p); | 356 | em_sti_register_clockevent(p); |
370 | em_sti_register_clocksource(p); | 357 | em_sti_register_clocksource(p); |
371 | return 0; | 358 | return 0; |
372 | |||
373 | err2: | ||
374 | clk_put(p->clk); | ||
375 | err1: | ||
376 | iounmap(p->base); | ||
377 | err0: | ||
378 | kfree(p); | ||
379 | return ret; | ||
380 | } | 359 | } |
381 | 360 | ||
382 | static int em_sti_remove(struct platform_device *pdev) | 361 | static int em_sti_remove(struct platform_device *pdev) |
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 7d2c2c56f73c..1b74bea12385 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c | |||
@@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) | |||
165 | 165 | ||
166 | static struct clock_event_device nmdk_clkevt = { | 166 | static struct clock_event_device nmdk_clkevt = { |
167 | .name = "mtu_1", | 167 | .name = "mtu_1", |
168 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | 168 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | |
169 | CLOCK_EVT_FEAT_DYNIRQ, | ||
169 | .rating = 200, | 170 | .rating = 200, |
170 | .set_mode = nmdk_clkevt_mode, | 171 | .set_mode = nmdk_clkevt_mode, |
171 | .set_next_event = nmdk_clkevt_next, | 172 | .set_next_event = nmdk_clkevt_next, |
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 08d0c418c94a..0965e9848b3d 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | struct sh_cmt_priv { | 38 | struct sh_cmt_priv { |
39 | void __iomem *mapbase; | 39 | void __iomem *mapbase; |
40 | void __iomem *mapbase_str; | ||
40 | struct clk *clk; | 41 | struct clk *clk; |
41 | unsigned long width; /* 16 or 32 bit version of hardware block */ | 42 | unsigned long width; /* 16 or 32 bit version of hardware block */ |
42 | unsigned long overflow_bit; | 43 | unsigned long overflow_bit; |
@@ -79,6 +80,12 @@ struct sh_cmt_priv { | |||
79 | * CMCSR 0xffca0060 16-bit | 80 | * CMCSR 0xffca0060 16-bit |
80 | * CMCNT 0xffca0064 32-bit | 81 | * CMCNT 0xffca0064 32-bit |
81 | * CMCOR 0xffca0068 32-bit | 82 | * CMCOR 0xffca0068 32-bit |
83 | * | ||
84 | * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: | ||
85 | * CMSTR 0xffca0500 32-bit | ||
86 | * CMCSR 0xffca0510 32-bit | ||
87 | * CMCNT 0xffca0514 32-bit | ||
88 | * CMCOR 0xffca0518 32-bit | ||
82 | */ | 89 | */ |
83 | 90 | ||
84 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) | 91 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) |
@@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, | |||
109 | 116 | ||
110 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) | 117 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) |
111 | { | 118 | { |
112 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 119 | return p->read_control(p->mapbase_str, 0); |
113 | |||
114 | return p->read_control(p->mapbase - cfg->channel_offset, 0); | ||
115 | } | 120 | } |
116 | 121 | ||
117 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) | 122 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) |
@@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) | |||
127 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, | 132 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, |
128 | unsigned long value) | 133 | unsigned long value) |
129 | { | 134 | { |
130 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 135 | p->write_control(p->mapbase_str, 0, value); |
131 | |||
132 | p->write_control(p->mapbase - cfg->channel_offset, 0, value); | ||
133 | } | 136 | } |
134 | 137 | ||
135 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, | 138 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, |
@@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, | |||
676 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | 679 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) |
677 | { | 680 | { |
678 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 681 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
679 | struct resource *res; | 682 | struct resource *res, *res2; |
680 | int irq, ret; | 683 | int irq, ret; |
681 | ret = -ENXIO; | 684 | ret = -ENXIO; |
682 | 685 | ||
@@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
694 | goto err0; | 697 | goto err0; |
695 | } | 698 | } |
696 | 699 | ||
700 | /* optional resource for the shared timer start/stop register */ | ||
701 | res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1); | ||
702 | |||
697 | irq = platform_get_irq(p->pdev, 0); | 703 | irq = platform_get_irq(p->pdev, 0); |
698 | if (irq < 0) { | 704 | if (irq < 0) { |
699 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 705 | dev_err(&p->pdev->dev, "failed to get irq\n"); |
@@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
707 | goto err0; | 713 | goto err0; |
708 | } | 714 | } |
709 | 715 | ||
716 | /* map second resource for CMSTR */ | ||
717 | p->mapbase_str = ioremap_nocache(res2 ? res2->start : | ||
718 | res->start - cfg->channel_offset, | ||
719 | res2 ? resource_size(res2) : 2); | ||
720 | if (p->mapbase_str == NULL) { | ||
721 | dev_err(&p->pdev->dev, "failed to remap I/O second memory\n"); | ||
722 | goto err1; | ||
723 | } | ||
724 | |||
710 | /* request irq using setup_irq() (too early for request_irq()) */ | 725 | /* request irq using setup_irq() (too early for request_irq()) */ |
711 | p->irqaction.name = dev_name(&p->pdev->dev); | 726 | p->irqaction.name = dev_name(&p->pdev->dev); |
712 | p->irqaction.handler = sh_cmt_interrupt; | 727 | p->irqaction.handler = sh_cmt_interrupt; |
@@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
719 | if (IS_ERR(p->clk)) { | 734 | if (IS_ERR(p->clk)) { |
720 | dev_err(&p->pdev->dev, "cannot get clock\n"); | 735 | dev_err(&p->pdev->dev, "cannot get clock\n"); |
721 | ret = PTR_ERR(p->clk); | 736 | ret = PTR_ERR(p->clk); |
722 | goto err1; | 737 | goto err2; |
723 | } | 738 | } |
724 | 739 | ||
725 | p->read_control = sh_cmt_read16; | 740 | if (res2 && (resource_size(res2) == 4)) { |
726 | p->write_control = sh_cmt_write16; | 741 | /* assume both CMSTR and CMCSR to be 32-bit */ |
742 | p->read_control = sh_cmt_read32; | ||
743 | p->write_control = sh_cmt_write32; | ||
744 | } else { | ||
745 | p->read_control = sh_cmt_read16; | ||
746 | p->write_control = sh_cmt_write16; | ||
747 | } | ||
727 | 748 | ||
728 | if (resource_size(res) == 6) { | 749 | if (resource_size(res) == 6) { |
729 | p->width = 16; | 750 | p->width = 16; |
@@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
752 | cfg->clocksource_rating); | 773 | cfg->clocksource_rating); |
753 | if (ret) { | 774 | if (ret) { |
754 | dev_err(&p->pdev->dev, "registration failed\n"); | 775 | dev_err(&p->pdev->dev, "registration failed\n"); |
755 | goto err2; | 776 | goto err3; |
756 | } | 777 | } |
757 | p->cs_enabled = false; | 778 | p->cs_enabled = false; |
758 | 779 | ||
759 | ret = setup_irq(irq, &p->irqaction); | 780 | ret = setup_irq(irq, &p->irqaction); |
760 | if (ret) { | 781 | if (ret) { |
761 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); | 782 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); |
762 | goto err2; | 783 | goto err3; |
763 | } | 784 | } |
764 | 785 | ||
765 | platform_set_drvdata(pdev, p); | 786 | platform_set_drvdata(pdev, p); |
766 | 787 | ||
767 | return 0; | 788 | return 0; |
768 | err2: | 789 | err3: |
769 | clk_put(p->clk); | 790 | clk_put(p->clk); |
770 | 791 | err2: | |
792 | iounmap(p->mapbase_str); | ||
771 | err1: | 793 | err1: |
772 | iounmap(p->mapbase); | 794 | iounmap(p->mapbase); |
773 | err0: | 795 | err0: |
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 847cab6f6e31..0198504ef6b0 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c | |||
@@ -13,6 +13,19 @@ | |||
13 | * | 13 | * |
14 | * Timer 0 is used as free-running clocksource, while timer 1 is | 14 | * Timer 0 is used as free-running clocksource, while timer 1 is |
15 | * used as clock_event_device. | 15 | * used as clock_event_device. |
16 | * | ||
17 | * --- | ||
18 | * Clocksource driver for Armada 370 and Armada XP SoC. | ||
19 | * This driver implements one compatible string for each SoC, given | ||
20 | * each has its own characteristics: | ||
21 | * | ||
22 | * * Armada 370 has no 25 MHz fixed timer. | ||
23 | * | ||
24 | * * Armada XP cannot work properly without such 25 MHz fixed timer as | ||
25 | * doing otherwise leads to using a clocksource whose frequency varies | ||
26 | * when doing cpufreq frequency changes. | ||
27 | * | ||
28 | * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt | ||
16 | */ | 29 | */ |
17 | 30 | ||
18 | #include <linux/init.h> | 31 | #include <linux/init.h> |
@@ -30,19 +43,18 @@ | |||
30 | #include <linux/module.h> | 43 | #include <linux/module.h> |
31 | #include <linux/sched_clock.h> | 44 | #include <linux/sched_clock.h> |
32 | #include <linux/percpu.h> | 45 | #include <linux/percpu.h> |
33 | #include <linux/time-armada-370-xp.h> | ||
34 | 46 | ||
35 | /* | 47 | /* |
36 | * Timer block registers. | 48 | * Timer block registers. |
37 | */ | 49 | */ |
38 | #define TIMER_CTRL_OFF 0x0000 | 50 | #define TIMER_CTRL_OFF 0x0000 |
39 | #define TIMER0_EN 0x0001 | 51 | #define TIMER0_EN BIT(0) |
40 | #define TIMER0_RELOAD_EN 0x0002 | 52 | #define TIMER0_RELOAD_EN BIT(1) |
41 | #define TIMER0_25MHZ 0x0800 | 53 | #define TIMER0_25MHZ BIT(11) |
42 | #define TIMER0_DIV(div) ((div) << 19) | 54 | #define TIMER0_DIV(div) ((div) << 19) |
43 | #define TIMER1_EN 0x0004 | 55 | #define TIMER1_EN BIT(2) |
44 | #define TIMER1_RELOAD_EN 0x0008 | 56 | #define TIMER1_RELOAD_EN BIT(3) |
45 | #define TIMER1_25MHZ 0x1000 | 57 | #define TIMER1_25MHZ BIT(12) |
46 | #define TIMER1_DIV(div) ((div) << 22) | 58 | #define TIMER1_DIV(div) ((div) << 22) |
47 | #define TIMER_EVENTS_STATUS 0x0004 | 59 | #define TIMER_EVENTS_STATUS 0x0004 |
48 | #define TIMER0_CLR_MASK (~0x1) | 60 | #define TIMER0_CLR_MASK (~0x1) |
@@ -72,6 +84,18 @@ static u32 ticks_per_jiffy; | |||
72 | 84 | ||
73 | static struct clock_event_device __percpu *armada_370_xp_evt; | 85 | static struct clock_event_device __percpu *armada_370_xp_evt; |
74 | 86 | ||
87 | static void timer_ctrl_clrset(u32 clr, u32 set) | ||
88 | { | ||
89 | writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
90 | timer_base + TIMER_CTRL_OFF); | ||
91 | } | ||
92 | |||
93 | static void local_timer_ctrl_clrset(u32 clr, u32 set) | ||
94 | { | ||
95 | writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
96 | local_base + TIMER_CTRL_OFF); | ||
97 | } | ||
98 | |||
75 | static u32 notrace armada_370_xp_read_sched_clock(void) | 99 | static u32 notrace armada_370_xp_read_sched_clock(void) |
76 | { | 100 | { |
77 | return ~readl(timer_base + TIMER0_VAL_OFF); | 101 | return ~readl(timer_base + TIMER0_VAL_OFF); |
@@ -84,7 +108,6 @@ static int | |||
84 | armada_370_xp_clkevt_next_event(unsigned long delta, | 108 | armada_370_xp_clkevt_next_event(unsigned long delta, |
85 | struct clock_event_device *dev) | 109 | struct clock_event_device *dev) |
86 | { | 110 | { |
87 | u32 u; | ||
88 | /* | 111 | /* |
89 | * Clear clockevent timer interrupt. | 112 | * Clear clockevent timer interrupt. |
90 | */ | 113 | */ |
@@ -98,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta, | |||
98 | /* | 121 | /* |
99 | * Enable the timer. | 122 | * Enable the timer. |
100 | */ | 123 | */ |
101 | u = readl(local_base + TIMER_CTRL_OFF); | 124 | local_timer_ctrl_clrset(TIMER0_RELOAD_EN, |
102 | u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | | 125 | TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); |
103 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | ||
104 | writel(u, local_base + TIMER_CTRL_OFF); | ||
105 | |||
106 | return 0; | 126 | return 0; |
107 | } | 127 | } |
108 | 128 | ||
@@ -110,8 +130,6 @@ static void | |||
110 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, | 130 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, |
111 | struct clock_event_device *dev) | 131 | struct clock_event_device *dev) |
112 | { | 132 | { |
113 | u32 u; | ||
114 | |||
115 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 133 | if (mode == CLOCK_EVT_MODE_PERIODIC) { |
116 | 134 | ||
117 | /* | 135 | /* |
@@ -123,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
123 | /* | 141 | /* |
124 | * Enable timer. | 142 | * Enable timer. |
125 | */ | 143 | */ |
126 | 144 | local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | | |
127 | u = readl(local_base + TIMER_CTRL_OFF); | 145 | TIMER0_EN | |
128 | 146 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
129 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
130 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), | ||
131 | local_base + TIMER_CTRL_OFF); | ||
132 | } else { | 147 | } else { |
133 | /* | 148 | /* |
134 | * Disable timer. | 149 | * Disable timer. |
135 | */ | 150 | */ |
136 | u = readl(local_base + TIMER_CTRL_OFF); | 151 | local_timer_ctrl_clrset(TIMER0_EN, 0); |
137 | writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF); | ||
138 | 152 | ||
139 | /* | 153 | /* |
140 | * ACK pending timer interrupt. | 154 | * ACK pending timer interrupt. |
@@ -163,14 +177,14 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | |||
163 | */ | 177 | */ |
164 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) | 178 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) |
165 | { | 179 | { |
166 | u32 u; | 180 | u32 clr = 0, set = 0; |
167 | int cpu = smp_processor_id(); | 181 | int cpu = smp_processor_id(); |
168 | 182 | ||
169 | u = readl(local_base + TIMER_CTRL_OFF); | ||
170 | if (timer25Mhz) | 183 | if (timer25Mhz) |
171 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 184 | set = TIMER0_25MHZ; |
172 | else | 185 | else |
173 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 186 | clr = TIMER0_25MHZ; |
187 | local_timer_ctrl_clrset(clr, set); | ||
174 | 188 | ||
175 | evt->name = "armada_370_xp_per_cpu_tick", | 189 | evt->name = "armada_370_xp_per_cpu_tick", |
176 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | 190 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
@@ -217,36 +231,21 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = { | |||
217 | .notifier_call = armada_370_xp_timer_cpu_notify, | 231 | .notifier_call = armada_370_xp_timer_cpu_notify, |
218 | }; | 232 | }; |
219 | 233 | ||
220 | void __init armada_370_xp_timer_init(void) | 234 | static void __init armada_370_xp_timer_common_init(struct device_node *np) |
221 | { | 235 | { |
222 | u32 u; | 236 | u32 clr = 0, set = 0; |
223 | struct device_node *np; | ||
224 | int res; | 237 | int res; |
225 | 238 | ||
226 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); | ||
227 | timer_base = of_iomap(np, 0); | 239 | timer_base = of_iomap(np, 0); |
228 | WARN_ON(!timer_base); | 240 | WARN_ON(!timer_base); |
229 | local_base = of_iomap(np, 1); | 241 | local_base = of_iomap(np, 1); |
230 | 242 | ||
231 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { | 243 | if (timer25Mhz) |
232 | /* The fixed 25MHz timer is available so let's use it */ | 244 | set = TIMER0_25MHZ; |
233 | u = readl(timer_base + TIMER_CTRL_OFF); | 245 | else |
234 | writel(u | TIMER0_25MHZ, | 246 | clr = TIMER0_25MHZ; |
235 | timer_base + TIMER_CTRL_OFF); | 247 | timer_ctrl_clrset(clr, set); |
236 | timer_clk = 25000000; | 248 | local_timer_ctrl_clrset(clr, set); |
237 | } else { | ||
238 | unsigned long rate = 0; | ||
239 | struct clk *clk = of_clk_get(np, 0); | ||
240 | WARN_ON(IS_ERR(clk)); | ||
241 | rate = clk_get_rate(clk); | ||
242 | |||
243 | u = readl(timer_base + TIMER_CTRL_OFF); | ||
244 | writel(u & ~(TIMER0_25MHZ), | ||
245 | timer_base + TIMER_CTRL_OFF); | ||
246 | |||
247 | timer_clk = rate / TIMER_DIVIDER; | ||
248 | timer25Mhz = false; | ||
249 | } | ||
250 | 249 | ||
251 | /* | 250 | /* |
252 | * We use timer 0 as clocksource, and private(local) timer 0 | 251 | * We use timer 0 as clocksource, and private(local) timer 0 |
@@ -268,10 +267,8 @@ void __init armada_370_xp_timer_init(void) | |||
268 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); | 267 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); |
269 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); | 268 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); |
270 | 269 | ||
271 | u = readl(timer_base + TIMER_CTRL_OFF); | 270 | timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN | |
272 | 271 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
273 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
274 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF); | ||
275 | 272 | ||
276 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, | 273 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, |
277 | "armada_370_xp_clocksource", | 274 | "armada_370_xp_clocksource", |
@@ -293,3 +290,29 @@ void __init armada_370_xp_timer_init(void) | |||
293 | if (!res) | 290 | if (!res) |
294 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); | 291 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); |
295 | } | 292 | } |
293 | |||
294 | static void __init armada_xp_timer_init(struct device_node *np) | ||
295 | { | ||
296 | struct clk *clk = of_clk_get_by_name(np, "fixed"); | ||
297 | |||
298 | /* The 25Mhz fixed clock is mandatory, and must always be available */ | ||
299 | BUG_ON(IS_ERR(clk)); | ||
300 | timer_clk = clk_get_rate(clk); | ||
301 | |||
302 | armada_370_xp_timer_common_init(np); | ||
303 | } | ||
304 | CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", | ||
305 | armada_xp_timer_init); | ||
306 | |||
307 | static void __init armada_370_timer_init(struct device_node *np) | ||
308 | { | ||
309 | struct clk *clk = of_clk_get(np, 0); | ||
310 | |||
311 | BUG_ON(IS_ERR(clk)); | ||
312 | timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; | ||
313 | timer25Mhz = false; | ||
314 | |||
315 | armada_370_xp_timer_common_init(np); | ||
316 | } | ||
317 | CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", | ||
318 | armada_370_timer_init); | ||