root/drivers/clocksource/timer-sp804.c

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

DEFINITIONS

This source file includes following definitions.
  1. sp804_get_clock_rate
  2. sp804_read
  3. sp804_timer_disable
  4. __sp804_clocksource_and_sched_clock_init
  5. sp804_timer_interrupt
  6. timer_shutdown
  7. sp804_shutdown
  8. sp804_set_periodic
  9. sp804_set_next_event
  10. __sp804_clockevents_init
  11. sp804_of_init
  12. integrator_cp_of_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  linux/drivers/clocksource/timer-sp.c
   4  *
   5  *  Copyright (C) 1999 - 2003 ARM Limited
   6  *  Copyright (C) 2000 Deep Blue Solutions Ltd
   7  */
   8 #include <linux/clk.h>
   9 #include <linux/clocksource.h>
  10 #include <linux/clockchips.h>
  11 #include <linux/err.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/irq.h>
  14 #include <linux/io.h>
  15 #include <linux/of.h>
  16 #include <linux/of_address.h>
  17 #include <linux/of_clk.h>
  18 #include <linux/of_irq.h>
  19 #include <linux/sched_clock.h>
  20 
  21 #include <clocksource/timer-sp804.h>
  22 
  23 #include "timer-sp.h"
  24 
  25 static long __init sp804_get_clock_rate(struct clk *clk)
  26 {
  27         long rate;
  28         int err;
  29 
  30         err = clk_prepare(clk);
  31         if (err) {
  32                 pr_err("sp804: clock failed to prepare: %d\n", err);
  33                 clk_put(clk);
  34                 return err;
  35         }
  36 
  37         err = clk_enable(clk);
  38         if (err) {
  39                 pr_err("sp804: clock failed to enable: %d\n", err);
  40                 clk_unprepare(clk);
  41                 clk_put(clk);
  42                 return err;
  43         }
  44 
  45         rate = clk_get_rate(clk);
  46         if (rate < 0) {
  47                 pr_err("sp804: clock failed to get rate: %ld\n", rate);
  48                 clk_disable(clk);
  49                 clk_unprepare(clk);
  50                 clk_put(clk);
  51         }
  52 
  53         return rate;
  54 }
  55 
  56 static void __iomem *sched_clock_base;
  57 
  58 static u64 notrace sp804_read(void)
  59 {
  60         return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
  61 }
  62 
  63 void __init sp804_timer_disable(void __iomem *base)
  64 {
  65         writel(0, base + TIMER_CTRL);
  66 }
  67 
  68 int  __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
  69                                                      const char *name,
  70                                                      struct clk *clk,
  71                                                      int use_sched_clock)
  72 {
  73         long rate;
  74 
  75         if (!clk) {
  76                 clk = clk_get_sys("sp804", name);
  77                 if (IS_ERR(clk)) {
  78                         pr_err("sp804: clock not found: %d\n",
  79                                (int)PTR_ERR(clk));
  80                         return PTR_ERR(clk);
  81                 }
  82         }
  83 
  84         rate = sp804_get_clock_rate(clk);
  85         if (rate < 0)
  86                 return -EINVAL;
  87 
  88         /* setup timer 0 as free-running clocksource */
  89         writel(0, base + TIMER_CTRL);
  90         writel(0xffffffff, base + TIMER_LOAD);
  91         writel(0xffffffff, base + TIMER_VALUE);
  92         writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
  93                 base + TIMER_CTRL);
  94 
  95         clocksource_mmio_init(base + TIMER_VALUE, name,
  96                 rate, 200, 32, clocksource_mmio_readl_down);
  97 
  98         if (use_sched_clock) {
  99                 sched_clock_base = base;
 100                 sched_clock_register(sp804_read, 32, rate);
 101         }
 102 
 103         return 0;
 104 }
 105 
 106 
 107 static void __iomem *clkevt_base;
 108 static unsigned long clkevt_reload;
 109 
 110 /*
 111  * IRQ handler for the timer
 112  */
 113 static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
 114 {
 115         struct clock_event_device *evt = dev_id;
 116 
 117         /* clear the interrupt */
 118         writel(1, clkevt_base + TIMER_INTCLR);
 119 
 120         evt->event_handler(evt);
 121 
 122         return IRQ_HANDLED;
 123 }
 124 
 125 static inline void timer_shutdown(struct clock_event_device *evt)
 126 {
 127         writel(0, clkevt_base + TIMER_CTRL);
 128 }
 129 
 130 static int sp804_shutdown(struct clock_event_device *evt)
 131 {
 132         timer_shutdown(evt);
 133         return 0;
 134 }
 135 
 136 static int sp804_set_periodic(struct clock_event_device *evt)
 137 {
 138         unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
 139                              TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
 140 
 141         timer_shutdown(evt);
 142         writel(clkevt_reload, clkevt_base + TIMER_LOAD);
 143         writel(ctrl, clkevt_base + TIMER_CTRL);
 144         return 0;
 145 }
 146 
 147 static int sp804_set_next_event(unsigned long next,
 148         struct clock_event_device *evt)
 149 {
 150         unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
 151                              TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
 152 
 153         writel(next, clkevt_base + TIMER_LOAD);
 154         writel(ctrl, clkevt_base + TIMER_CTRL);
 155 
 156         return 0;
 157 }
 158 
 159 static struct clock_event_device sp804_clockevent = {
 160         .features               = CLOCK_EVT_FEAT_PERIODIC |
 161                                   CLOCK_EVT_FEAT_ONESHOT |
 162                                   CLOCK_EVT_FEAT_DYNIRQ,
 163         .set_state_shutdown     = sp804_shutdown,
 164         .set_state_periodic     = sp804_set_periodic,
 165         .set_state_oneshot      = sp804_shutdown,
 166         .tick_resume            = sp804_shutdown,
 167         .set_next_event         = sp804_set_next_event,
 168         .rating                 = 300,
 169 };
 170 
 171 static struct irqaction sp804_timer_irq = {
 172         .name           = "timer",
 173         .flags          = IRQF_TIMER | IRQF_IRQPOLL,
 174         .handler        = sp804_timer_interrupt,
 175         .dev_id         = &sp804_clockevent,
 176 };
 177 
 178 int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
 179 {
 180         struct clock_event_device *evt = &sp804_clockevent;
 181         long rate;
 182 
 183         if (!clk)
 184                 clk = clk_get_sys("sp804", name);
 185         if (IS_ERR(clk)) {
 186                 pr_err("sp804: %s clock not found: %d\n", name,
 187                         (int)PTR_ERR(clk));
 188                 return PTR_ERR(clk);
 189         }
 190 
 191         rate = sp804_get_clock_rate(clk);
 192         if (rate < 0)
 193                 return -EINVAL;
 194 
 195         clkevt_base = base;
 196         clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
 197         evt->name = name;
 198         evt->irq = irq;
 199         evt->cpumask = cpu_possible_mask;
 200 
 201         writel(0, base + TIMER_CTRL);
 202 
 203         setup_irq(irq, &sp804_timer_irq);
 204         clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
 205 
 206         return 0;
 207 }
 208 
 209 static int __init sp804_of_init(struct device_node *np)
 210 {
 211         static bool initialized = false;
 212         void __iomem *base;
 213         int irq, ret = -EINVAL;
 214         u32 irq_num = 0;
 215         struct clk *clk1, *clk2;
 216         const char *name = of_get_property(np, "compatible", NULL);
 217 
 218         base = of_iomap(np, 0);
 219         if (!base)
 220                 return -ENXIO;
 221 
 222         /* Ensure timers are disabled */
 223         writel(0, base + TIMER_CTRL);
 224         writel(0, base + TIMER_2_BASE + TIMER_CTRL);
 225 
 226         if (initialized || !of_device_is_available(np)) {
 227                 ret = -EINVAL;
 228                 goto err;
 229         }
 230 
 231         clk1 = of_clk_get(np, 0);
 232         if (IS_ERR(clk1))
 233                 clk1 = NULL;
 234 
 235         /* Get the 2nd clock if the timer has 3 timer clocks */
 236         if (of_clk_get_parent_count(np) == 3) {
 237                 clk2 = of_clk_get(np, 1);
 238                 if (IS_ERR(clk2)) {
 239                         pr_err("sp804: %pOFn clock not found: %d\n", np,
 240                                 (int)PTR_ERR(clk2));
 241                         clk2 = NULL;
 242                 }
 243         } else
 244                 clk2 = clk1;
 245 
 246         irq = irq_of_parse_and_map(np, 0);
 247         if (irq <= 0)
 248                 goto err;
 249 
 250         of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
 251         if (irq_num == 2) {
 252 
 253                 ret = __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
 254                 if (ret)
 255                         goto err;
 256 
 257                 ret = __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1);
 258                 if (ret)
 259                         goto err;
 260         } else {
 261 
 262                 ret = __sp804_clockevents_init(base, irq, clk1 , name);
 263                 if (ret)
 264                         goto err;
 265 
 266                 ret =__sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
 267                                                               name, clk2, 1);
 268                 if (ret)
 269                         goto err;
 270         }
 271         initialized = true;
 272 
 273         return 0;
 274 err:
 275         iounmap(base);
 276         return ret;
 277 }
 278 TIMER_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
 279 
 280 static int __init integrator_cp_of_init(struct device_node *np)
 281 {
 282         static int init_count = 0;
 283         void __iomem *base;
 284         int irq, ret = -EINVAL;
 285         const char *name = of_get_property(np, "compatible", NULL);
 286         struct clk *clk;
 287 
 288         base = of_iomap(np, 0);
 289         if (!base) {
 290                 pr_err("Failed to iomap\n");
 291                 return -ENXIO;
 292         }
 293 
 294         clk = of_clk_get(np, 0);
 295         if (IS_ERR(clk)) {
 296                 pr_err("Failed to get clock\n");
 297                 return PTR_ERR(clk);
 298         }
 299 
 300         /* Ensure timer is disabled */
 301         writel(0, base + TIMER_CTRL);
 302 
 303         if (init_count == 2 || !of_device_is_available(np))
 304                 goto err;
 305 
 306         if (!init_count) {
 307                 ret = __sp804_clocksource_and_sched_clock_init(base, name, clk, 0);
 308                 if (ret)
 309                         goto err;
 310         } else {
 311                 irq = irq_of_parse_and_map(np, 0);
 312                 if (irq <= 0)
 313                         goto err;
 314 
 315                 ret = __sp804_clockevents_init(base, irq, clk, name);
 316                 if (ret)
 317                         goto err;
 318         }
 319 
 320         init_count++;
 321         return 0;
 322 err:
 323         iounmap(base);
 324         return ret;
 325 }
 326 TIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);

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