diff options
author | Daniel Lezcano <daniel.lezcano@linaro.org> | 2017-06-06 17:07:51 -0400 |
---|---|---|
committer | Daniel Lezcano <daniel.lezcano@linaro.org> | 2017-06-26 12:32:04 -0400 |
commit | 239751edad27d4fae964fb1f4ca1fedd742c8365 (patch) | |
tree | 53ade1523c701cb8cd3233f6a12320e774cc6474 | |
parent | 22ece4e3df6335e691207de1198a609e761b8640 (diff) |
clocksource/drivers/sun4i: Switch to the timer-of common init
Previously a framework to factor out the drivers init function has been
merged.
Use this common framework in this driver, we get:
Before:
text data bss dec hex filename
1787 384 12 2183 887 drivers/clocksource/sun4i_timer.o
After:
text data bss dec hex filename
1407 512 0 1919 77f drivers/clocksource/sun4i_timer.o
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Tested-by: Chen-Yu Tsai <wens@csie.org>
-rw-r--r-- | drivers/clocksource/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clocksource/sun4i_timer.c | 171 |
2 files changed, 78 insertions, 94 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4be163bca8a8..88818a43d6e9 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -108,6 +108,7 @@ config SUN4I_TIMER | |||
108 | depends on GENERIC_CLOCKEVENTS | 108 | depends on GENERIC_CLOCKEVENTS |
109 | depends on HAS_IOMEM | 109 | depends on HAS_IOMEM |
110 | select CLKSRC_MMIO | 110 | select CLKSRC_MMIO |
111 | select TIMER_OF | ||
111 | help | 112 | help |
112 | Enables support for the Sun4i timer. | 113 | Enables support for the Sun4i timer. |
113 | 114 | ||
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 3e4bc64ff176..6e0180aaf784 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <linux/of_address.h> | 24 | #include <linux/of_address.h> |
25 | #include <linux/of_irq.h> | 25 | #include <linux/of_irq.h> |
26 | 26 | ||
27 | #include "timer-of.h" | ||
28 | |||
27 | #define TIMER_IRQ_EN_REG 0x00 | 29 | #define TIMER_IRQ_EN_REG 0x00 |
28 | #define TIMER_IRQ_EN(val) BIT(val) | 30 | #define TIMER_IRQ_EN(val) BIT(val) |
29 | #define TIMER_IRQ_ST_REG 0x04 | 31 | #define TIMER_IRQ_ST_REG 0x04 |
@@ -39,38 +41,37 @@ | |||
39 | 41 | ||
40 | #define TIMER_SYNC_TICKS 3 | 42 | #define TIMER_SYNC_TICKS 3 |
41 | 43 | ||
42 | static void __iomem *timer_base; | ||
43 | static u32 ticks_per_jiffy; | ||
44 | |||
45 | /* | 44 | /* |
46 | * When we disable a timer, we need to wait at least for 2 cycles of | 45 | * When we disable a timer, we need to wait at least for 2 cycles of |
47 | * the timer source clock. We will use for that the clocksource timer | 46 | * the timer source clock. We will use for that the clocksource timer |
48 | * that is already setup and runs at the same frequency than the other | 47 | * that is already setup and runs at the same frequency than the other |
49 | * timers, and we never will be disabled. | 48 | * timers, and we never will be disabled. |
50 | */ | 49 | */ |
51 | static void sun4i_clkevt_sync(void) | 50 | static void sun4i_clkevt_sync(void __iomem *base) |
52 | { | 51 | { |
53 | u32 old = readl(timer_base + TIMER_CNTVAL_REG(1)); | 52 | u32 old = readl(base + TIMER_CNTVAL_REG(1)); |
54 | 53 | ||
55 | while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS) | 54 | while ((old - readl(base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS) |
56 | cpu_relax(); | 55 | cpu_relax(); |
57 | } | 56 | } |
58 | 57 | ||
59 | static void sun4i_clkevt_time_stop(u8 timer) | 58 | static void sun4i_clkevt_time_stop(void __iomem *base, u8 timer) |
60 | { | 59 | { |
61 | u32 val = readl(timer_base + TIMER_CTL_REG(timer)); | 60 | u32 val = readl(base + TIMER_CTL_REG(timer)); |
62 | writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); | 61 | writel(val & ~TIMER_CTL_ENABLE, base + TIMER_CTL_REG(timer)); |
63 | sun4i_clkevt_sync(); | 62 | sun4i_clkevt_sync(base); |
64 | } | 63 | } |
65 | 64 | ||
66 | static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay) | 65 | static void sun4i_clkevt_time_setup(void __iomem *base, u8 timer, |
66 | unsigned long delay) | ||
67 | { | 67 | { |
68 | writel(delay, timer_base + TIMER_INTVAL_REG(timer)); | 68 | writel(delay, base + TIMER_INTVAL_REG(timer)); |
69 | } | 69 | } |
70 | 70 | ||
71 | static void sun4i_clkevt_time_start(u8 timer, bool periodic) | 71 | static void sun4i_clkevt_time_start(void __iomem *base, u8 timer, |
72 | bool periodic) | ||
72 | { | 73 | { |
73 | u32 val = readl(timer_base + TIMER_CTL_REG(timer)); | 74 | u32 val = readl(base + TIMER_CTL_REG(timer)); |
74 | 75 | ||
75 | if (periodic) | 76 | if (periodic) |
76 | val &= ~TIMER_CTL_ONESHOT; | 77 | val &= ~TIMER_CTL_ONESHOT; |
@@ -78,115 +79,106 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) | |||
78 | val |= TIMER_CTL_ONESHOT; | 79 | val |= TIMER_CTL_ONESHOT; |
79 | 80 | ||
80 | writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, | 81 | writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, |
81 | timer_base + TIMER_CTL_REG(timer)); | 82 | base + TIMER_CTL_REG(timer)); |
82 | } | 83 | } |
83 | 84 | ||
84 | static int sun4i_clkevt_shutdown(struct clock_event_device *evt) | 85 | static int sun4i_clkevt_shutdown(struct clock_event_device *evt) |
85 | { | 86 | { |
86 | sun4i_clkevt_time_stop(0); | 87 | struct timer_of *to = to_timer_of(evt); |
88 | |||
89 | sun4i_clkevt_time_stop(timer_of_base(to), 0); | ||
90 | |||
87 | return 0; | 91 | return 0; |
88 | } | 92 | } |
89 | 93 | ||
90 | static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt) | 94 | static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt) |
91 | { | 95 | { |
92 | sun4i_clkevt_time_stop(0); | 96 | struct timer_of *to = to_timer_of(evt); |
93 | sun4i_clkevt_time_start(0, false); | 97 | |
98 | sun4i_clkevt_time_stop(timer_of_base(to), 0); | ||
99 | sun4i_clkevt_time_start(timer_of_base(to), 0, false); | ||
100 | |||
94 | return 0; | 101 | return 0; |
95 | } | 102 | } |
96 | 103 | ||
97 | static int sun4i_clkevt_set_periodic(struct clock_event_device *evt) | 104 | static int sun4i_clkevt_set_periodic(struct clock_event_device *evt) |
98 | { | 105 | { |
99 | sun4i_clkevt_time_stop(0); | 106 | struct timer_of *to = to_timer_of(evt); |
100 | sun4i_clkevt_time_setup(0, ticks_per_jiffy); | 107 | |
101 | sun4i_clkevt_time_start(0, true); | 108 | sun4i_clkevt_time_stop(timer_of_base(to), 0); |
109 | sun4i_clkevt_time_setup(timer_of_base(to), 0, timer_of_period(to)); | ||
110 | sun4i_clkevt_time_start(timer_of_base(to), 0, true); | ||
111 | |||
102 | return 0; | 112 | return 0; |
103 | } | 113 | } |
104 | 114 | ||
105 | static int sun4i_clkevt_next_event(unsigned long evt, | 115 | static int sun4i_clkevt_next_event(unsigned long evt, |
106 | struct clock_event_device *unused) | 116 | struct clock_event_device *clkevt) |
107 | { | 117 | { |
108 | sun4i_clkevt_time_stop(0); | 118 | struct timer_of *to = to_timer_of(clkevt); |
109 | sun4i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS); | 119 | |
110 | sun4i_clkevt_time_start(0, false); | 120 | sun4i_clkevt_time_stop(timer_of_base(to), 0); |
121 | sun4i_clkevt_time_setup(timer_of_base(to), 0, evt - TIMER_SYNC_TICKS); | ||
122 | sun4i_clkevt_time_start(timer_of_base(to), 0, false); | ||
111 | 123 | ||
112 | return 0; | 124 | return 0; |
113 | } | 125 | } |
114 | 126 | ||
115 | static struct clock_event_device sun4i_clockevent = { | 127 | static void sun4i_timer_clear_interrupt(void __iomem *base) |
116 | .name = "sun4i_tick", | ||
117 | .rating = 350, | ||
118 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
119 | .set_state_shutdown = sun4i_clkevt_shutdown, | ||
120 | .set_state_periodic = sun4i_clkevt_set_periodic, | ||
121 | .set_state_oneshot = sun4i_clkevt_set_oneshot, | ||
122 | .tick_resume = sun4i_clkevt_shutdown, | ||
123 | .set_next_event = sun4i_clkevt_next_event, | ||
124 | }; | ||
125 | |||
126 | static void sun4i_timer_clear_interrupt(void) | ||
127 | { | 128 | { |
128 | writel(TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_ST_REG); | 129 | writel(TIMER_IRQ_EN(0), base + TIMER_IRQ_ST_REG); |
129 | } | 130 | } |
130 | 131 | ||
131 | static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id) | 132 | static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id) |
132 | { | 133 | { |
133 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; | 134 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; |
135 | struct timer_of *to = to_timer_of(evt); | ||
134 | 136 | ||
135 | sun4i_timer_clear_interrupt(); | 137 | sun4i_timer_clear_interrupt(timer_of_base(to)); |
136 | evt->event_handler(evt); | 138 | evt->event_handler(evt); |
137 | 139 | ||
138 | return IRQ_HANDLED; | 140 | return IRQ_HANDLED; |
139 | } | 141 | } |
140 | 142 | ||
141 | static struct irqaction sun4i_timer_irq = { | 143 | static struct timer_of to = { |
142 | .name = "sun4i_timer0", | 144 | .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE, |
143 | .flags = IRQF_TIMER | IRQF_IRQPOLL, | 145 | |
144 | .handler = sun4i_timer_interrupt, | 146 | .clkevt = { |
145 | .dev_id = &sun4i_clockevent, | 147 | .name = "sun4i_tick", |
148 | .rating = 350, | ||
149 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
150 | .set_state_shutdown = sun4i_clkevt_shutdown, | ||
151 | .set_state_periodic = sun4i_clkevt_set_periodic, | ||
152 | .set_state_oneshot = sun4i_clkevt_set_oneshot, | ||
153 | .tick_resume = sun4i_clkevt_shutdown, | ||
154 | .set_next_event = sun4i_clkevt_next_event, | ||
155 | .cpumask = cpu_possible_mask, | ||
156 | }, | ||
157 | |||
158 | .of_irq = { | ||
159 | .handler = sun4i_timer_interrupt, | ||
160 | .flags = IRQF_TIMER | IRQF_IRQPOLL, | ||
161 | }, | ||
146 | }; | 162 | }; |
147 | 163 | ||
148 | static u64 notrace sun4i_timer_sched_read(void) | 164 | static u64 notrace sun4i_timer_sched_read(void) |
149 | { | 165 | { |
150 | return ~readl(timer_base + TIMER_CNTVAL_REG(1)); | 166 | return ~readl(timer_of_base(&to) + TIMER_CNTVAL_REG(1)); |
151 | } | 167 | } |
152 | 168 | ||
153 | static int __init sun4i_timer_init(struct device_node *node) | 169 | static int __init sun4i_timer_init(struct device_node *node) |
154 | { | 170 | { |
155 | unsigned long rate = 0; | 171 | int ret; |
156 | struct clk *clk; | ||
157 | int ret, irq; | ||
158 | u32 val; | 172 | u32 val; |
159 | 173 | ||
160 | timer_base = of_iomap(node, 0); | 174 | ret = timer_of_init(node, &to); |
161 | if (!timer_base) { | 175 | if (ret) |
162 | pr_crit("Can't map registers\n"); | ||
163 | return -ENXIO; | ||
164 | } | ||
165 | |||
166 | irq = irq_of_parse_and_map(node, 0); | ||
167 | if (irq <= 0) { | ||
168 | pr_crit("Can't parse IRQ\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | clk = of_clk_get(node, 0); | ||
173 | if (IS_ERR(clk)) { | ||
174 | pr_crit("Can't get timer clock\n"); | ||
175 | return PTR_ERR(clk); | ||
176 | } | ||
177 | |||
178 | ret = clk_prepare_enable(clk); | ||
179 | if (ret) { | ||
180 | pr_err("Failed to prepare clock\n"); | ||
181 | return ret; | 176 | return ret; |
182 | } | ||
183 | |||
184 | rate = clk_get_rate(clk); | ||
185 | 177 | ||
186 | writel(~0, timer_base + TIMER_INTVAL_REG(1)); | 178 | writel(~0, timer_of_base(&to) + TIMER_INTVAL_REG(1)); |
187 | writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD | | 179 | writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD | |
188 | TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), | 180 | TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), |
189 | timer_base + TIMER_CTL_REG(1)); | 181 | timer_of_base(&to) + TIMER_CTL_REG(1)); |
190 | 182 | ||
191 | /* | 183 | /* |
192 | * sched_clock_register does not have priorities, and on sun6i and | 184 | * sched_clock_register does not have priorities, and on sun6i and |
@@ -195,41 +187,32 @@ static int __init sun4i_timer_init(struct device_node *node) | |||
195 | if (of_machine_is_compatible("allwinner,sun4i-a10") || | 187 | if (of_machine_is_compatible("allwinner,sun4i-a10") || |
196 | of_machine_is_compatible("allwinner,sun5i-a13") || | 188 | of_machine_is_compatible("allwinner,sun5i-a13") || |
197 | of_machine_is_compatible("allwinner,sun5i-a10s")) | 189 | of_machine_is_compatible("allwinner,sun5i-a10s")) |
198 | sched_clock_register(sun4i_timer_sched_read, 32, rate); | 190 | sched_clock_register(sun4i_timer_sched_read, 32, |
191 | timer_of_rate(&to)); | ||
199 | 192 | ||
200 | ret = clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, | 193 | ret = clocksource_mmio_init(timer_of_base(&to) + TIMER_CNTVAL_REG(1), |
201 | rate, 350, 32, clocksource_mmio_readl_down); | 194 | node->name, timer_of_rate(&to), 350, 32, |
195 | clocksource_mmio_readl_down); | ||
202 | if (ret) { | 196 | if (ret) { |
203 | pr_err("Failed to register clocksource\n"); | 197 | pr_err("Failed to register clocksource\n"); |
204 | return ret; | 198 | return ret; |
205 | } | 199 | } |
206 | 200 | ||
207 | ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); | ||
208 | |||
209 | writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), | 201 | writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), |
210 | timer_base + TIMER_CTL_REG(0)); | 202 | timer_of_base(&to) + TIMER_CTL_REG(0)); |
211 | 203 | ||
212 | /* Make sure timer is stopped before playing with interrupts */ | 204 | /* Make sure timer is stopped before playing with interrupts */ |
213 | sun4i_clkevt_time_stop(0); | 205 | sun4i_clkevt_time_stop(timer_of_base(&to), 0); |
214 | 206 | ||
215 | /* clear timer0 interrupt */ | 207 | /* clear timer0 interrupt */ |
216 | sun4i_timer_clear_interrupt(); | 208 | sun4i_timer_clear_interrupt(timer_of_base(&to)); |
217 | |||
218 | sun4i_clockevent.cpumask = cpu_possible_mask; | ||
219 | sun4i_clockevent.irq = irq; | ||
220 | 209 | ||
221 | clockevents_config_and_register(&sun4i_clockevent, rate, | 210 | clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), |
222 | TIMER_SYNC_TICKS, 0xffffffff); | 211 | TIMER_SYNC_TICKS, 0xffffffff); |
223 | 212 | ||
224 | ret = setup_irq(irq, &sun4i_timer_irq); | ||
225 | if (ret) { | ||
226 | pr_err("failed to setup irq %d\n", irq); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /* Enable timer0 interrupt */ | 213 | /* Enable timer0 interrupt */ |
231 | val = readl(timer_base + TIMER_IRQ_EN_REG); | 214 | val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG); |
232 | writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); | 215 | writel(val | TIMER_IRQ_EN(0), timer_of_base(&to) + TIMER_IRQ_EN_REG); |
233 | 216 | ||
234 | return ret; | 217 | return ret; |
235 | } | 218 | } |