linux/drivers/clocksource/moxart_timer.c
<<
>>
Prefs
   1/*
   2 * MOXA ART SoCs timer handling.
   3 *
   4 * Copyright (C) 2013 Jonas Jensen
   5 *
   6 * Jonas Jensen <jonas.jensen@gmail.com>
   7 *
   8 * This file is licensed under the terms of the GNU General Public
   9 * License version 2.  This program is licensed "as is" without any
  10 * warranty of any kind, whether express or implied.
  11 */
  12
  13#include <linux/clk.h>
  14#include <linux/clockchips.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/irqreturn.h>
  18#include <linux/of.h>
  19#include <linux/of_address.h>
  20#include <linux/of_irq.h>
  21#include <linux/io.h>
  22#include <linux/clocksource.h>
  23#include <linux/bitops.h>
  24#include <linux/slab.h>
  25
  26#define TIMER1_BASE             0x00
  27#define TIMER2_BASE             0x10
  28#define TIMER3_BASE             0x20
  29
  30#define REG_COUNT               0x0 /* writable */
  31#define REG_LOAD                0x4
  32#define REG_MATCH1              0x8
  33#define REG_MATCH2              0xC
  34
  35#define TIMER_CR                0x30
  36#define TIMER_INTR_STATE        0x34
  37#define TIMER_INTR_MASK         0x38
  38
  39/*
  40 * Moxart TIMER_CR flags:
  41 *
  42 * MOXART_CR_*_CLOCK    0: PCLK, 1: EXT1CLK
  43 * MOXART_CR_*_INT      overflow interrupt enable bit
  44 */
  45#define MOXART_CR_1_ENABLE      BIT(0)
  46#define MOXART_CR_1_CLOCK       BIT(1)
  47#define MOXART_CR_1_INT BIT(2)
  48#define MOXART_CR_2_ENABLE      BIT(3)
  49#define MOXART_CR_2_CLOCK       BIT(4)
  50#define MOXART_CR_2_INT BIT(5)
  51#define MOXART_CR_3_ENABLE      BIT(6)
  52#define MOXART_CR_3_CLOCK       BIT(7)
  53#define MOXART_CR_3_INT BIT(8)
  54#define MOXART_CR_COUNT_UP      BIT(9)
  55
  56#define MOXART_TIMER1_ENABLE    (MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE)
  57#define MOXART_TIMER1_DISABLE   (MOXART_CR_2_ENABLE)
  58
  59/*
  60 * The ASpeed variant of the IP block has a different layout
  61 * for the control register
  62 */
  63#define ASPEED_CR_1_ENABLE      BIT(0)
  64#define ASPEED_CR_1_CLOCK       BIT(1)
  65#define ASPEED_CR_1_INT         BIT(2)
  66#define ASPEED_CR_2_ENABLE      BIT(4)
  67#define ASPEED_CR_2_CLOCK       BIT(5)
  68#define ASPEED_CR_2_INT         BIT(6)
  69#define ASPEED_CR_3_ENABLE      BIT(8)
  70#define ASPEED_CR_3_CLOCK       BIT(9)
  71#define ASPEED_CR_3_INT         BIT(10)
  72
  73#define ASPEED_TIMER1_ENABLE   (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE)
  74#define ASPEED_TIMER1_DISABLE  (ASPEED_CR_2_ENABLE)
  75
  76struct moxart_timer {
  77        void __iomem *base;
  78        unsigned int t1_disable_val;
  79        unsigned int t1_enable_val;
  80        unsigned int count_per_tick;
  81        struct clock_event_device clkevt;
  82};
  83
  84static inline struct moxart_timer *to_moxart(struct clock_event_device *evt)
  85{
  86        return container_of(evt, struct moxart_timer, clkevt);
  87}
  88
  89static inline void moxart_disable(struct clock_event_device *evt)
  90{
  91        struct moxart_timer *timer = to_moxart(evt);
  92
  93        writel(timer->t1_disable_val, timer->base + TIMER_CR);
  94}
  95
  96static inline void moxart_enable(struct clock_event_device *evt)
  97{
  98        struct moxart_timer *timer = to_moxart(evt);
  99
 100        writel(timer->t1_enable_val, timer->base + TIMER_CR);
 101}
 102
 103static int moxart_shutdown(struct clock_event_device *evt)
 104{
 105        moxart_disable(evt);
 106        return 0;
 107}
 108
 109static int moxart_set_oneshot(struct clock_event_device *evt)
 110{
 111        moxart_disable(evt);
 112        writel(~0, to_moxart(evt)->base + TIMER1_BASE + REG_LOAD);
 113        return 0;
 114}
 115
 116static int moxart_set_periodic(struct clock_event_device *evt)
 117{
 118        struct moxart_timer *timer = to_moxart(evt);
 119
 120        moxart_disable(evt);
 121        writel(timer->count_per_tick, timer->base + TIMER1_BASE + REG_LOAD);
 122        writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
 123        moxart_enable(evt);
 124        return 0;
 125}
 126
 127static int moxart_clkevt_next_event(unsigned long cycles,
 128                                    struct clock_event_device *evt)
 129{
 130        struct moxart_timer *timer = to_moxart(evt);
 131        u32 u;
 132
 133        moxart_disable(evt);
 134
 135        u = readl(timer->base + TIMER1_BASE + REG_COUNT) - cycles;
 136        writel(u, timer->base + TIMER1_BASE + REG_MATCH1);
 137
 138        moxart_enable(evt);
 139
 140        return 0;
 141}
 142
 143static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
 144{
 145        struct clock_event_device *evt = dev_id;
 146        evt->event_handler(evt);
 147        return IRQ_HANDLED;
 148}
 149
 150static int __init moxart_timer_init(struct device_node *node)
 151{
 152        int ret, irq;
 153        unsigned long pclk;
 154        struct clk *clk;
 155        struct moxart_timer *timer;
 156
 157        timer = kzalloc(sizeof(*timer), GFP_KERNEL);
 158        if (!timer)
 159                return -ENOMEM;
 160
 161        timer->base = of_iomap(node, 0);
 162        if (!timer->base) {
 163                pr_err("%s: of_iomap failed\n", node->full_name);
 164                return -ENXIO;
 165        }
 166
 167        irq = irq_of_parse_and_map(node, 0);
 168        if (irq <= 0) {
 169                pr_err("%s: irq_of_parse_and_map failed\n", node->full_name);
 170                return -EINVAL;
 171        }
 172
 173        clk = of_clk_get(node, 0);
 174        if (IS_ERR(clk))  {
 175                pr_err("%s: of_clk_get failed\n", node->full_name);
 176                return PTR_ERR(clk);
 177        }
 178
 179        pclk = clk_get_rate(clk);
 180
 181        if (of_device_is_compatible(node, "moxa,moxart-timer")) {
 182                timer->t1_enable_val = MOXART_TIMER1_ENABLE;
 183                timer->t1_disable_val = MOXART_TIMER1_DISABLE;
 184        } else if (of_device_is_compatible(node, "aspeed,ast2400-timer")) {
 185                timer->t1_enable_val = ASPEED_TIMER1_ENABLE;
 186                timer->t1_disable_val = ASPEED_TIMER1_DISABLE;
 187        } else {
 188                pr_err("%s: unknown platform\n", node->full_name);
 189                return -EINVAL;
 190        }
 191
 192        timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
 193
 194        timer->clkevt.name = node->name;
 195        timer->clkevt.rating = 200;
 196        timer->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
 197                                        CLOCK_EVT_FEAT_ONESHOT;
 198        timer->clkevt.set_state_shutdown = moxart_shutdown;
 199        timer->clkevt.set_state_periodic = moxart_set_periodic;
 200        timer->clkevt.set_state_oneshot = moxart_set_oneshot;
 201        timer->clkevt.tick_resume = moxart_set_oneshot;
 202        timer->clkevt.set_next_event = moxart_clkevt_next_event;
 203        timer->clkevt.cpumask = cpumask_of(0);
 204        timer->clkevt.irq = irq;
 205
 206        ret = clocksource_mmio_init(timer->base + TIMER2_BASE + REG_COUNT,
 207                                    "moxart_timer", pclk, 200, 32,
 208                                    clocksource_mmio_readl_down);
 209        if (ret) {
 210                pr_err("%s: clocksource_mmio_init failed\n", node->full_name);
 211                return ret;
 212        }
 213
 214        ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER,
 215                          node->name, &timer->clkevt);
 216        if (ret) {
 217                pr_err("%s: setup_irq failed\n", node->full_name);
 218                return ret;
 219        }
 220
 221        /* Clear match registers */
 222        writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
 223        writel(0, timer->base + TIMER1_BASE + REG_MATCH2);
 224        writel(0, timer->base + TIMER2_BASE + REG_MATCH1);
 225        writel(0, timer->base + TIMER2_BASE + REG_MATCH2);
 226
 227        /*
 228         * Start timer 2 rolling as our main wall clock source, keep timer 1
 229         * disabled
 230         */
 231        writel(0, timer->base + TIMER_CR);
 232        writel(~0, timer->base + TIMER2_BASE + REG_LOAD);
 233        writel(timer->t1_disable_val, timer->base + TIMER_CR);
 234
 235        /*
 236         * documentation is not publicly available:
 237         * min_delta / max_delta obtained by trial-and-error,
 238         * max_delta 0xfffffffe should be ok because count
 239         * register size is u32
 240         */
 241        clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe);
 242
 243        return 0;
 244}
 245CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
 246CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init);
 247