linux/drivers/clocksource/timer-sun5i.c
<<
>>
Prefs
   1/*
   2 * Allwinner SoCs hstimer driver.
   3 *
   4 * Copyright (C) 2013 Maxime Ripard
   5 *
   6 * Maxime Ripard <maxime.ripard@free-electrons.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/clocksource.h>
  16#include <linux/delay.h>
  17#include <linux/interrupt.h>
  18#include <linux/irq.h>
  19#include <linux/irqreturn.h>
  20#include <linux/reset.h>
  21#include <linux/slab.h>
  22#include <linux/of.h>
  23#include <linux/of_address.h>
  24#include <linux/of_irq.h>
  25
  26#define TIMER_IRQ_EN_REG                0x00
  27#define TIMER_IRQ_EN(val)                       BIT(val)
  28#define TIMER_IRQ_ST_REG                0x04
  29#define TIMER_CTL_REG(val)              (0x20 * (val) + 0x10)
  30#define TIMER_CTL_ENABLE                        BIT(0)
  31#define TIMER_CTL_RELOAD                        BIT(1)
  32#define TIMER_CTL_CLK_PRES(val)                 (((val) & 0x7) << 4)
  33#define TIMER_CTL_ONESHOT                       BIT(7)
  34#define TIMER_INTVAL_LO_REG(val)        (0x20 * (val) + 0x14)
  35#define TIMER_INTVAL_HI_REG(val)        (0x20 * (val) + 0x18)
  36#define TIMER_CNTVAL_LO_REG(val)        (0x20 * (val) + 0x1c)
  37#define TIMER_CNTVAL_HI_REG(val)        (0x20 * (val) + 0x20)
  38
  39#define TIMER_SYNC_TICKS        3
  40
  41struct sun5i_timer {
  42        void __iomem            *base;
  43        struct clk              *clk;
  44        struct notifier_block   clk_rate_cb;
  45        u32                     ticks_per_jiffy;
  46};
  47
  48#define to_sun5i_timer(x) \
  49        container_of(x, struct sun5i_timer, clk_rate_cb)
  50
  51struct sun5i_timer_clksrc {
  52        struct sun5i_timer      timer;
  53        struct clocksource      clksrc;
  54};
  55
  56#define to_sun5i_timer_clksrc(x) \
  57        container_of(x, struct sun5i_timer_clksrc, clksrc)
  58
  59struct sun5i_timer_clkevt {
  60        struct sun5i_timer              timer;
  61        struct clock_event_device       clkevt;
  62};
  63
  64#define to_sun5i_timer_clkevt(x) \
  65        container_of(x, struct sun5i_timer_clkevt, clkevt)
  66
  67/*
  68 * When we disable a timer, we need to wait at least for 2 cycles of
  69 * the timer source clock. We will use for that the clocksource timer
  70 * that is already setup and runs at the same frequency than the other
  71 * timers, and we never will be disabled.
  72 */
  73static void sun5i_clkevt_sync(struct sun5i_timer_clkevt *ce)
  74{
  75        u32 old = readl(ce->timer.base + TIMER_CNTVAL_LO_REG(1));
  76
  77        while ((old - readl(ce->timer.base + TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS)
  78                cpu_relax();
  79}
  80
  81static void sun5i_clkevt_time_stop(struct sun5i_timer_clkevt *ce, u8 timer)
  82{
  83        u32 val = readl(ce->timer.base + TIMER_CTL_REG(timer));
  84        writel(val & ~TIMER_CTL_ENABLE, ce->timer.base + TIMER_CTL_REG(timer));
  85
  86        sun5i_clkevt_sync(ce);
  87}
  88
  89static void sun5i_clkevt_time_setup(struct sun5i_timer_clkevt *ce, u8 timer, u32 delay)
  90{
  91        writel(delay, ce->timer.base + TIMER_INTVAL_LO_REG(timer));
  92}
  93
  94static void sun5i_clkevt_time_start(struct sun5i_timer_clkevt *ce, u8 timer, bool periodic)
  95{
  96        u32 val = readl(ce->timer.base + TIMER_CTL_REG(timer));
  97
  98        if (periodic)
  99                val &= ~TIMER_CTL_ONESHOT;
 100        else
 101                val |= TIMER_CTL_ONESHOT;
 102
 103        writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
 104               ce->timer.base + TIMER_CTL_REG(timer));
 105}
 106
 107static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt)
 108{
 109        struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
 110
 111        sun5i_clkevt_time_stop(ce, 0);
 112        return 0;
 113}
 114
 115static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt)
 116{
 117        struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
 118
 119        sun5i_clkevt_time_stop(ce, 0);
 120        sun5i_clkevt_time_start(ce, 0, false);
 121        return 0;
 122}
 123
 124static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt)
 125{
 126        struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
 127
 128        sun5i_clkevt_time_stop(ce, 0);
 129        sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy);
 130        sun5i_clkevt_time_start(ce, 0, true);
 131        return 0;
 132}
 133
 134static int sun5i_clkevt_next_event(unsigned long evt,
 135                                   struct clock_event_device *clkevt)
 136{
 137        struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
 138
 139        sun5i_clkevt_time_stop(ce, 0);
 140        sun5i_clkevt_time_setup(ce, 0, evt - TIMER_SYNC_TICKS);
 141        sun5i_clkevt_time_start(ce, 0, false);
 142
 143        return 0;
 144}
 145
 146static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
 147{
 148        struct sun5i_timer_clkevt *ce = (struct sun5i_timer_clkevt *)dev_id;
 149
 150        writel(0x1, ce->timer.base + TIMER_IRQ_ST_REG);
 151        ce->clkevt.event_handler(&ce->clkevt);
 152
 153        return IRQ_HANDLED;
 154}
 155
 156static u64 sun5i_clksrc_read(struct clocksource *clksrc)
 157{
 158        struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
 159
 160        return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1));
 161}
 162
 163static int sun5i_rate_cb_clksrc(struct notifier_block *nb,
 164                                unsigned long event, void *data)
 165{
 166        struct clk_notifier_data *ndata = data;
 167        struct sun5i_timer *timer = to_sun5i_timer(nb);
 168        struct sun5i_timer_clksrc *cs = container_of(timer, struct sun5i_timer_clksrc, timer);
 169
 170        switch (event) {
 171        case PRE_RATE_CHANGE:
 172                clocksource_unregister(&cs->clksrc);
 173                break;
 174
 175        case POST_RATE_CHANGE:
 176                clocksource_register_hz(&cs->clksrc, ndata->new_rate);
 177                break;
 178
 179        default:
 180                break;
 181        }
 182
 183        return NOTIFY_DONE;
 184}
 185
 186static int __init sun5i_setup_clocksource(struct device_node *node,
 187                                          void __iomem *base,
 188                                          struct clk *clk, int irq)
 189{
 190        struct sun5i_timer_clksrc *cs;
 191        unsigned long rate;
 192        int ret;
 193
 194        cs = kzalloc(sizeof(*cs), GFP_KERNEL);
 195        if (!cs)
 196                return -ENOMEM;
 197
 198        ret = clk_prepare_enable(clk);
 199        if (ret) {
 200                pr_err("Couldn't enable parent clock\n");
 201                goto err_free;
 202        }
 203
 204        rate = clk_get_rate(clk);
 205        if (!rate) {
 206                pr_err("Couldn't get parent clock rate\n");
 207                ret = -EINVAL;
 208                goto err_disable_clk;
 209        }
 210
 211        cs->timer.base = base;
 212        cs->timer.clk = clk;
 213        cs->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clksrc;
 214        cs->timer.clk_rate_cb.next = NULL;
 215
 216        ret = clk_notifier_register(clk, &cs->timer.clk_rate_cb);
 217        if (ret) {
 218                pr_err("Unable to register clock notifier.\n");
 219                goto err_disable_clk;
 220        }
 221
 222        writel(~0, base + TIMER_INTVAL_LO_REG(1));
 223        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
 224               base + TIMER_CTL_REG(1));
 225
 226        cs->clksrc.name = node->name;
 227        cs->clksrc.rating = 340;
 228        cs->clksrc.read = sun5i_clksrc_read;
 229        cs->clksrc.mask = CLOCKSOURCE_MASK(32);
 230        cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
 231
 232        ret = clocksource_register_hz(&cs->clksrc, rate);
 233        if (ret) {
 234                pr_err("Couldn't register clock source.\n");
 235                goto err_remove_notifier;
 236        }
 237
 238        return 0;
 239
 240err_remove_notifier:
 241        clk_notifier_unregister(clk, &cs->timer.clk_rate_cb);
 242err_disable_clk:
 243        clk_disable_unprepare(clk);
 244err_free:
 245        kfree(cs);
 246        return ret;
 247}
 248
 249static int sun5i_rate_cb_clkevt(struct notifier_block *nb,
 250                                unsigned long event, void *data)
 251{
 252        struct clk_notifier_data *ndata = data;
 253        struct sun5i_timer *timer = to_sun5i_timer(nb);
 254        struct sun5i_timer_clkevt *ce = container_of(timer, struct sun5i_timer_clkevt, timer);
 255
 256        if (event == POST_RATE_CHANGE) {
 257                clockevents_update_freq(&ce->clkevt, ndata->new_rate);
 258                ce->timer.ticks_per_jiffy = DIV_ROUND_UP(ndata->new_rate, HZ);
 259        }
 260
 261        return NOTIFY_DONE;
 262}
 263
 264static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem *base,
 265                                         struct clk *clk, int irq)
 266{
 267        struct sun5i_timer_clkevt *ce;
 268        unsigned long rate;
 269        int ret;
 270        u32 val;
 271
 272        ce = kzalloc(sizeof(*ce), GFP_KERNEL);
 273        if (!ce)
 274                return -ENOMEM;
 275
 276        ret = clk_prepare_enable(clk);
 277        if (ret) {
 278                pr_err("Couldn't enable parent clock\n");
 279                goto err_free;
 280        }
 281
 282        rate = clk_get_rate(clk);
 283        if (!rate) {
 284                pr_err("Couldn't get parent clock rate\n");
 285                ret = -EINVAL;
 286                goto err_disable_clk;
 287        }
 288
 289        ce->timer.base = base;
 290        ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 291        ce->timer.clk = clk;
 292        ce->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clkevt;
 293        ce->timer.clk_rate_cb.next = NULL;
 294
 295        ret = clk_notifier_register(clk, &ce->timer.clk_rate_cb);
 296        if (ret) {
 297                pr_err("Unable to register clock notifier.\n");
 298                goto err_disable_clk;
 299        }
 300
 301        ce->clkevt.name = node->name;
 302        ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 303        ce->clkevt.set_next_event = sun5i_clkevt_next_event;
 304        ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown;
 305        ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic;
 306        ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot;
 307        ce->clkevt.tick_resume = sun5i_clkevt_shutdown;
 308        ce->clkevt.rating = 340;
 309        ce->clkevt.irq = irq;
 310        ce->clkevt.cpumask = cpu_possible_mask;
 311
 312        /* Enable timer0 interrupt */
 313        val = readl(base + TIMER_IRQ_EN_REG);
 314        writel(val | TIMER_IRQ_EN(0), base + TIMER_IRQ_EN_REG);
 315
 316        clockevents_config_and_register(&ce->clkevt, rate,
 317                                        TIMER_SYNC_TICKS, 0xffffffff);
 318
 319        ret = request_irq(irq, sun5i_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 320                          "sun5i_timer0", ce);
 321        if (ret) {
 322                pr_err("Unable to register interrupt\n");
 323                goto err_remove_notifier;
 324        }
 325
 326        return 0;
 327
 328err_remove_notifier:
 329        clk_notifier_unregister(clk, &ce->timer.clk_rate_cb);
 330err_disable_clk:
 331        clk_disable_unprepare(clk);
 332err_free:
 333        kfree(ce);
 334        return ret;
 335}
 336
 337static int __init sun5i_timer_init(struct device_node *node)
 338{
 339        struct reset_control *rstc;
 340        void __iomem *timer_base;
 341        struct clk *clk;
 342        int irq, ret;
 343
 344        timer_base = of_io_request_and_map(node, 0, of_node_full_name(node));
 345        if (IS_ERR(timer_base)) {
 346                pr_err("Can't map registers\n");
 347                return PTR_ERR(timer_base);
 348        }
 349
 350        irq = irq_of_parse_and_map(node, 0);
 351        if (irq <= 0) {
 352                pr_err("Can't parse IRQ\n");
 353                return -EINVAL;
 354        }
 355
 356        clk = of_clk_get(node, 0);
 357        if (IS_ERR(clk)) {
 358                pr_err("Can't get timer clock\n");
 359                return PTR_ERR(clk);
 360        }
 361
 362        rstc = of_reset_control_get(node, NULL);
 363        if (!IS_ERR(rstc))
 364                reset_control_deassert(rstc);
 365
 366        ret = sun5i_setup_clocksource(node, timer_base, clk, irq);
 367        if (ret)
 368                return ret;
 369
 370        return sun5i_setup_clockevent(node, timer_base, clk, irq);
 371}
 372TIMER_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
 373                           sun5i_timer_init);
 374TIMER_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
 375                           sun5i_timer_init);
 376