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