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
 206        cs->timer.base = base;
 207        cs->timer.clk = clk;
 208        cs->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clksrc;
 209        cs->timer.clk_rate_cb.next = NULL;
 210
 211        ret = clk_notifier_register(clk, &cs->timer.clk_rate_cb);
 212        if (ret) {
 213                pr_err("Unable to register clock notifier.\n");
 214                goto err_disable_clk;
 215        }
 216
 217        writel(~0, base + TIMER_INTVAL_LO_REG(1));
 218        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
 219               base + TIMER_CTL_REG(1));
 220
 221        cs->clksrc.name = node->name;
 222        cs->clksrc.rating = 340;
 223        cs->clksrc.read = sun5i_clksrc_read;
 224        cs->clksrc.mask = CLOCKSOURCE_MASK(32);
 225        cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
 226
 227        ret = clocksource_register_hz(&cs->clksrc, rate);
 228        if (ret) {
 229                pr_err("Couldn't register clock source.\n");
 230                goto err_remove_notifier;
 231        }
 232
 233        return 0;
 234
 235err_remove_notifier:
 236        clk_notifier_unregister(clk, &cs->timer.clk_rate_cb);
 237err_disable_clk:
 238        clk_disable_unprepare(clk);
 239err_free:
 240        kfree(cs);
 241        return ret;
 242}
 243
 244static int sun5i_rate_cb_clkevt(struct notifier_block *nb,
 245                                unsigned long event, void *data)
 246{
 247        struct clk_notifier_data *ndata = data;
 248        struct sun5i_timer *timer = to_sun5i_timer(nb);
 249        struct sun5i_timer_clkevt *ce = container_of(timer, struct sun5i_timer_clkevt, timer);
 250
 251        if (event == POST_RATE_CHANGE) {
 252                clockevents_update_freq(&ce->clkevt, ndata->new_rate);
 253                ce->timer.ticks_per_jiffy = DIV_ROUND_UP(ndata->new_rate, HZ);
 254        }
 255
 256        return NOTIFY_DONE;
 257}
 258
 259static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem *base,
 260                                         struct clk *clk, int irq)
 261{
 262        struct sun5i_timer_clkevt *ce;
 263        unsigned long rate;
 264        int ret;
 265        u32 val;
 266
 267        ce = kzalloc(sizeof(*ce), GFP_KERNEL);
 268        if (!ce)
 269                return -ENOMEM;
 270
 271        ret = clk_prepare_enable(clk);
 272        if (ret) {
 273                pr_err("Couldn't enable parent clock\n");
 274                goto err_free;
 275        }
 276
 277        rate = clk_get_rate(clk);
 278
 279        ce->timer.base = base;
 280        ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 281        ce->timer.clk = clk;
 282        ce->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clkevt;
 283        ce->timer.clk_rate_cb.next = NULL;
 284
 285        ret = clk_notifier_register(clk, &ce->timer.clk_rate_cb);
 286        if (ret) {
 287                pr_err("Unable to register clock notifier.\n");
 288                goto err_disable_clk;
 289        }
 290
 291        ce->clkevt.name = node->name;
 292        ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 293        ce->clkevt.set_next_event = sun5i_clkevt_next_event;
 294        ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown;
 295        ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic;
 296        ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot;
 297        ce->clkevt.tick_resume = sun5i_clkevt_shutdown;
 298        ce->clkevt.rating = 340;
 299        ce->clkevt.irq = irq;
 300        ce->clkevt.cpumask = cpu_possible_mask;
 301
 302        /* Enable timer0 interrupt */
 303        val = readl(base + TIMER_IRQ_EN_REG);
 304        writel(val | TIMER_IRQ_EN(0), base + TIMER_IRQ_EN_REG);
 305
 306        clockevents_config_and_register(&ce->clkevt, rate,
 307                                        TIMER_SYNC_TICKS, 0xffffffff);
 308
 309        ret = request_irq(irq, sun5i_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
 310                          "sun5i_timer0", ce);
 311        if (ret) {
 312                pr_err("Unable to register interrupt\n");
 313                goto err_remove_notifier;
 314        }
 315
 316        return 0;
 317
 318err_remove_notifier:
 319        clk_notifier_unregister(clk, &ce->timer.clk_rate_cb);
 320err_disable_clk:
 321        clk_disable_unprepare(clk);
 322err_free:
 323        kfree(ce);
 324        return ret;
 325}
 326
 327static int __init sun5i_timer_init(struct device_node *node)
 328{
 329        struct reset_control *rstc;
 330        void __iomem *timer_base;
 331        struct clk *clk;
 332        int irq, ret;
 333
 334        timer_base = of_io_request_and_map(node, 0, of_node_full_name(node));
 335        if (IS_ERR(timer_base)) {
 336                pr_err("Can't map registers\n");
 337                return PTR_ERR(timer_base);
 338        }
 339
 340        irq = irq_of_parse_and_map(node, 0);
 341        if (irq <= 0) {
 342                pr_err("Can't parse IRQ\n");
 343                return -EINVAL;
 344        }
 345
 346        clk = of_clk_get(node, 0);
 347        if (IS_ERR(clk)) {
 348                pr_err("Can't get timer clock\n");
 349                return PTR_ERR(clk);
 350        }
 351
 352        rstc = of_reset_control_get(node, NULL);
 353        if (!IS_ERR(rstc))
 354                reset_control_deassert(rstc);
 355
 356        ret = sun5i_setup_clocksource(node, timer_base, clk, irq);
 357        if (ret)
 358                return ret;
 359
 360        return sun5i_setup_clockevent(node, timer_base, clk, irq);
 361}
 362TIMER_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
 363                           sun5i_timer_init);
 364TIMER_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
 365                           sun5i_timer_init);
 366