root/drivers/clocksource/timer-sun5i.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun5i_clkevt_sync
  2. sun5i_clkevt_time_stop
  3. sun5i_clkevt_time_setup
  4. sun5i_clkevt_time_start
  5. sun5i_clkevt_shutdown
  6. sun5i_clkevt_set_oneshot
  7. sun5i_clkevt_set_periodic
  8. sun5i_clkevt_next_event
  9. sun5i_timer_interrupt
  10. sun5i_clksrc_read
  11. sun5i_rate_cb_clksrc
  12. sun5i_setup_clocksource
  13. sun5i_rate_cb_clkevt
  14. sun5i_setup_clockevent
  15. sun5i_timer_init

   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 
  41 struct 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 
  51 struct 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 
  59 struct 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  */
  73 static 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 
  81 static 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 
  89 static 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 
  94 static 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 
 107 static 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 
 115 static 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 
 124 static 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 
 134 static 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 
 146 static 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 
 156 static 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 
 163 static 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 
 186 static 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 
 240 err_remove_notifier:
 241         clk_notifier_unregister(clk, &cs->timer.clk_rate_cb);
 242 err_disable_clk:
 243         clk_disable_unprepare(clk);
 244 err_free:
 245         kfree(cs);
 246         return ret;
 247 }
 248 
 249 static 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 
 264 static 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 
 328 err_remove_notifier:
 329         clk_notifier_unregister(clk, &ce->timer.clk_rate_cb);
 330 err_disable_clk:
 331         clk_disable_unprepare(clk);
 332 err_free:
 333         kfree(ce);
 334         return ret;
 335 }
 336 
 337 static 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 }
 372 TIMER_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
 373                            sun5i_timer_init);
 374 TIMER_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
 375                            sun5i_timer_init);

/* [<][>][^][v][top][bottom][index][help] */