diff options
-rw-r--r-- | arch/mips/ralink/Kconfig | 7 | ||||
-rw-r--r-- | arch/mips/ralink/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/ralink/cevt-rt3352.c | 145 |
3 files changed, 154 insertions, 0 deletions
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 026e823d871d..c528d0cf5add 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig | |||
@@ -1,5 +1,12 @@ | |||
1 | if RALINK | 1 | if RALINK |
2 | 2 | ||
3 | config CLKEVT_RT3352 | ||
4 | bool | ||
5 | depends on SOC_RT305X || SOC_MT7620 | ||
6 | default y | ||
7 | select CLKSRC_OF | ||
8 | select CLKSRC_MMIO | ||
9 | |||
3 | choice | 10 | choice |
4 | prompt "Ralink SoC selection" | 11 | prompt "Ralink SoC selection" |
5 | default SOC_RT305X | 12 | default SOC_RT305X |
diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile index e37e0ec5b378..98ae349827be 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile | |||
@@ -8,6 +8,8 @@ | |||
8 | 8 | ||
9 | obj-y := prom.o of.o reset.o clk.o irq.o timer.o | 9 | obj-y := prom.o of.o reset.o clk.o irq.o timer.o |
10 | 10 | ||
11 | obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o | ||
12 | |||
11 | obj-$(CONFIG_SOC_RT288X) += rt288x.o | 13 | obj-$(CONFIG_SOC_RT288X) += rt288x.o |
12 | obj-$(CONFIG_SOC_RT305X) += rt305x.o | 14 | obj-$(CONFIG_SOC_RT305X) += rt305x.o |
13 | obj-$(CONFIG_SOC_RT3883) += rt3883.o | 15 | obj-$(CONFIG_SOC_RT3883) += rt3883.o |
diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c new file mode 100644 index 000000000000..cc17566d1934 --- /dev/null +++ b/arch/mips/ralink/cevt-rt3352.c | |||
@@ -0,0 +1,145 @@ | |||
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 <blogic@openwrt.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 void systick_set_clock_mode(enum clock_event_mode mode, | ||
40 | 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 + delta, 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_mode = systick_set_clock_mode, | ||
80 | .event_handler = systick_event_handler, | ||
81 | }, | ||
82 | }; | ||
83 | |||
84 | static struct irqaction systick_irqaction = { | ||
85 | .handler = systick_interrupt, | ||
86 | .flags = IRQF_PERCPU | IRQF_TIMER, | ||
87 | .dev_id = &systick.dev, | ||
88 | }; | ||
89 | |||
90 | static void systick_set_clock_mode(enum clock_event_mode mode, | ||
91 | struct clock_event_device *evt) | ||
92 | { | ||
93 | struct systick_device *sdev; | ||
94 | |||
95 | sdev = container_of(evt, struct systick_device, dev); | ||
96 | |||
97 | switch (mode) { | ||
98 | case CLOCK_EVT_MODE_ONESHOT: | ||
99 | if (!sdev->irq_requested) | ||
100 | setup_irq(systick.dev.irq, &systick_irqaction); | ||
101 | sdev->irq_requested = 1; | ||
102 | iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, | ||
103 | systick.membase + SYSTICK_CONFIG); | ||
104 | break; | ||
105 | |||
106 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
107 | if (sdev->irq_requested) | ||
108 | free_irq(systick.dev.irq, &systick_irqaction); | ||
109 | sdev->irq_requested = 0; | ||
110 | iowrite32(0, systick.membase + SYSTICK_CONFIG); | ||
111 | break; | ||
112 | |||
113 | default: | ||
114 | pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static void __init ralink_systick_init(struct device_node *np) | ||
120 | { | ||
121 | systick.membase = of_iomap(np, 0); | ||
122 | if (!systick.membase) | ||
123 | return; | ||
124 | |||
125 | systick_irqaction.name = np->name; | ||
126 | systick.dev.name = np->name; | ||
127 | clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); | ||
128 | systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); | ||
129 | systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); | ||
130 | systick.dev.irq = irq_of_parse_and_map(np, 0); | ||
131 | if (!systick.dev.irq) { | ||
132 | pr_err("%s: request_irq failed", np->name); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, | ||
137 | SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up); | ||
138 | |||
139 | clockevents_register_device(&systick.dev); | ||
140 | |||
141 | pr_info("%s: runing - mult: %d, shift: %d\n", | ||
142 | np->name, systick.dev.mult, systick.dev.shift); | ||
143 | } | ||
144 | |||
145 | CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); | ||