From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:08:11 +0200
Subject: [PATCH 1/2] MIPS: use set_mode() to enable/disable the cevt-r4k irq

Signed-off-by: John Crispin <blogic@openwrt.org>
---
 arch/mips/kernel/cevt-r4k.c | 43 +++++++++++++++++++++++++++++++++++++
 drivers/clocksource/Kconfig |  5 +++++
 2 files changed, 48 insertions(+)

--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -16,6 +16,31 @@
 #include <asm/time.h>
 #include <asm/cevt-r4k.h>
 
+#ifdef CONFIG_CEVT_SYSTICK_QUIRK
+static int mips_state_oneshot(struct clock_event_device *evt)
+{
+	unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
+	if (!cp0_timer_irq_installed) {
+		cp0_timer_irq_installed = 1;
+		if (request_irq(evt->irq, c0_compare_interrupt, flags, "timer",
+					c0_compare_interrupt))
+			pr_err("Failed to request irq %d (timer)\n", evt->irq);
+	}
+
+	return 0;
+}
+
+static int mips_state_shutdown(struct clock_event_device *evt)
+{
+	if (cp0_timer_irq_installed) {
+		cp0_timer_irq_installed = 0;
+		free_irq(evt->irq, NULL);
+	}
+
+	return 0;
+}
+#endif
+
 static int mips_next_event(unsigned long delta,
 			   struct clock_event_device *evt)
 {
@@ -292,7 +317,9 @@ core_initcall(r4k_register_cpufreq_notif
 
 int r4k_clockevent_init(void)
 {
+#ifndef CONFIG_CEVT_SYSTICK_QUIRK
 	unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
+#endif
 	unsigned int cpu = smp_processor_id();
 	struct clock_event_device *cd;
 	unsigned int irq, min_delta;
@@ -303,6 +330,15 @@ int r4k_clockevent_init(void)
 	if (!c0_compare_int_usable())
 		return -ENXIO;
 
+#ifdef CONFIG_CEVT_SYSTICK_QUIRK
+	/*
+	 * With vectored interrupts things are getting platform specific.
+	 * get_c0_compare_int is a hook to allow a platform to return the
+	 * interrupt number of its liking.
+	 */
+	irq = get_c0_compare_int();
+#endif
+
 	cd = &per_cpu(mips_clockevent_device, cpu);
 
 	cd->name		= "MIPS";
@@ -314,11 +350,17 @@ int r4k_clockevent_init(void)
 
 	cd->rating		= 300;
 	cd->cpumask		= cpumask_of(cpu);
+#ifdef CONFIG_CEVT_SYSTICK_QUIRK
+	cd->irq			= irq;
+	cd->set_state_shutdown	= mips_state_shutdown;
+	cd->set_state_oneshot	= mips_state_oneshot;
+#endif
 	cd->set_next_event	= mips_next_event;
 	cd->event_handler	= mips_event_handler;
 
 	clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
 
+#ifndef CONFIG_CEVT_SYSTICK_QUIRK
 	if (cp0_timer_irq_installed)
 		return 0;
 
@@ -334,6 +376,7 @@ int r4k_clockevent_init(void)
 	if (request_irq(irq, c0_compare_interrupt, flags, "timer",
 			c0_compare_interrupt))
 		pr_err("Failed to request irq %d (timer)\n", irq);
+#endif
 
 	return 0;
 }
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -753,10 +753,15 @@ config EP93XX_TIMER
 	help
 	  Enables support for the Cirrus Logic timer block
 	  EP93XX.
+ 
+config CEVT_SYSTICK_QUIRK
+	bool
+	default n
 
 config RALINK_TIMER
 	bool "Ralink System Tick Counter"
 	depends on SOC_RT305X || SOC_MT7620 || COMPILE_TEST
+	select CEVT_SYSTICK_QUIRK
 	select CLKSRC_MMIO
 	select TIMER_OF
 	help
