root/drivers/clocksource/timer-atcpit100.c

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

DEFINITIONS

This source file includes following definitions.
  1. atcpit100_ch1_tmr0_en
  2. atcpit100_ch0_tmr0_en
  3. atcpit100_clkevt_time_setup
  4. atcpit100_timer_clear_interrupt
  5. atcpit100_clocksource_start
  6. atcpit100_clkevt_time_start
  7. atcpit100_clkevt_time_stop
  8. atcpit100_clkevt_next_event
  9. atcpit100_clkevt_set_periodic
  10. atcpit100_clkevt_shutdown
  11. atcpit100_clkevt_set_oneshot
  12. atcpit100_timer_interrupt
  13. atcpit100_timer_sched_read
  14. fill_vdso_need_info
  15. atcpit100_timer_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 // Copyright (C) 2005-2017 Andes Technology Corporation
   3 /*
   4  *  Andestech ATCPIT100 Timer Device Driver Implementation
   5  * Rick Chen, Andes Technology Corporation <rick@andestech.com>
   6  *
   7  */
   8 
   9 #include <linux/irq.h>
  10 #include <linux/clocksource.h>
  11 #include <linux/clockchips.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/ioport.h>
  14 #include <linux/cpufreq.h>
  15 #include <linux/sched.h>
  16 #include <linux/sched_clock.h>
  17 #include <linux/of_address.h>
  18 #include <linux/of_irq.h>
  19 #include <linux/of_platform.h>
  20 #include "timer-of.h"
  21 #ifdef CONFIG_NDS32
  22 #include <asm/vdso_timer_info.h>
  23 #endif
  24 
  25 /*
  26  * Definition of register offsets
  27  */
  28 
  29 /* ID and Revision Register */
  30 #define ID_REV          0x0
  31 
  32 /* Configuration Register */
  33 #define CFG             0x10
  34 
  35 /* Interrupt Enable Register */
  36 #define INT_EN          0x14
  37 #define CH_INT_EN(c, i) ((1<<i)<<(4*c))
  38 #define CH0INT0EN       0x01
  39 
  40 /* Interrupt Status Register */
  41 #define INT_STA         0x18
  42 #define CH0INT0         0x01
  43 
  44 /* Channel Enable Register */
  45 #define CH_EN           0x1C
  46 #define CH0TMR0EN       0x1
  47 #define CH1TMR0EN       0x10
  48 
  49 /* Channel 0 , 1 Control Register */
  50 #define CH0_CTL         (0x20)
  51 #define CH1_CTL         (0x20 + 0x10)
  52 
  53 /* Channel clock source , bit 3 , 0:External clock , 1:APB clock */
  54 #define APB_CLK         BIT(3)
  55 
  56 /* Channel mode , bit 0~2 */
  57 #define TMR_32          0x1
  58 #define TMR_16          0x2
  59 #define TMR_8           0x3
  60 
  61 /* Channel 0 , 1 Reload Register */
  62 #define CH0_REL         (0x24)
  63 #define CH1_REL         (0x24 + 0x10)
  64 
  65 /* Channel 0 , 1 Counter Register */
  66 #define CH0_CNT         (0x28)
  67 #define CH1_CNT         (0x28 + 0x10)
  68 
  69 #define TIMER_SYNC_TICKS        3
  70 
  71 static void atcpit100_ch1_tmr0_en(void __iomem *base)
  72 {
  73         writel(~0, base + CH1_REL);
  74         writel(APB_CLK|TMR_32, base + CH1_CTL);
  75 }
  76 
  77 static void atcpit100_ch0_tmr0_en(void __iomem *base)
  78 {
  79         writel(APB_CLK|TMR_32, base + CH0_CTL);
  80 }
  81 
  82 static void atcpit100_clkevt_time_setup(void __iomem *base, unsigned long delay)
  83 {
  84         writel(delay, base + CH0_CNT);
  85         writel(delay, base + CH0_REL);
  86 }
  87 
  88 static void atcpit100_timer_clear_interrupt(void __iomem *base)
  89 {
  90         u32 val;
  91 
  92         val = readl(base + INT_STA);
  93         writel(val | CH0INT0, base + INT_STA);
  94 }
  95 
  96 static void atcpit100_clocksource_start(void __iomem *base)
  97 {
  98         u32 val;
  99 
 100         val = readl(base + CH_EN);
 101         writel(val | CH1TMR0EN, base + CH_EN);
 102 }
 103 
 104 static void atcpit100_clkevt_time_start(void __iomem *base)
 105 {
 106         u32 val;
 107 
 108         val = readl(base + CH_EN);
 109         writel(val | CH0TMR0EN, base + CH_EN);
 110 }
 111 
 112 static void atcpit100_clkevt_time_stop(void __iomem *base)
 113 {
 114         u32 val;
 115 
 116         atcpit100_timer_clear_interrupt(base);
 117         val = readl(base + CH_EN);
 118         writel(val & ~CH0TMR0EN, base + CH_EN);
 119 }
 120 
 121 static int atcpit100_clkevt_next_event(unsigned long evt,
 122         struct clock_event_device *clkevt)
 123 {
 124         u32 val;
 125         struct timer_of *to = to_timer_of(clkevt);
 126 
 127         val = readl(timer_of_base(to) + CH_EN);
 128         writel(val & ~CH0TMR0EN, timer_of_base(to) + CH_EN);
 129         writel(evt, timer_of_base(to) + CH0_REL);
 130         writel(val | CH0TMR0EN, timer_of_base(to) + CH_EN);
 131 
 132         return 0;
 133 }
 134 
 135 static int atcpit100_clkevt_set_periodic(struct clock_event_device *evt)
 136 {
 137         struct timer_of *to = to_timer_of(evt);
 138 
 139         atcpit100_clkevt_time_setup(timer_of_base(to), timer_of_period(to));
 140         atcpit100_clkevt_time_start(timer_of_base(to));
 141 
 142         return 0;
 143 }
 144 static int atcpit100_clkevt_shutdown(struct clock_event_device *evt)
 145 {
 146         struct timer_of *to = to_timer_of(evt);
 147 
 148         atcpit100_clkevt_time_stop(timer_of_base(to));
 149 
 150         return 0;
 151 }
 152 static int atcpit100_clkevt_set_oneshot(struct clock_event_device *evt)
 153 {
 154         struct timer_of *to = to_timer_of(evt);
 155         u32 val;
 156 
 157         writel(~0x0, timer_of_base(to) + CH0_REL);
 158         val = readl(timer_of_base(to) + CH_EN);
 159         writel(val | CH0TMR0EN, timer_of_base(to) + CH_EN);
 160 
 161         return 0;
 162 }
 163 
 164 static irqreturn_t atcpit100_timer_interrupt(int irq, void *dev_id)
 165 {
 166         struct clock_event_device *evt = (struct clock_event_device *)dev_id;
 167         struct timer_of *to = to_timer_of(evt);
 168 
 169         atcpit100_timer_clear_interrupt(timer_of_base(to));
 170 
 171         evt->event_handler(evt);
 172 
 173         return IRQ_HANDLED;
 174 }
 175 
 176 static struct timer_of to = {
 177         .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
 178 
 179         .clkevt = {
 180                 .name = "atcpit100_tick",
 181                 .rating = 300,
 182                 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 183                 .set_state_shutdown = atcpit100_clkevt_shutdown,
 184                 .set_state_periodic = atcpit100_clkevt_set_periodic,
 185                 .set_state_oneshot = atcpit100_clkevt_set_oneshot,
 186                 .tick_resume = atcpit100_clkevt_shutdown,
 187                 .set_next_event = atcpit100_clkevt_next_event,
 188                 .cpumask = cpu_possible_mask,
 189         },
 190 
 191         .of_irq = {
 192                 .handler = atcpit100_timer_interrupt,
 193                 .flags = IRQF_TIMER | IRQF_IRQPOLL,
 194         },
 195 
 196         /*
 197          * FIXME: we currently only support clocking using PCLK
 198          * and using EXTCLK is not supported in the driver.
 199          */
 200         .of_clk = {
 201                 .name = "PCLK",
 202         }
 203 };
 204 
 205 static u64 notrace atcpit100_timer_sched_read(void)
 206 {
 207         return ~readl(timer_of_base(&to) + CH1_CNT);
 208 }
 209 
 210 #ifdef CONFIG_NDS32
 211 static void fill_vdso_need_info(struct device_node *node)
 212 {
 213         struct resource timer_res;
 214         of_address_to_resource(node, 0, &timer_res);
 215         timer_info.mapping_base = (unsigned long)timer_res.start;
 216         timer_info.cycle_count_down = true;
 217         timer_info.cycle_count_reg_offset = CH1_CNT;
 218 }
 219 #endif
 220 
 221 static int __init atcpit100_timer_init(struct device_node *node)
 222 {
 223         int ret;
 224         u32 val;
 225         void __iomem *base;
 226 
 227         ret = timer_of_init(node, &to);
 228         if (ret)
 229                 return ret;
 230 
 231         base = timer_of_base(&to);
 232 
 233         sched_clock_register(atcpit100_timer_sched_read, 32,
 234                 timer_of_rate(&to));
 235 
 236         ret = clocksource_mmio_init(base + CH1_CNT,
 237                 node->name, timer_of_rate(&to), 300, 32,
 238                 clocksource_mmio_readl_down);
 239 
 240         if (ret) {
 241                 pr_err("Failed to register clocksource\n");
 242                 return ret;
 243         }
 244 
 245         /* clear channel 0 timer0 interrupt */
 246         atcpit100_timer_clear_interrupt(base);
 247 
 248         clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
 249                                         TIMER_SYNC_TICKS, 0xffffffff);
 250         atcpit100_ch0_tmr0_en(base);
 251         atcpit100_ch1_tmr0_en(base);
 252         atcpit100_clocksource_start(base);
 253         atcpit100_clkevt_time_start(base);
 254 
 255         /* Enable channel 0 timer0 interrupt */
 256         val = readl(base + INT_EN);
 257         writel(val | CH0INT0EN, base + INT_EN);
 258 
 259 #ifdef CONFIG_NDS32
 260         fill_vdso_need_info(node);
 261 #endif
 262 
 263         return ret;
 264 }
 265 
 266 TIMER_OF_DECLARE(atcpit100, "andestech,atcpit100", atcpit100_timer_init);

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