linux/drivers/clocksource/timer-prima2.c
<<
>>
Prefs
   1/*
   2 * System timer for CSR SiRFprimaII
   3 *
   4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
   5 *
   6 * Licensed under GPLv2 or later.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/interrupt.h>
  11#include <linux/clockchips.h>
  12#include <linux/clocksource.h>
  13#include <linux/bitops.h>
  14#include <linux/irq.h>
  15#include <linux/clk.h>
  16#include <linux/err.h>
  17#include <linux/slab.h>
  18#include <linux/of.h>
  19#include <linux/of_irq.h>
  20#include <linux/of_address.h>
  21#include <linux/sched_clock.h>
  22
  23#define PRIMA2_CLOCK_FREQ 1000000
  24
  25#define SIRFSOC_TIMER_COUNTER_LO        0x0000
  26#define SIRFSOC_TIMER_COUNTER_HI        0x0004
  27#define SIRFSOC_TIMER_MATCH_0           0x0008
  28#define SIRFSOC_TIMER_MATCH_1           0x000C
  29#define SIRFSOC_TIMER_MATCH_2           0x0010
  30#define SIRFSOC_TIMER_MATCH_3           0x0014
  31#define SIRFSOC_TIMER_MATCH_4           0x0018
  32#define SIRFSOC_TIMER_MATCH_5           0x001C
  33#define SIRFSOC_TIMER_STATUS            0x0020
  34#define SIRFSOC_TIMER_INT_EN            0x0024
  35#define SIRFSOC_TIMER_WATCHDOG_EN       0x0028
  36#define SIRFSOC_TIMER_DIV               0x002C
  37#define SIRFSOC_TIMER_LATCH             0x0030
  38#define SIRFSOC_TIMER_LATCHED_LO        0x0034
  39#define SIRFSOC_TIMER_LATCHED_HI        0x0038
  40
  41#define SIRFSOC_TIMER_WDT_INDEX         5
  42
  43#define SIRFSOC_TIMER_LATCH_BIT  BIT(0)
  44
  45#define SIRFSOC_TIMER_REG_CNT 11
  46
  47static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
  48        SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2,
  49        SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5,
  50        SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV,
  51        SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI,
  52};
  53
  54static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
  55
  56static void __iomem *sirfsoc_timer_base;
  57
  58/* timer0 interrupt handler */
  59static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
  60{
  61        struct clock_event_device *ce = dev_id;
  62
  63        WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) &
  64                BIT(0)));
  65
  66        /* clear timer0 interrupt */
  67        writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
  68
  69        ce->event_handler(ce);
  70
  71        return IRQ_HANDLED;
  72}
  73
  74/* read 64-bit timer counter */
  75static u64 notrace sirfsoc_timer_read(struct clocksource *cs)
  76{
  77        u64 cycles;
  78
  79        /* latch the 64-bit timer counter */
  80        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
  81                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
  82        cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
  83        cycles = (cycles << 32) |
  84                readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
  85
  86        return cycles;
  87}
  88
  89static int sirfsoc_timer_set_next_event(unsigned long delta,
  90        struct clock_event_device *ce)
  91{
  92        unsigned long now, next;
  93
  94        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
  95                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
  96        now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
  97        next = now + delta;
  98        writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
  99        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
 100                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 101        now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 102
 103        return next - now > delta ? -ETIME : 0;
 104}
 105
 106static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
 107{
 108        u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 109
 110        writel_relaxed(val & ~BIT(0),
 111                       sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 112        return 0;
 113}
 114
 115static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt)
 116{
 117        u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 118
 119        writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 120        return 0;
 121}
 122
 123static void sirfsoc_clocksource_suspend(struct clocksource *cs)
 124{
 125        int i;
 126
 127        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
 128                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 129
 130        for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
 131                sirfsoc_timer_reg_val[i] =
 132                        readl_relaxed(sirfsoc_timer_base +
 133                                sirfsoc_timer_reg_list[i]);
 134}
 135
 136static void sirfsoc_clocksource_resume(struct clocksource *cs)
 137{
 138        int i;
 139
 140        for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
 141                writel_relaxed(sirfsoc_timer_reg_val[i],
 142                        sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
 143
 144        writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
 145                sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
 146        writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
 147                sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
 148}
 149
 150static struct clock_event_device sirfsoc_clockevent = {
 151        .name = "sirfsoc_clockevent",
 152        .rating = 200,
 153        .features = CLOCK_EVT_FEAT_ONESHOT,
 154        .set_state_shutdown = sirfsoc_timer_shutdown,
 155        .set_state_oneshot = sirfsoc_timer_set_oneshot,
 156        .set_next_event = sirfsoc_timer_set_next_event,
 157};
 158
 159static struct clocksource sirfsoc_clocksource = {
 160        .name = "sirfsoc_clocksource",
 161        .rating = 200,
 162        .mask = CLOCKSOURCE_MASK(64),
 163        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 164        .read = sirfsoc_timer_read,
 165        .suspend = sirfsoc_clocksource_suspend,
 166        .resume = sirfsoc_clocksource_resume,
 167};
 168
 169static struct irqaction sirfsoc_timer_irq = {
 170        .name = "sirfsoc_timer0",
 171        .flags = IRQF_TIMER,
 172        .irq = 0,
 173        .handler = sirfsoc_timer_interrupt,
 174        .dev_id = &sirfsoc_clockevent,
 175};
 176
 177/* Overwrite weak default sched_clock with more precise one */
 178static u64 notrace sirfsoc_read_sched_clock(void)
 179{
 180        return sirfsoc_timer_read(NULL);
 181}
 182
 183static void __init sirfsoc_clockevent_init(void)
 184{
 185        sirfsoc_clockevent.cpumask = cpumask_of(0);
 186        clockevents_config_and_register(&sirfsoc_clockevent, PRIMA2_CLOCK_FREQ,
 187                                        2, -2);
 188}
 189
 190/* initialize the kernel jiffy timer source */
 191static int __init sirfsoc_prima2_timer_init(struct device_node *np)
 192{
 193        unsigned long rate;
 194        struct clk *clk;
 195        int ret;
 196
 197        clk = of_clk_get(np, 0);
 198        if (IS_ERR(clk)) {
 199                pr_err("Failed to get clock\n");
 200                return PTR_ERR(clk);
 201        }
 202
 203        ret = clk_prepare_enable(clk);
 204        if (ret) {
 205                pr_err("Failed to enable clock\n");
 206                return ret;
 207        }
 208
 209        rate = clk_get_rate(clk);
 210
 211        if (rate < PRIMA2_CLOCK_FREQ || rate % PRIMA2_CLOCK_FREQ) {
 212                pr_err("Invalid clock rate\n");
 213                return -EINVAL;
 214        }
 215
 216        sirfsoc_timer_base = of_iomap(np, 0);
 217        if (!sirfsoc_timer_base) {
 218                pr_err("unable to map timer cpu registers\n");
 219                return -ENXIO;
 220        }
 221
 222        sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
 223
 224        writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1,
 225                sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
 226        writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
 227        writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
 228        writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
 229
 230        ret = clocksource_register_hz(&sirfsoc_clocksource, PRIMA2_CLOCK_FREQ);
 231        if (ret) {
 232                pr_err("Failed to register clocksource\n");
 233                return ret;
 234        }
 235
 236        sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ);
 237
 238        ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
 239        if (ret) {
 240                pr_err("Failed to setup irq\n");
 241                return ret;
 242        }
 243
 244        sirfsoc_clockevent_init();
 245
 246        return 0;
 247}
 248TIMER_OF_DECLARE(sirfsoc_prima2_timer,
 249        "sirf,prima2-tick", sirfsoc_prima2_timer_init);
 250