diff options
Diffstat (limited to 'arch/mips/ralink/cevt-rt3352.c')
-rw-r--r-- | arch/mips/ralink/cevt-rt3352.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c new file mode 100644 index 000000000..269d4877d --- /dev/null +++ b/arch/mips/ralink/cevt-rt3352.c | |||
@@ -0,0 +1,153 @@ | |||
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, systick_interrupt, | ||
109 | IRQF_PERCPU | IRQF_TIMER, name, &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(np, 0); | ||
124 | if (!systick.membase) | ||
125 | return -ENXIO; | ||
126 | |||
127 | systick.dev.name = np->name; | ||
128 | clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); | ||
129 | systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); | ||
130 | systick.dev.max_delta_ticks = 0x7fff; | ||
131 | systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); | ||
132 | systick.dev.min_delta_ticks = 0x3; | ||
133 | systick.dev.irq = irq_of_parse_and_map(np, 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(&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); | ||