Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

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