Clockevent driver based on host timer operations and clocksource
driver and udelay support based on host time operations.

Signed-off-by: Octavian Purdila <octavian.purd...@intel.com>
---
 arch/lkl/kernel/time.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)
 create mode 100644 arch/lkl/kernel/time.c

diff --git a/arch/lkl/kernel/time.c b/arch/lkl/kernel/time.c
new file mode 100644
index 0000000..d099736
--- /dev/null
+++ b/arch/lkl/kernel/time.c
@@ -0,0 +1,125 @@
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/host_ops.h>
+
+void __ndelay(unsigned long nsecs)
+{
+       unsigned long long start = lkl_ops->time();
+
+       while (lkl_ops->time() < start + nsecs)
+               ;
+}
+
+void __udelay(unsigned long usecs)
+{
+       __ndelay(usecs * NSEC_PER_USEC);
+}
+
+void __const_udelay(unsigned long xloops)
+{
+       __udelay(xloops / 5);
+}
+
+void calibrate_delay(void)
+{
+}
+
+static cycle_t clock_read(struct clocksource *cs)
+{
+       return lkl_ops->time();
+}
+
+static struct clocksource clocksource = {
+       .name   = "lkl",
+       .rating = 499,
+       .read   = clock_read,
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .mask   = CLOCKSOURCE_MASK(64),
+};
+
+static void *timer;
+
+static int timer_irq;
+
+static void timer_fn(void *arg)
+{
+       lkl_trigger_irq(timer_irq, NULL);
+}
+
+static int clockevent_set_state_shutdown(struct clock_event_device *evt)
+{
+       if (timer) {
+               lkl_ops->timer_free(timer);
+               timer = NULL;
+       }
+
+       return 0;
+}
+
+static int clockevent_set_state_oneshot(struct clock_event_device *evt)
+{
+       timer = lkl_ops->timer_alloc(timer_fn, NULL);
+       if (!timer)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static irqreturn_t timer_irq_handler(int irq, void *dev_id)
+{
+       struct clock_event_device *dev = (struct clock_event_device *)dev_id;
+
+       dev->event_handler(dev);
+
+       return IRQ_HANDLED;
+}
+
+static int clockevent_next_event(unsigned long hz,
+                                struct clock_event_device *evt)
+{
+       unsigned long ns = 1000000000 * hz / HZ;
+
+       return lkl_ops->timer_set_oneshot(timer, ns);
+}
+
+static struct clock_event_device clockevent = {
+       .name                   = "lkl",
+       .features               = CLOCK_EVT_FEAT_ONESHOT,
+       .set_state_oneshot      = clockevent_set_state_oneshot,
+       .set_next_event         = clockevent_next_event,
+       .set_state_shutdown     = clockevent_set_state_shutdown,
+};
+
+static struct irqaction irq0  = {
+       .handler = timer_irq_handler,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER,
+       .dev_id = &clockevent,
+       .name = "timer"
+};
+
+void __init time_init(void)
+{
+       int ret;
+
+       if (!lkl_ops->timer_alloc || !lkl_ops->timer_free ||
+           !lkl_ops->timer_set_oneshot || !lkl_ops->time) {
+               pr_err("lkl: no time or timer support provided by host\n");
+               return;
+       }
+
+       timer_irq = lkl_get_free_irq("timer");
+       setup_irq(timer_irq, &irq0);
+
+       ret = clocksource_register_khz(&clocksource, 1000000);
+       if (ret)
+               pr_err("lkl: unable to register clocksource\n");
+
+       clockevents_config_and_register(&clockevent, HZ, 0, 0xffffffff);
+
+       pr_info("lkl: time and timers initialized\n");
+}
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to