linux/arch/m68k/coldfire/pit.c
<<
>>
Prefs
   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
  38static 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
  46static 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
  56static 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
  64static 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 */
  75static 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
  82struct 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
  98static 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
 114static u64 pit_read_clk(struct clocksource *cs)
 115{
 116        unsigned long flags;
 117        u32 cycles;
 118        u16 pcntr;
 119
 120        local_irq_save(flags);
 121        pcntr = __raw_readw(TA(MCFPIT_PCNTR));
 122        cycles = pit_cnt;
 123        local_irq_restore(flags);
 124
 125        return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
 126}
 127
 128/***************************************************************************/
 129
 130static struct clocksource pit_clk = {
 131        .name   = "pit",
 132        .rating = 100,
 133        .read   = pit_read_clk,
 134        .mask   = CLOCKSOURCE_MASK(32),
 135};
 136
 137/***************************************************************************/
 138
 139void hw_timer_init(void)
 140{
 141        int ret;
 142
 143        cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
 144        cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
 145        cf_pit_clockevent.max_delta_ns =
 146                clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
 147        cf_pit_clockevent.max_delta_ticks = 0xFFFF;
 148        cf_pit_clockevent.min_delta_ns =
 149                clockevent_delta2ns(0x3f, &cf_pit_clockevent);
 150        cf_pit_clockevent.min_delta_ticks = 0x3f;
 151        clockevents_register_device(&cf_pit_clockevent);
 152
 153        ret = request_irq(MCF_IRQ_PIT1, pit_tick, IRQF_TIMER, "timer", NULL);
 154        if (ret) {
 155                pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_PIT1,
 156                       ERR_PTR(ret));
 157        }
 158
 159        clocksource_register_hz(&pit_clk, FREQ);
 160}
 161
 162/***************************************************************************/
 163