root/drivers/clocksource/renesas-ostm.c

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

DEFINITIONS

This source file includes following definitions.
  1. ced_to_ostm
  2. ostm_timer_stop
  3. ostm_init_clksrc
  4. ostm_read_sched_clock
  5. ostm_init_sched_clock
  6. ostm_clock_event_next
  7. ostm_shutdown
  8. ostm_set_periodic
  9. ostm_set_oneshot
  10. ostm_timer_interrupt
  11. ostm_init_clkevt
  12. ostm_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Renesas Timer Support - OSTM
   4  *
   5  * Copyright (C) 2017 Renesas Electronics America, Inc.
   6  * Copyright (C) 2017 Chris Brandt
   7  */
   8 
   9 #include <linux/of_address.h>
  10 #include <linux/of_irq.h>
  11 #include <linux/clk.h>
  12 #include <linux/clockchips.h>
  13 #include <linux/interrupt.h>
  14 #include <linux/sched_clock.h>
  15 #include <linux/slab.h>
  16 
  17 /*
  18  * The OSTM contains independent channels.
  19  * The first OSTM channel probed will be set up as a free running
  20  * clocksource. Additionally we will use this clocksource for the system
  21  * schedule timer sched_clock().
  22  *
  23  * The second (or more) channel probed will be set up as an interrupt
  24  * driven clock event.
  25  */
  26 
  27 struct ostm_device {
  28         void __iomem *base;
  29         unsigned long ticks_per_jiffy;
  30         struct clock_event_device ced;
  31 };
  32 
  33 static void __iomem *system_clock;      /* For sched_clock() */
  34 
  35 /* OSTM REGISTERS */
  36 #define OSTM_CMP                0x000   /* RW,32 */
  37 #define OSTM_CNT                0x004   /* R,32 */
  38 #define OSTM_TE                 0x010   /* R,8 */
  39 #define OSTM_TS                 0x014   /* W,8 */
  40 #define OSTM_TT                 0x018   /* W,8 */
  41 #define OSTM_CTL                0x020   /* RW,8 */
  42 
  43 #define TE                      0x01
  44 #define TS                      0x01
  45 #define TT                      0x01
  46 #define CTL_PERIODIC            0x00
  47 #define CTL_ONESHOT             0x02
  48 #define CTL_FREERUN             0x02
  49 
  50 static struct ostm_device *ced_to_ostm(struct clock_event_device *ced)
  51 {
  52         return container_of(ced, struct ostm_device, ced);
  53 }
  54 
  55 static void ostm_timer_stop(struct ostm_device *ostm)
  56 {
  57         if (readb(ostm->base + OSTM_TE) & TE) {
  58                 writeb(TT, ostm->base + OSTM_TT);
  59 
  60                 /*
  61                  * Read back the register simply to confirm the write operation
  62                  * has completed since I/O writes can sometimes get queued by
  63                  * the bus architecture.
  64                  */
  65                 while (readb(ostm->base + OSTM_TE) & TE)
  66                         ;
  67         }
  68 }
  69 
  70 static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate)
  71 {
  72         /*
  73          * irq not used (clock sources don't use interrupts)
  74          */
  75 
  76         ostm_timer_stop(ostm);
  77 
  78         writel(0, ostm->base + OSTM_CMP);
  79         writeb(CTL_FREERUN, ostm->base + OSTM_CTL);
  80         writeb(TS, ostm->base + OSTM_TS);
  81 
  82         return clocksource_mmio_init(ostm->base + OSTM_CNT,
  83                         "ostm", rate,
  84                         300, 32, clocksource_mmio_readl_up);
  85 }
  86 
  87 static u64 notrace ostm_read_sched_clock(void)
  88 {
  89         return readl(system_clock);
  90 }
  91 
  92 static void __init ostm_init_sched_clock(struct ostm_device *ostm,
  93                         unsigned long rate)
  94 {
  95         system_clock = ostm->base + OSTM_CNT;
  96         sched_clock_register(ostm_read_sched_clock, 32, rate);
  97 }
  98 
  99 static int ostm_clock_event_next(unsigned long delta,
 100                                      struct clock_event_device *ced)
 101 {
 102         struct ostm_device *ostm = ced_to_ostm(ced);
 103 
 104         ostm_timer_stop(ostm);
 105 
 106         writel(delta, ostm->base + OSTM_CMP);
 107         writeb(CTL_ONESHOT, ostm->base + OSTM_CTL);
 108         writeb(TS, ostm->base + OSTM_TS);
 109 
 110         return 0;
 111 }
 112 
 113 static int ostm_shutdown(struct clock_event_device *ced)
 114 {
 115         struct ostm_device *ostm = ced_to_ostm(ced);
 116 
 117         ostm_timer_stop(ostm);
 118 
 119         return 0;
 120 }
 121 static int ostm_set_periodic(struct clock_event_device *ced)
 122 {
 123         struct ostm_device *ostm = ced_to_ostm(ced);
 124 
 125         if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
 126                 ostm_timer_stop(ostm);
 127 
 128         writel(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP);
 129         writeb(CTL_PERIODIC, ostm->base + OSTM_CTL);
 130         writeb(TS, ostm->base + OSTM_TS);
 131 
 132         return 0;
 133 }
 134 
 135 static int ostm_set_oneshot(struct clock_event_device *ced)
 136 {
 137         struct ostm_device *ostm = ced_to_ostm(ced);
 138 
 139         ostm_timer_stop(ostm);
 140 
 141         return 0;
 142 }
 143 
 144 static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id)
 145 {
 146         struct ostm_device *ostm = dev_id;
 147 
 148         if (clockevent_state_oneshot(&ostm->ced))
 149                 ostm_timer_stop(ostm);
 150 
 151         /* notify clockevent layer */
 152         if (ostm->ced.event_handler)
 153                 ostm->ced.event_handler(&ostm->ced);
 154 
 155         return IRQ_HANDLED;
 156 }
 157 
 158 static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq,
 159                         unsigned long rate)
 160 {
 161         struct clock_event_device *ced = &ostm->ced;
 162         int ret = -ENXIO;
 163 
 164         ret = request_irq(irq, ostm_timer_interrupt,
 165                           IRQF_TIMER | IRQF_IRQPOLL,
 166                           "ostm", ostm);
 167         if (ret) {
 168                 pr_err("ostm: failed to request irq\n");
 169                 return ret;
 170         }
 171 
 172         ced->name = "ostm";
 173         ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
 174         ced->set_state_shutdown = ostm_shutdown;
 175         ced->set_state_periodic = ostm_set_periodic;
 176         ced->set_state_oneshot = ostm_set_oneshot;
 177         ced->set_next_event = ostm_clock_event_next;
 178         ced->shift = 32;
 179         ced->rating = 300;
 180         ced->cpumask = cpumask_of(0);
 181         clockevents_config_and_register(ced, rate, 0xf, 0xffffffff);
 182 
 183         return 0;
 184 }
 185 
 186 static int __init ostm_init(struct device_node *np)
 187 {
 188         struct ostm_device *ostm;
 189         int ret = -EFAULT;
 190         struct clk *ostm_clk = NULL;
 191         int irq;
 192         unsigned long rate;
 193 
 194         ostm = kzalloc(sizeof(*ostm), GFP_KERNEL);
 195         if (!ostm)
 196                 return -ENOMEM;
 197 
 198         ostm->base = of_iomap(np, 0);
 199         if (!ostm->base) {
 200                 pr_err("ostm: failed to remap I/O memory\n");
 201                 goto err;
 202         }
 203 
 204         irq = irq_of_parse_and_map(np, 0);
 205         if (irq < 0) {
 206                 pr_err("ostm: Failed to get irq\n");
 207                 goto err;
 208         }
 209 
 210         ostm_clk = of_clk_get(np, 0);
 211         if (IS_ERR(ostm_clk)) {
 212                 pr_err("ostm: Failed to get clock\n");
 213                 ostm_clk = NULL;
 214                 goto err;
 215         }
 216 
 217         ret = clk_prepare_enable(ostm_clk);
 218         if (ret) {
 219                 pr_err("ostm: Failed to enable clock\n");
 220                 goto err;
 221         }
 222 
 223         rate = clk_get_rate(ostm_clk);
 224         ostm->ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
 225 
 226         /*
 227          * First probed device will be used as system clocksource. Any
 228          * additional devices will be used as clock events.
 229          */
 230         if (!system_clock) {
 231                 ret = ostm_init_clksrc(ostm, rate);
 232 
 233                 if (!ret) {
 234                         ostm_init_sched_clock(ostm, rate);
 235                         pr_info("ostm: used for clocksource\n");
 236                 }
 237 
 238         } else {
 239                 ret = ostm_init_clkevt(ostm, irq, rate);
 240 
 241                 if (!ret)
 242                         pr_info("ostm: used for clock events\n");
 243         }
 244 
 245 err:
 246         if (ret) {
 247                 clk_disable_unprepare(ostm_clk);
 248                 iounmap(ostm->base);
 249                 kfree(ostm);
 250                 return ret;
 251         }
 252 
 253         return 0;
 254 }
 255 
 256 TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init);

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