xref: /openbmc/linux/arch/mips/ralink/cevt-rt3352.c (revision 37bcc03f97e05cc65ce87d3b2fdcd4e5b28ce06c)
11f2acc5aSJohn Crispin /*
21f2acc5aSJohn Crispin  * This file is subject to the terms and conditions of the GNU General Public
31f2acc5aSJohn Crispin  * License.  See the file "COPYING" in the main directory of this archive
41f2acc5aSJohn Crispin  * for more details.
51f2acc5aSJohn Crispin  *
61f2acc5aSJohn Crispin  * Copyright (C) 2013 by John Crispin <blogic@openwrt.org>
71f2acc5aSJohn Crispin  */
81f2acc5aSJohn Crispin 
91f2acc5aSJohn Crispin #include <linux/clockchips.h>
101f2acc5aSJohn Crispin #include <linux/clocksource.h>
111f2acc5aSJohn Crispin #include <linux/interrupt.h>
121f2acc5aSJohn Crispin #include <linux/reset.h>
131f2acc5aSJohn Crispin #include <linux/init.h>
141f2acc5aSJohn Crispin #include <linux/time.h>
151f2acc5aSJohn Crispin #include <linux/of.h>
161f2acc5aSJohn Crispin #include <linux/of_irq.h>
171f2acc5aSJohn Crispin #include <linux/of_address.h>
181f2acc5aSJohn Crispin 
191f2acc5aSJohn Crispin #include <asm/mach-ralink/ralink_regs.h>
201f2acc5aSJohn Crispin 
211f2acc5aSJohn Crispin #define SYSTICK_FREQ		(50 * 1000)
221f2acc5aSJohn Crispin 
231f2acc5aSJohn Crispin #define SYSTICK_CONFIG		0x00
241f2acc5aSJohn Crispin #define SYSTICK_COMPARE		0x04
251f2acc5aSJohn Crispin #define SYSTICK_COUNT		0x08
261f2acc5aSJohn Crispin 
271f2acc5aSJohn Crispin /* route systick irq to mips irq 7 instead of the r4k-timer */
281f2acc5aSJohn Crispin #define CFG_EXT_STK_EN		0x2
291f2acc5aSJohn Crispin /* enable the counter */
301f2acc5aSJohn Crispin #define CFG_CNT_EN		0x1
311f2acc5aSJohn Crispin 
321f2acc5aSJohn Crispin struct systick_device {
331f2acc5aSJohn Crispin 	void __iomem *membase;
341f2acc5aSJohn Crispin 	struct clock_event_device dev;
351f2acc5aSJohn Crispin 	int irq_requested;
361f2acc5aSJohn Crispin 	int freq_scale;
371f2acc5aSJohn Crispin };
381f2acc5aSJohn Crispin 
3959113d93SViresh Kumar static int systick_set_oneshot(struct clock_event_device *evt);
4059113d93SViresh Kumar static int systick_shutdown(struct clock_event_device *evt);
411f2acc5aSJohn Crispin 
421f2acc5aSJohn Crispin static int systick_next_event(unsigned long delta,
431f2acc5aSJohn Crispin 				struct clock_event_device *evt)
441f2acc5aSJohn Crispin {
451f2acc5aSJohn Crispin 	struct systick_device *sdev;
461f2acc5aSJohn Crispin 	u32 count;
471f2acc5aSJohn Crispin 
481f2acc5aSJohn Crispin 	sdev = container_of(evt, struct systick_device, dev);
491f2acc5aSJohn Crispin 	count = ioread32(sdev->membase + SYSTICK_COUNT);
501f2acc5aSJohn Crispin 	count = (count + delta) % SYSTICK_FREQ;
51*37bcc03fSJohn Crispin 	iowrite32(count, sdev->membase + SYSTICK_COMPARE);
521f2acc5aSJohn Crispin 
531f2acc5aSJohn Crispin 	return 0;
541f2acc5aSJohn Crispin }
551f2acc5aSJohn Crispin 
561f2acc5aSJohn Crispin static void systick_event_handler(struct clock_event_device *dev)
571f2acc5aSJohn Crispin {
581f2acc5aSJohn Crispin 	/* noting to do here */
591f2acc5aSJohn Crispin }
601f2acc5aSJohn Crispin 
611f2acc5aSJohn Crispin static irqreturn_t systick_interrupt(int irq, void *dev_id)
621f2acc5aSJohn Crispin {
631f2acc5aSJohn Crispin 	struct clock_event_device *dev = (struct clock_event_device *) dev_id;
641f2acc5aSJohn Crispin 
651f2acc5aSJohn Crispin 	dev->event_handler(dev);
661f2acc5aSJohn Crispin 
671f2acc5aSJohn Crispin 	return IRQ_HANDLED;
681f2acc5aSJohn Crispin }
691f2acc5aSJohn Crispin 
701f2acc5aSJohn Crispin static struct systick_device systick = {
711f2acc5aSJohn Crispin 	.dev = {
721f2acc5aSJohn Crispin 		/*
731f2acc5aSJohn Crispin 		 * cevt-r4k uses 300, make sure systick
741f2acc5aSJohn Crispin 		 * gets used if available
751f2acc5aSJohn Crispin 		 */
761f2acc5aSJohn Crispin 		.rating			= 310,
771f2acc5aSJohn Crispin 		.features		= CLOCK_EVT_FEAT_ONESHOT,
781f2acc5aSJohn Crispin 		.set_next_event		= systick_next_event,
7959113d93SViresh Kumar 		.set_state_shutdown	= systick_shutdown,
8059113d93SViresh Kumar 		.set_state_oneshot	= systick_set_oneshot,
811f2acc5aSJohn Crispin 		.event_handler		= systick_event_handler,
821f2acc5aSJohn Crispin 	},
831f2acc5aSJohn Crispin };
841f2acc5aSJohn Crispin 
851f2acc5aSJohn Crispin static struct irqaction systick_irqaction = {
861f2acc5aSJohn Crispin 	.handler = systick_interrupt,
871f2acc5aSJohn Crispin 	.flags = IRQF_PERCPU | IRQF_TIMER,
881f2acc5aSJohn Crispin 	.dev_id = &systick.dev,
891f2acc5aSJohn Crispin };
901f2acc5aSJohn Crispin 
9159113d93SViresh Kumar static int systick_shutdown(struct clock_event_device *evt)
921f2acc5aSJohn Crispin {
931f2acc5aSJohn Crispin 	struct systick_device *sdev;
941f2acc5aSJohn Crispin 
951f2acc5aSJohn Crispin 	sdev = container_of(evt, struct systick_device, dev);
961f2acc5aSJohn Crispin 
9759113d93SViresh Kumar 	if (sdev->irq_requested)
9859113d93SViresh Kumar 		free_irq(systick.dev.irq, &systick_irqaction);
9959113d93SViresh Kumar 	sdev->irq_requested = 0;
10059113d93SViresh Kumar 	iowrite32(0, systick.membase + SYSTICK_CONFIG);
10159113d93SViresh Kumar 
10259113d93SViresh Kumar 	return 0;
10359113d93SViresh Kumar }
10459113d93SViresh Kumar 
10559113d93SViresh Kumar static int systick_set_oneshot(struct clock_event_device *evt)
10659113d93SViresh Kumar {
10759113d93SViresh Kumar 	struct systick_device *sdev;
10859113d93SViresh Kumar 
10959113d93SViresh Kumar 	sdev = container_of(evt, struct systick_device, dev);
11059113d93SViresh Kumar 
1111f2acc5aSJohn Crispin 	if (!sdev->irq_requested)
1121f2acc5aSJohn Crispin 		setup_irq(systick.dev.irq, &systick_irqaction);
1131f2acc5aSJohn Crispin 	sdev->irq_requested = 1;
1141f2acc5aSJohn Crispin 	iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
1151f2acc5aSJohn Crispin 		  systick.membase + SYSTICK_CONFIG);
1161f2acc5aSJohn Crispin 
11759113d93SViresh Kumar 	return 0;
1181f2acc5aSJohn Crispin }
1191f2acc5aSJohn Crispin 
1201f2acc5aSJohn Crispin static void __init ralink_systick_init(struct device_node *np)
1211f2acc5aSJohn Crispin {
1221f2acc5aSJohn Crispin 	systick.membase = of_iomap(np, 0);
1231f2acc5aSJohn Crispin 	if (!systick.membase)
1241f2acc5aSJohn Crispin 		return;
1251f2acc5aSJohn Crispin 
1261f2acc5aSJohn Crispin 	systick_irqaction.name = np->name;
1271f2acc5aSJohn Crispin 	systick.dev.name = np->name;
1281f2acc5aSJohn Crispin 	clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
1291f2acc5aSJohn Crispin 	systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
1301f2acc5aSJohn Crispin 	systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
1311f2acc5aSJohn Crispin 	systick.dev.irq = irq_of_parse_and_map(np, 0);
1321f2acc5aSJohn Crispin 	if (!systick.dev.irq) {
1331f2acc5aSJohn Crispin 		pr_err("%s: request_irq failed", np->name);
1341f2acc5aSJohn Crispin 		return;
1351f2acc5aSJohn Crispin 	}
1361f2acc5aSJohn Crispin 
1371f2acc5aSJohn Crispin 	clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
1381f2acc5aSJohn Crispin 			SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up);
1391f2acc5aSJohn Crispin 
1401f2acc5aSJohn Crispin 	clockevents_register_device(&systick.dev);
1411f2acc5aSJohn Crispin 
14277d84ff8SMasanari Iida 	pr_info("%s: running - mult: %d, shift: %d\n",
1431f2acc5aSJohn Crispin 			np->name, systick.dev.mult, systick.dev.shift);
1441f2acc5aSJohn Crispin }
1451f2acc5aSJohn Crispin 
1461f2acc5aSJohn Crispin CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
147