linux/drivers/clocksource/h8300_timer8.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/h8300/kernel/cpu/timer/timer8.c
   3 *
   4 *  Yoshinori Sato <ysato@users.sourcefoge.jp>
   5 *
   6 *  8bit Timer driver
   7 *
   8 */
   9
  10#include <linux/errno.h>
  11#include <linux/kernel.h>
  12#include <linux/interrupt.h>
  13#include <linux/init.h>
  14#include <linux/clockchips.h>
  15#include <linux/clk.h>
  16#include <linux/io.h>
  17#include <linux/of.h>
  18#include <linux/of_address.h>
  19#include <linux/of_irq.h>
  20
  21#define _8TCR   0
  22#define _8TCSR  2
  23#define TCORA   4
  24#define TCORB   6
  25#define _8TCNT  8
  26
  27#define CMIEA   6
  28#define CMFA    6
  29
  30#define FLAG_STARTED (1 << 3)
  31
  32#define SCALE 64
  33
  34#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
  35#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
  36
  37struct timer8_priv {
  38        struct clock_event_device ced;
  39        void __iomem *mapbase;
  40        unsigned long flags;
  41        unsigned int rate;
  42};
  43
  44static irqreturn_t timer8_interrupt(int irq, void *dev_id)
  45{
  46        struct timer8_priv *p = dev_id;
  47
  48        if (clockevent_state_oneshot(&p->ced))
  49                iowrite16be(0x0000, p->mapbase + _8TCR);
  50
  51        p->ced.event_handler(&p->ced);
  52
  53        bclr(CMFA, p->mapbase + _8TCSR);
  54
  55        return IRQ_HANDLED;
  56}
  57
  58static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
  59{
  60        if (delta >= 0x10000)
  61                pr_warn("delta out of range\n");
  62        bclr(CMIEA, p->mapbase + _8TCR);
  63        iowrite16be(delta, p->mapbase + TCORA);
  64        iowrite16be(0x0000, p->mapbase + _8TCNT);
  65        bclr(CMFA, p->mapbase + _8TCSR);
  66        bset(CMIEA, p->mapbase + _8TCR);
  67}
  68
  69static int timer8_enable(struct timer8_priv *p)
  70{
  71        iowrite16be(0xffff, p->mapbase + TCORA);
  72        iowrite16be(0x0000, p->mapbase + _8TCNT);
  73        iowrite16be(0x0c02, p->mapbase + _8TCR);
  74
  75        return 0;
  76}
  77
  78static int timer8_start(struct timer8_priv *p)
  79{
  80        int ret;
  81
  82        if ((p->flags & FLAG_STARTED))
  83                return 0;
  84
  85        ret = timer8_enable(p);
  86        if (!ret)
  87                p->flags |= FLAG_STARTED;
  88
  89        return ret;
  90}
  91
  92static void timer8_stop(struct timer8_priv *p)
  93{
  94        iowrite16be(0x0000, p->mapbase + _8TCR);
  95}
  96
  97static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
  98{
  99        return container_of(ced, struct timer8_priv, ced);
 100}
 101
 102static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
 103{
 104        timer8_start(p);
 105        timer8_set_next(p, delta);
 106}
 107
 108static int timer8_clock_event_shutdown(struct clock_event_device *ced)
 109{
 110        timer8_stop(ced_to_priv(ced));
 111        return 0;
 112}
 113
 114static int timer8_clock_event_periodic(struct clock_event_device *ced)
 115{
 116        struct timer8_priv *p = ced_to_priv(ced);
 117
 118        pr_info("%s: used for periodic clock events\n", ced->name);
 119        timer8_stop(p);
 120        timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
 121
 122        return 0;
 123}
 124
 125static int timer8_clock_event_oneshot(struct clock_event_device *ced)
 126{
 127        struct timer8_priv *p = ced_to_priv(ced);
 128
 129        pr_info("%s: used for oneshot clock events\n", ced->name);
 130        timer8_stop(p);
 131        timer8_clock_event_start(p, 0x10000);
 132
 133        return 0;
 134}
 135
 136static int timer8_clock_event_next(unsigned long delta,
 137                                   struct clock_event_device *ced)
 138{
 139        struct timer8_priv *p = ced_to_priv(ced);
 140
 141        BUG_ON(!clockevent_state_oneshot(ced));
 142        timer8_set_next(p, delta - 1);
 143
 144        return 0;
 145}
 146
 147static struct timer8_priv timer8_priv = {
 148        .ced = {
 149                .name = "h8300_8timer",
 150                .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 151                .rating = 200,
 152                .set_next_event = timer8_clock_event_next,
 153                .set_state_shutdown = timer8_clock_event_shutdown,
 154                .set_state_periodic = timer8_clock_event_periodic,
 155                .set_state_oneshot = timer8_clock_event_oneshot,
 156        },
 157};
 158
 159static int __init h8300_8timer_init(struct device_node *node)
 160{
 161        void __iomem *base;
 162        int irq, ret;
 163        struct clk *clk;
 164
 165        clk = of_clk_get(node, 0);
 166        if (IS_ERR(clk)) {
 167                pr_err("failed to get clock for clockevent\n");
 168                return PTR_ERR(clk);
 169        }
 170
 171        ret = ENXIO;
 172        base = of_iomap(node, 0);
 173        if (!base) {
 174                pr_err("failed to map registers for clockevent\n");
 175                goto free_clk;
 176        }
 177
 178        ret = -EINVAL;
 179        irq = irq_of_parse_and_map(node, 0);
 180        if (!irq) {
 181                pr_err("failed to get irq for clockevent\n");
 182                goto unmap_reg;
 183        }
 184
 185        timer8_priv.mapbase = base;
 186
 187        timer8_priv.rate = clk_get_rate(clk) / SCALE;
 188        if (!timer8_priv.rate) {
 189                pr_err("Failed to get rate for the clocksource\n");
 190                goto unmap_reg;
 191        }
 192
 193        if (request_irq(irq, timer8_interrupt, IRQF_TIMER,
 194                        timer8_priv.ced.name, &timer8_priv) < 0) {
 195                pr_err("failed to request irq %d for clockevent\n", irq);
 196                goto unmap_reg;
 197        }
 198
 199        clockevents_config_and_register(&timer8_priv.ced,
 200                                        timer8_priv.rate, 1, 0x0000ffff);
 201
 202        return 0;
 203unmap_reg:
 204        iounmap(base);
 205free_clk:
 206        clk_put(clk);
 207        return ret;
 208}
 209
 210CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
 211