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