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