root/arch/m68k/coldfire/pit.c

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

DEFINITIONS

This source file includes following definitions.
  1. cf_pit_set_periodic
  2. cf_pit_set_oneshot
  3. cf_pit_shutdown
  4. cf_pit_next_event
  5. pit_tick
  6. pit_read_clk
  7. hw_timer_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /***************************************************************************/
   3 
   4 /*
   5  *      pit.c -- Freescale ColdFire PIT timer. Currently this type of
   6  *               hardware timer only exists in the Freescale ColdFire
   7  *               5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
   8  *               family members will probably use it too.
   9  *
  10  *      Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
  11  *      Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
  12  */
  13 
  14 /***************************************************************************/
  15 
  16 #include <linux/kernel.h>
  17 #include <linux/sched.h>
  18 #include <linux/param.h>
  19 #include <linux/init.h>
  20 #include <linux/interrupt.h>
  21 #include <linux/irq.h>
  22 #include <linux/clockchips.h>
  23 #include <asm/machdep.h>
  24 #include <asm/io.h>
  25 #include <asm/coldfire.h>
  26 #include <asm/mcfpit.h>
  27 #include <asm/mcfsim.h>
  28 
  29 /***************************************************************************/
  30 
  31 /*
  32  *      By default use timer1 as the system clock timer.
  33  */
  34 #define FREQ    ((MCF_CLK / 2) / 64)
  35 #define TA(a)   (MCFPIT_BASE1 + (a))
  36 #define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
  37 
  38 static u32 pit_cnt;
  39 
  40 /*
  41  * Initialize the PIT timer.
  42  *
  43  * This is also called after resume to bring the PIT into operation again.
  44  */
  45 
  46 static int cf_pit_set_periodic(struct clock_event_device *evt)
  47 {
  48         __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
  49         __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
  50         __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE |
  51                      MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD |
  52                      MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
  53         return 0;
  54 }
  55 
  56 static int cf_pit_set_oneshot(struct clock_event_device *evt)
  57 {
  58         __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
  59         __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE |
  60                      MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
  61         return 0;
  62 }
  63 
  64 static int cf_pit_shutdown(struct clock_event_device *evt)
  65 {
  66         __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
  67         return 0;
  68 }
  69 
  70 /*
  71  * Program the next event in oneshot mode
  72  *
  73  * Delta is given in PIT ticks
  74  */
  75 static int cf_pit_next_event(unsigned long delta,
  76                 struct clock_event_device *evt)
  77 {
  78         __raw_writew(delta, TA(MCFPIT_PMR));
  79         return 0;
  80 }
  81 
  82 struct clock_event_device cf_pit_clockevent = {
  83         .name                   = "pit",
  84         .features               = CLOCK_EVT_FEAT_PERIODIC |
  85                                   CLOCK_EVT_FEAT_ONESHOT,
  86         .set_state_shutdown     = cf_pit_shutdown,
  87         .set_state_periodic     = cf_pit_set_periodic,
  88         .set_state_oneshot      = cf_pit_set_oneshot,
  89         .set_next_event         = cf_pit_next_event,
  90         .shift                  = 32,
  91         .irq                    = MCF_IRQ_PIT1,
  92 };
  93 
  94 
  95 
  96 /***************************************************************************/
  97 
  98 static irqreturn_t pit_tick(int irq, void *dummy)
  99 {
 100         struct clock_event_device *evt = &cf_pit_clockevent;
 101         u16 pcsr;
 102 
 103         /* Reset the ColdFire timer */
 104         pcsr = __raw_readw(TA(MCFPIT_PCSR));
 105         __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
 106 
 107         pit_cnt += PIT_CYCLES_PER_JIFFY;
 108         evt->event_handler(evt);
 109         return IRQ_HANDLED;
 110 }
 111 
 112 /***************************************************************************/
 113 
 114 static struct irqaction pit_irq = {
 115         .name    = "timer",
 116         .flags   = IRQF_TIMER,
 117         .handler = pit_tick,
 118 };
 119 
 120 /***************************************************************************/
 121 
 122 static u64 pit_read_clk(struct clocksource *cs)
 123 {
 124         unsigned long flags;
 125         u32 cycles;
 126         u16 pcntr;
 127 
 128         local_irq_save(flags);
 129         pcntr = __raw_readw(TA(MCFPIT_PCNTR));
 130         cycles = pit_cnt;
 131         local_irq_restore(flags);
 132 
 133         return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
 134 }
 135 
 136 /***************************************************************************/
 137 
 138 static struct clocksource pit_clk = {
 139         .name   = "pit",
 140         .rating = 100,
 141         .read   = pit_read_clk,
 142         .mask   = CLOCKSOURCE_MASK(32),
 143 };
 144 
 145 /***************************************************************************/
 146 
 147 void hw_timer_init(irq_handler_t handler)
 148 {
 149         cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
 150         cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
 151         cf_pit_clockevent.max_delta_ns =
 152                 clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
 153         cf_pit_clockevent.max_delta_ticks = 0xFFFF;
 154         cf_pit_clockevent.min_delta_ns =
 155                 clockevent_delta2ns(0x3f, &cf_pit_clockevent);
 156         cf_pit_clockevent.min_delta_ticks = 0x3f;
 157         clockevents_register_device(&cf_pit_clockevent);
 158 
 159         setup_irq(MCF_IRQ_PIT1, &pit_irq);
 160 
 161         clocksource_register_hz(&pit_clk, FREQ);
 162 }
 163 
 164 /***************************************************************************/

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