1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public |
3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. |
5 | * |
6 | * Copyright (C) 2013 by John Crispin <john@phrozen.org> |
7 | */ |
8 | |
9 | #include <linux/clockchips.h> |
10 | #include <linux/clocksource.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/reset.h> |
13 | #include <linux/init.h> |
14 | #include <linux/time.h> |
15 | #include <linux/of.h> |
16 | #include <linux/of_irq.h> |
17 | #include <linux/of_address.h> |
18 | |
19 | #include <asm/mach-ralink/ralink_regs.h> |
20 | |
21 | #define SYSTICK_FREQ (50 * 1000) |
22 | |
23 | #define SYSTICK_CONFIG 0x00 |
24 | #define SYSTICK_COMPARE 0x04 |
25 | #define SYSTICK_COUNT 0x08 |
26 | |
27 | /* route systick irq to mips irq 7 instead of the r4k-timer */ |
28 | #define CFG_EXT_STK_EN 0x2 |
29 | /* enable the counter */ |
30 | #define CFG_CNT_EN 0x1 |
31 | |
32 | struct systick_device { |
33 | void __iomem *membase; |
34 | struct clock_event_device dev; |
35 | int irq_requested; |
36 | int freq_scale; |
37 | }; |
38 | |
39 | static int systick_set_oneshot(struct clock_event_device *evt); |
40 | static int systick_shutdown(struct clock_event_device *evt); |
41 | |
42 | static int systick_next_event(unsigned long delta, |
43 | struct clock_event_device *evt) |
44 | { |
45 | struct systick_device *sdev; |
46 | u32 count; |
47 | |
48 | sdev = container_of(evt, struct systick_device, dev); |
49 | count = ioread32(sdev->membase + SYSTICK_COUNT); |
50 | count = (count + delta) % SYSTICK_FREQ; |
51 | iowrite32(count, sdev->membase + SYSTICK_COMPARE); |
52 | |
53 | return 0; |
54 | } |
55 | |
56 | static void systick_event_handler(struct clock_event_device *dev) |
57 | { |
58 | /* noting to do here */ |
59 | } |
60 | |
61 | static irqreturn_t systick_interrupt(int irq, void *dev_id) |
62 | { |
63 | struct clock_event_device *dev = (struct clock_event_device *) dev_id; |
64 | |
65 | dev->event_handler(dev); |
66 | |
67 | return IRQ_HANDLED; |
68 | } |
69 | |
70 | static struct systick_device systick = { |
71 | .dev = { |
72 | /* |
73 | * cevt-r4k uses 300, make sure systick |
74 | * gets used if available |
75 | */ |
76 | .rating = 310, |
77 | .features = CLOCK_EVT_FEAT_ONESHOT, |
78 | .set_next_event = systick_next_event, |
79 | .set_state_shutdown = systick_shutdown, |
80 | .set_state_oneshot = systick_set_oneshot, |
81 | .event_handler = systick_event_handler, |
82 | }, |
83 | }; |
84 | |
85 | static int systick_shutdown(struct clock_event_device *evt) |
86 | { |
87 | struct systick_device *sdev; |
88 | |
89 | sdev = container_of(evt, struct systick_device, dev); |
90 | |
91 | if (sdev->irq_requested) |
92 | free_irq(systick.dev.irq, &systick.dev); |
93 | sdev->irq_requested = 0; |
94 | iowrite32(0, systick.membase + SYSTICK_CONFIG); |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | static int systick_set_oneshot(struct clock_event_device *evt) |
100 | { |
101 | const char *name = systick.dev.name; |
102 | struct systick_device *sdev; |
103 | int irq = systick.dev.irq; |
104 | |
105 | sdev = container_of(evt, struct systick_device, dev); |
106 | |
107 | if (!sdev->irq_requested) { |
108 | if (request_irq(irq, handler: systick_interrupt, |
109 | IRQF_PERCPU | IRQF_TIMER, name, dev: &systick.dev)) |
110 | pr_err("Failed to request irq %d (%s)\n" , irq, name); |
111 | } |
112 | sdev->irq_requested = 1; |
113 | iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, |
114 | systick.membase + SYSTICK_CONFIG); |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | static int __init ralink_systick_init(struct device_node *np) |
120 | { |
121 | int ret; |
122 | |
123 | systick.membase = of_iomap(node: np, index: 0); |
124 | if (!systick.membase) |
125 | return -ENXIO; |
126 | |
127 | systick.dev.name = np->name; |
128 | clockevents_calc_mult_shift(ce: &systick.dev, SYSTICK_FREQ, maxsec: 60); |
129 | systick.dev.max_delta_ns = clockevent_delta2ns(latch: 0x7fff, evt: &systick.dev); |
130 | systick.dev.max_delta_ticks = 0x7fff; |
131 | systick.dev.min_delta_ns = clockevent_delta2ns(latch: 0x3, evt: &systick.dev); |
132 | systick.dev.min_delta_ticks = 0x3; |
133 | systick.dev.irq = irq_of_parse_and_map(node: np, index: 0); |
134 | if (!systick.dev.irq) { |
135 | pr_err("%pOFn: request_irq failed" , np); |
136 | return -EINVAL; |
137 | } |
138 | |
139 | ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, |
140 | SYSTICK_FREQ, 301, 16, |
141 | clocksource_mmio_readl_up); |
142 | if (ret) |
143 | return ret; |
144 | |
145 | clockevents_register_device(dev: &systick.dev); |
146 | |
147 | pr_info("%pOFn: running - mult: %d, shift: %d\n" , |
148 | np, systick.dev.mult, systick.dev.shift); |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | TIMER_OF_DECLARE(systick, "ralink,cevt-systick" , ralink_systick_init); |
154 | |