Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2fcfe6b8 authored by Uwe Kleine-König's avatar Uwe Kleine-König
Browse files

netx: add support for clockevents



This is based on a patch by Luotao Fu <lfu@pengutronix.de>

Signed-off-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: default avatarLuotao Fu <lfu@pengutronix.de>
Acked-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
parent 21edecd3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@ config ARCH_FOOTBRIDGE
config ARCH_NETX
	bool "Hilscher NetX based"
	select ARM_VIC
	select GENERIC_CLOCKEVENTS
	select GENERIC_TIME
	help
	  This enables support for systems based on the Hilscher NetX Soc
+67 −1
Original line number Diff line number Diff line
@@ -21,25 +21,80 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>

#include <mach/hardware.h>
#include <asm/mach/time.h>
#include <mach/netx-regs.h>

#define TIMER_CLOCKEVENT 0
#define TIMER_CLOCKSOURCE 1

static void netx_set_mode(enum clock_event_mode mode,
		struct clock_event_device *clk)
{
	u32 tmode;

	/* disable timer */
	writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT));

	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		writel(LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT));
		tmode = NETX_GPIO_COUNTER_CTRL_RST_EN |
			NETX_GPIO_COUNTER_CTRL_IRQ_EN |
			NETX_GPIO_COUNTER_CTRL_RUN;
		break;

	case CLOCK_EVT_MODE_ONESHOT:
		writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT));
		tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN |
			NETX_GPIO_COUNTER_CTRL_RUN;
		break;

	default:
		WARN(1, "%s: unhandled mode %d\n", __func__, mode);
		/* fall through */

	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_UNUSED:
	case CLOCK_EVT_MODE_RESUME:
		tmode = 0;
		break;
	}

	writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT));
}

static int netx_set_next_event(unsigned long evt,
		struct clock_event_device *clk)
{
	writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT));
	return 0;
}

static struct clock_event_device netx_clockevent = {
	.name = "netx-timer" __stringify(TIMER_CLOCKEVENT),
	.shift = 32,
	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
	.set_next_event = netx_set_next_event,
	.set_mode = netx_set_mode,
};

/*
 * IRQ handler for the timer
 */
static irqreturn_t
netx_timer_interrupt(int irq, void *dev_id)
{
	timer_tick();
	struct clock_event_device *evt = &netx_clockevent;

	/* acknowledge interrupt */
	writel(COUNTER_BIT(0), NETX_GPIO_IRQ);

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

@@ -99,6 +154,17 @@ static void __init netx_timer_init(void)
	clocksource_netx.mult =
		clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift);
	clocksource_register(&clocksource_netx);

	netx_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
			netx_clockevent.shift);
	netx_clockevent.max_delta_ns =
		clockevent_delta2ns(0xfffffffe, &netx_clockevent);
	/* with max_delta_ns >= delta2ns(0x800) the system currently runs fine.
	 * Adding some safety ... */
	netx_clockevent.min_delta_ns =
		clockevent_delta2ns(0xa00, &netx_clockevent);
	netx_clockevent.cpumask = cpumask_of_cpu(0);
	clockevents_register_device(&netx_clockevent);
}

struct sys_timer netx_timer = {