xref: /openbmc/linux/arch/mips/ralink/cevt-rt3352.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
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  *
697b92108SJohn Crispin  * Copyright (C) 2013 by John Crispin <john@phrozen.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 
systick_next_event(unsigned long delta,struct clock_event_device * evt)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;
5137bcc03fSJohn Crispin 	iowrite32(count, sdev->membase + SYSTICK_COMPARE);
521f2acc5aSJohn Crispin 
531f2acc5aSJohn Crispin 	return 0;
541f2acc5aSJohn Crispin }
551f2acc5aSJohn Crispin 
systick_event_handler(struct clock_event_device * dev)561f2acc5aSJohn Crispin static void systick_event_handler(struct clock_event_device *dev)
571f2acc5aSJohn Crispin {
581f2acc5aSJohn Crispin 	/* noting to do here */
591f2acc5aSJohn Crispin }
601f2acc5aSJohn Crispin 
systick_interrupt(int irq,void * dev_id)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 
systick_shutdown(struct clock_event_device * evt)8559113d93SViresh Kumar static int systick_shutdown(struct clock_event_device *evt)
861f2acc5aSJohn Crispin {
871f2acc5aSJohn Crispin 	struct systick_device *sdev;
881f2acc5aSJohn Crispin 
891f2acc5aSJohn Crispin 	sdev = container_of(evt, struct systick_device, dev);
901f2acc5aSJohn Crispin 
9159113d93SViresh Kumar 	if (sdev->irq_requested)
92*ac8fd122Safzal mohammed 		free_irq(systick.dev.irq, &systick.dev);
9359113d93SViresh Kumar 	sdev->irq_requested = 0;
9459113d93SViresh Kumar 	iowrite32(0, systick.membase + SYSTICK_CONFIG);
9559113d93SViresh Kumar 
9659113d93SViresh Kumar 	return 0;
9759113d93SViresh Kumar }
9859113d93SViresh Kumar 
systick_set_oneshot(struct clock_event_device * evt)9959113d93SViresh Kumar static int systick_set_oneshot(struct clock_event_device *evt)
10059113d93SViresh Kumar {
101*ac8fd122Safzal mohammed 	const char *name = systick.dev.name;
10259113d93SViresh Kumar 	struct systick_device *sdev;
103*ac8fd122Safzal mohammed 	int irq = systick.dev.irq;
10459113d93SViresh Kumar 
10559113d93SViresh Kumar 	sdev = container_of(evt, struct systick_device, dev);
10659113d93SViresh Kumar 
107*ac8fd122Safzal mohammed 	if (!sdev->irq_requested) {
108*ac8fd122Safzal mohammed 		if (request_irq(irq, systick_interrupt,
109*ac8fd122Safzal mohammed 				IRQF_PERCPU | IRQF_TIMER, name, &systick.dev))
110*ac8fd122Safzal mohammed 			pr_err("Failed to request irq %d (%s)\n", irq, name);
111*ac8fd122Safzal mohammed 	}
1121f2acc5aSJohn Crispin 	sdev->irq_requested = 1;
1131f2acc5aSJohn Crispin 	iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
1141f2acc5aSJohn Crispin 		  systick.membase + SYSTICK_CONFIG);
1151f2acc5aSJohn Crispin 
11659113d93SViresh Kumar 	return 0;
1171f2acc5aSJohn Crispin }
1181f2acc5aSJohn Crispin 
ralink_systick_init(struct device_node * np)1192712616fSDaniel Lezcano static int __init ralink_systick_init(struct device_node *np)
1201f2acc5aSJohn Crispin {
1212712616fSDaniel Lezcano 	int ret;
1222712616fSDaniel Lezcano 
1231f2acc5aSJohn Crispin 	systick.membase = of_iomap(np, 0);
1241f2acc5aSJohn Crispin 	if (!systick.membase)
1252712616fSDaniel Lezcano 		return -ENXIO;
1261f2acc5aSJohn Crispin 
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);
130e4db9253SNicolai Stange 	systick.dev.max_delta_ticks = 0x7fff;
1311f2acc5aSJohn Crispin 	systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
132e4db9253SNicolai Stange 	systick.dev.min_delta_ticks = 0x3;
1331f2acc5aSJohn Crispin 	systick.dev.irq = irq_of_parse_and_map(np, 0);
1341f2acc5aSJohn Crispin 	if (!systick.dev.irq) {
1359475e90fSRob Herring 		pr_err("%pOFn: request_irq failed", np);
1362712616fSDaniel Lezcano 		return -EINVAL;
1371f2acc5aSJohn Crispin 	}
1381f2acc5aSJohn Crispin 
1392712616fSDaniel Lezcano 	ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
1402712616fSDaniel Lezcano 				    SYSTICK_FREQ, 301, 16,
1412712616fSDaniel Lezcano 				    clocksource_mmio_readl_up);
1422712616fSDaniel Lezcano 	if (ret)
1432712616fSDaniel Lezcano 		return ret;
1441f2acc5aSJohn Crispin 
1451f2acc5aSJohn Crispin 	clockevents_register_device(&systick.dev);
1461f2acc5aSJohn Crispin 
1479475e90fSRob Herring 	pr_info("%pOFn: running - mult: %d, shift: %d\n",
1489475e90fSRob Herring 			np, systick.dev.mult, systick.dev.shift);
1492712616fSDaniel Lezcano 
1502712616fSDaniel Lezcano 	return 0;
1511f2acc5aSJohn Crispin }
1521f2acc5aSJohn Crispin 
15317273395SDaniel Lezcano TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
154