linux/drivers/clocksource/rockchip_timer.c
<<
>>
Prefs
   1/*
   2 * Rockchip timer support
   3 *
   4 * Copyright (C) Daniel Lezcano <daniel.lezcano@linaro.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/clk.h>
  11#include <linux/clockchips.h>
  12#include <linux/init.h>
  13#include <linux/interrupt.h>
  14#include <linux/of.h>
  15#include <linux/of_address.h>
  16#include <linux/of_irq.h>
  17
  18#define TIMER_NAME "rk_timer"
  19
  20#define TIMER_LOAD_COUNT0 0x00
  21#define TIMER_LOAD_COUNT1 0x04
  22#define TIMER_CONTROL_REG 0x10
  23#define TIMER_INT_STATUS 0x18
  24
  25#define TIMER_DISABLE 0x0
  26#define TIMER_ENABLE 0x1
  27#define TIMER_MODE_FREE_RUNNING (0 << 1)
  28#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
  29#define TIMER_INT_UNMASK (1 << 2)
  30
  31struct bc_timer {
  32        struct clock_event_device ce;
  33        void __iomem *base;
  34        u32 freq;
  35};
  36
  37static struct bc_timer bc_timer;
  38
  39static inline struct bc_timer *rk_timer(struct clock_event_device *ce)
  40{
  41        return container_of(ce, struct bc_timer, ce);
  42}
  43
  44static inline void __iomem *rk_base(struct clock_event_device *ce)
  45{
  46        return rk_timer(ce)->base;
  47}
  48
  49static inline void rk_timer_disable(struct clock_event_device *ce)
  50{
  51        writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
  52        dsb();
  53}
  54
  55static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
  56{
  57        writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
  58                       rk_base(ce) + TIMER_CONTROL_REG);
  59        dsb();
  60}
  61
  62static void rk_timer_update_counter(unsigned long cycles,
  63                                    struct clock_event_device *ce)
  64{
  65        writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
  66        writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
  67        dsb();
  68}
  69
  70static void rk_timer_interrupt_clear(struct clock_event_device *ce)
  71{
  72        writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
  73        dsb();
  74}
  75
  76static inline int rk_timer_set_next_event(unsigned long cycles,
  77                                          struct clock_event_device *ce)
  78{
  79        rk_timer_disable(ce);
  80        rk_timer_update_counter(cycles, ce);
  81        rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
  82        return 0;
  83}
  84
  85static inline void rk_timer_set_mode(enum clock_event_mode mode,
  86                                     struct clock_event_device *ce)
  87{
  88        switch (mode) {
  89        case CLOCK_EVT_MODE_PERIODIC:
  90                rk_timer_disable(ce);
  91                rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
  92                rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
  93                break;
  94        case CLOCK_EVT_MODE_ONESHOT:
  95        case CLOCK_EVT_MODE_RESUME:
  96                break;
  97        case CLOCK_EVT_MODE_UNUSED:
  98        case CLOCK_EVT_MODE_SHUTDOWN:
  99                rk_timer_disable(ce);
 100                break;
 101        }
 102}
 103
 104static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
 105{
 106        struct clock_event_device *ce = dev_id;
 107
 108        rk_timer_interrupt_clear(ce);
 109
 110        if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
 111                rk_timer_disable(ce);
 112
 113        ce->event_handler(ce);
 114
 115        return IRQ_HANDLED;
 116}
 117
 118static void __init rk_timer_init(struct device_node *np)
 119{
 120        struct clock_event_device *ce = &bc_timer.ce;
 121        struct clk *timer_clk;
 122        struct clk *pclk;
 123        int ret, irq;
 124
 125        bc_timer.base = of_iomap(np, 0);
 126        if (!bc_timer.base) {
 127                pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
 128                return;
 129        }
 130
 131        pclk = of_clk_get_by_name(np, "pclk");
 132        if (IS_ERR(pclk)) {
 133                pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
 134                return;
 135        }
 136
 137        if (clk_prepare_enable(pclk)) {
 138                pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
 139                return;
 140        }
 141
 142        timer_clk = of_clk_get_by_name(np, "timer");
 143        if (IS_ERR(timer_clk)) {
 144                pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
 145                return;
 146        }
 147
 148        if (clk_prepare_enable(timer_clk)) {
 149                pr_err("Failed to enable timer clock\n");
 150                return;
 151        }
 152
 153        bc_timer.freq = clk_get_rate(timer_clk);
 154
 155        irq = irq_of_parse_and_map(np, 0);
 156        if (irq == NO_IRQ) {
 157                pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
 158                return;
 159        }
 160
 161        ce->name = TIMER_NAME;
 162        ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 163        ce->set_next_event = rk_timer_set_next_event;
 164        ce->set_mode = rk_timer_set_mode;
 165        ce->irq = irq;
 166        ce->cpumask = cpumask_of(0);
 167        ce->rating = 250;
 168
 169        rk_timer_interrupt_clear(ce);
 170        rk_timer_disable(ce);
 171
 172        ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
 173        if (ret) {
 174                pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
 175                return;
 176        }
 177
 178        clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
 179}
 180CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
 181