root/drivers/clocksource/timer-digicolor.c

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

DEFINITIONS

This source file includes following definitions.
  1. dc_timer
  2. dc_timer_disable
  3. dc_timer_enable
  4. dc_timer_set_count
  5. digicolor_clkevt_shutdown
  6. digicolor_clkevt_set_oneshot
  7. digicolor_clkevt_set_periodic
  8. digicolor_clkevt_next_event
  9. digicolor_timer_interrupt
  10. digicolor_timer_sched_read
  11. digicolor_timer_init

   1 /*
   2  * Conexant Digicolor timer driver
   3  *
   4  * Author: Baruch Siach <baruch@tkos.co.il>
   5  *
   6  * Copyright (C) 2014 Paradox Innovation Ltd.
   7  *
   8  * Based on:
   9  *      Allwinner SoCs hstimer driver
  10  *
  11  * Copyright (C) 2013 Maxime Ripard
  12  *
  13  * Maxime Ripard <maxime.ripard@free-electrons.com>
  14  *
  15  * This file is licensed under the terms of the GNU General Public
  16  * License version 2.  This program is licensed "as is" without any
  17  * warranty of any kind, whether express or implied.
  18  */
  19 
  20 /*
  21  * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to
  22  * "Timer H". Timer A is the only one with watchdog support, so it is dedicated
  23  * to the watchdog driver. This driver uses Timer B for sched_clock(), and
  24  * Timer C for clockevents.
  25  */
  26 
  27 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  28 
  29 #include <linux/clk.h>
  30 #include <linux/clockchips.h>
  31 #include <linux/interrupt.h>
  32 #include <linux/irq.h>
  33 #include <linux/irqreturn.h>
  34 #include <linux/sched/clock.h>
  35 #include <linux/sched_clock.h>
  36 #include <linux/of.h>
  37 #include <linux/of_address.h>
  38 #include <linux/of_irq.h>
  39 
  40 enum {
  41         TIMER_A,
  42         TIMER_B,
  43         TIMER_C,
  44         TIMER_D,
  45         TIMER_E,
  46         TIMER_F,
  47         TIMER_G,
  48         TIMER_H,
  49 };
  50 
  51 #define CONTROL(t)      ((t)*8)
  52 #define COUNT(t)        ((t)*8 + 4)
  53 
  54 #define CONTROL_DISABLE         0
  55 #define CONTROL_ENABLE          BIT(0)
  56 #define CONTROL_MODE(m)         ((m) << 4)
  57 #define CONTROL_MODE_ONESHOT    CONTROL_MODE(1)
  58 #define CONTROL_MODE_PERIODIC   CONTROL_MODE(2)
  59 
  60 struct digicolor_timer {
  61         struct clock_event_device ce;
  62         void __iomem *base;
  63         u32 ticks_per_jiffy;
  64         int timer_id; /* one of TIMER_* */
  65 };
  66 
  67 static struct digicolor_timer *dc_timer(struct clock_event_device *ce)
  68 {
  69         return container_of(ce, struct digicolor_timer, ce);
  70 }
  71 
  72 static inline void dc_timer_disable(struct clock_event_device *ce)
  73 {
  74         struct digicolor_timer *dt = dc_timer(ce);
  75         writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id));
  76 }
  77 
  78 static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode)
  79 {
  80         struct digicolor_timer *dt = dc_timer(ce);
  81         writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id));
  82 }
  83 
  84 static inline void dc_timer_set_count(struct clock_event_device *ce,
  85                                       unsigned long count)
  86 {
  87         struct digicolor_timer *dt = dc_timer(ce);
  88         writel(count, dt->base + COUNT(dt->timer_id));
  89 }
  90 
  91 static int digicolor_clkevt_shutdown(struct clock_event_device *ce)
  92 {
  93         dc_timer_disable(ce);
  94         return 0;
  95 }
  96 
  97 static int digicolor_clkevt_set_oneshot(struct clock_event_device *ce)
  98 {
  99         dc_timer_disable(ce);
 100         dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
 101         return 0;
 102 }
 103 
 104 static int digicolor_clkevt_set_periodic(struct clock_event_device *ce)
 105 {
 106         struct digicolor_timer *dt = dc_timer(ce);
 107 
 108         dc_timer_disable(ce);
 109         dc_timer_set_count(ce, dt->ticks_per_jiffy);
 110         dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
 111         return 0;
 112 }
 113 
 114 static int digicolor_clkevt_next_event(unsigned long evt,
 115                                        struct clock_event_device *ce)
 116 {
 117         dc_timer_disable(ce);
 118         dc_timer_set_count(ce, evt);
 119         dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
 120 
 121         return 0;
 122 }
 123 
 124 static struct digicolor_timer dc_timer_dev = {
 125         .ce = {
 126                 .name = "digicolor_tick",
 127                 .rating = 340,
 128                 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 129                 .set_state_shutdown = digicolor_clkevt_shutdown,
 130                 .set_state_periodic = digicolor_clkevt_set_periodic,
 131                 .set_state_oneshot = digicolor_clkevt_set_oneshot,
 132                 .tick_resume = digicolor_clkevt_shutdown,
 133                 .set_next_event = digicolor_clkevt_next_event,
 134         },
 135         .timer_id = TIMER_C,
 136 };
 137 
 138 static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id)
 139 {
 140         struct clock_event_device *evt = dev_id;
 141 
 142         evt->event_handler(evt);
 143 
 144         return IRQ_HANDLED;
 145 }
 146 
 147 static u64 notrace digicolor_timer_sched_read(void)
 148 {
 149         return ~readl(dc_timer_dev.base + COUNT(TIMER_B));
 150 }
 151 
 152 static int __init digicolor_timer_init(struct device_node *node)
 153 {
 154         unsigned long rate;
 155         struct clk *clk;
 156         int ret, irq;
 157 
 158         /*
 159          * timer registers are shared with the watchdog timer;
 160          * don't map exclusively
 161          */
 162         dc_timer_dev.base = of_iomap(node, 0);
 163         if (!dc_timer_dev.base) {
 164                 pr_err("Can't map registers\n");
 165                 return -ENXIO;
 166         }
 167 
 168         irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
 169         if (irq <= 0) {
 170                 pr_err("Can't parse IRQ\n");
 171                 return -EINVAL;
 172         }
 173 
 174         clk = of_clk_get(node, 0);
 175         if (IS_ERR(clk)) {
 176                 pr_err("Can't get timer clock\n");
 177                 return PTR_ERR(clk);
 178         }
 179         clk_prepare_enable(clk);
 180         rate = clk_get_rate(clk);
 181         dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 182 
 183         writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B));
 184         writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B));
 185         writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B));
 186 
 187         sched_clock_register(digicolor_timer_sched_read, 32, rate);
 188         clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name,
 189                               rate, 340, 32, clocksource_mmio_readl_down);
 190 
 191         ret = request_irq(irq, digicolor_timer_interrupt,
 192                           IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC",
 193                           &dc_timer_dev.ce);
 194         if (ret) {
 195                 pr_warn("request of timer irq %d failed (%d)\n", irq, ret);
 196                 return ret;
 197         }
 198 
 199         dc_timer_dev.ce.cpumask = cpu_possible_mask;
 200         dc_timer_dev.ce.irq = irq;
 201 
 202         clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff);
 203 
 204         return 0;
 205 }
 206 TIMER_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
 207                        digicolor_timer_init);

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