root/drivers/clocksource/timer-vt8500.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vt8500_timer_read
  2. vt8500_timer_set_next_event
  3. vt8500_shutdown
  4. vt8500_timer_interrupt
  5. vt8500_timer_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  arch/arm/mach-vt8500/timer.c
   4  *
   5  *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
   6  *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
   7  */
   8 
   9 /*
  10  * This file is copied and modified from the original timer.c provided by
  11  * Alexey Charkov. Minor changes have been made for Device Tree Support.
  12  */
  13 
  14 #include <linux/io.h>
  15 #include <linux/irq.h>
  16 #include <linux/interrupt.h>
  17 #include <linux/clocksource.h>
  18 #include <linux/clockchips.h>
  19 #include <linux/delay.h>
  20 
  21 #include <linux/of.h>
  22 #include <linux/of_address.h>
  23 #include <linux/of_irq.h>
  24 
  25 #define VT8500_TIMER_OFFSET     0x0100
  26 #define VT8500_TIMER_HZ         3000000
  27 #define TIMER_MATCH_VAL         0x0000
  28 #define TIMER_COUNT_VAL         0x0010
  29 #define TIMER_STATUS_VAL        0x0014
  30 #define TIMER_IER_VAL           0x001c          /* interrupt enable */
  31 #define TIMER_CTRL_VAL          0x0020
  32 #define TIMER_AS_VAL            0x0024          /* access status */
  33 #define TIMER_COUNT_R_ACTIVE    (1 << 5)        /* not ready for read */
  34 #define TIMER_COUNT_W_ACTIVE    (1 << 4)        /* not ready for write */
  35 #define TIMER_MATCH_W_ACTIVE    (1 << 0)        /* not ready for write */
  36 
  37 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
  38 
  39 #define MIN_OSCR_DELTA          16
  40 
  41 static void __iomem *regbase;
  42 
  43 static u64 vt8500_timer_read(struct clocksource *cs)
  44 {
  45         int loops = msecs_to_loops(10);
  46         writel(3, regbase + TIMER_CTRL_VAL);
  47         while ((readl((regbase + TIMER_AS_VAL)) & TIMER_COUNT_R_ACTIVE)
  48                                                 && --loops)
  49                 cpu_relax();
  50         return readl(regbase + TIMER_COUNT_VAL);
  51 }
  52 
  53 static struct clocksource clocksource = {
  54         .name           = "vt8500_timer",
  55         .rating         = 200,
  56         .read           = vt8500_timer_read,
  57         .mask           = CLOCKSOURCE_MASK(32),
  58         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  59 };
  60 
  61 static int vt8500_timer_set_next_event(unsigned long cycles,
  62                                     struct clock_event_device *evt)
  63 {
  64         int loops = msecs_to_loops(10);
  65         u64 alarm = clocksource.read(&clocksource) + cycles;
  66         while ((readl(regbase + TIMER_AS_VAL) & TIMER_MATCH_W_ACTIVE)
  67                                                 && --loops)
  68                 cpu_relax();
  69         writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
  70 
  71         if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA)
  72                 return -ETIME;
  73 
  74         writel(1, regbase + TIMER_IER_VAL);
  75 
  76         return 0;
  77 }
  78 
  79 static int vt8500_shutdown(struct clock_event_device *evt)
  80 {
  81         writel(readl(regbase + TIMER_CTRL_VAL) | 1, regbase + TIMER_CTRL_VAL);
  82         writel(0, regbase + TIMER_IER_VAL);
  83         return 0;
  84 }
  85 
  86 static struct clock_event_device clockevent = {
  87         .name                   = "vt8500_timer",
  88         .features               = CLOCK_EVT_FEAT_ONESHOT,
  89         .rating                 = 200,
  90         .set_next_event         = vt8500_timer_set_next_event,
  91         .set_state_shutdown     = vt8500_shutdown,
  92         .set_state_oneshot      = vt8500_shutdown,
  93 };
  94 
  95 static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id)
  96 {
  97         struct clock_event_device *evt = dev_id;
  98         writel(0xf, regbase + TIMER_STATUS_VAL);
  99         evt->event_handler(evt);
 100 
 101         return IRQ_HANDLED;
 102 }
 103 
 104 static struct irqaction irq = {
 105         .name    = "vt8500_timer",
 106         .flags   = IRQF_TIMER | IRQF_IRQPOLL,
 107         .handler = vt8500_timer_interrupt,
 108         .dev_id  = &clockevent,
 109 };
 110 
 111 static int __init vt8500_timer_init(struct device_node *np)
 112 {
 113         int timer_irq, ret;
 114 
 115         regbase = of_iomap(np, 0);
 116         if (!regbase) {
 117                 pr_err("%s: Missing iobase description in Device Tree\n",
 118                                                                 __func__);
 119                 return -ENXIO;
 120         }
 121 
 122         timer_irq = irq_of_parse_and_map(np, 0);
 123         if (!timer_irq) {
 124                 pr_err("%s: Missing irq description in Device Tree\n",
 125                                                                 __func__);
 126                 return -EINVAL;
 127         }
 128 
 129         writel(1, regbase + TIMER_CTRL_VAL);
 130         writel(0xf, regbase + TIMER_STATUS_VAL);
 131         writel(~0, regbase + TIMER_MATCH_VAL);
 132 
 133         ret = clocksource_register_hz(&clocksource, VT8500_TIMER_HZ);
 134         if (ret) {
 135                 pr_err("%s: clocksource_register failed for %s\n",
 136                        __func__, clocksource.name);
 137                 return ret;
 138         }
 139 
 140         clockevent.cpumask = cpumask_of(0);
 141 
 142         ret = setup_irq(timer_irq, &irq);
 143         if (ret) {
 144                 pr_err("%s: setup_irq failed for %s\n", __func__,
 145                                                         clockevent.name);
 146                 return ret;
 147         }
 148 
 149         clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
 150                                         MIN_OSCR_DELTA * 2, 0xf0000000);
 151 
 152         return 0;
 153 }
 154 
 155 TIMER_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);

/* [<][>][^][v][top][bottom][index][help] */