linux/arch/arm/mach-rpc/time.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/arch/arm/common/time-acorn.c
   4 *
   5 *  Copyright (c) 1996-2000 Russell King.
   6 *
   7 *  Changelog:
   8 *   24-Sep-1996        RMK     Created
   9 *   10-Oct-1996        RMK     Brought up to date with arch-sa110eval
  10 *   04-Dec-1997        RMK     Updated for new arch/arm/time.c
  11 *   13=Jun-2004        DS      Moved to arch/arm/common b/c shared w/CLPS7500
  12 */
  13#include <linux/clocksource.h>
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/io.h>
  18
  19#include <mach/hardware.h>
  20#include <asm/hardware/ioc.h>
  21
  22#include <asm/mach/time.h>
  23
  24#define RPC_CLOCK_FREQ 2000000
  25#define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ)
  26
  27static u32 ioc_time;
  28
  29static u64 ioc_timer_read(struct clocksource *cs)
  30{
  31        unsigned int count1, count2, status;
  32        unsigned long flags;
  33        u32 ticks;
  34
  35        local_irq_save(flags);
  36        ioc_writeb (0, IOC_T0LATCH);
  37        barrier ();
  38        count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
  39        barrier ();
  40        status = ioc_readb(IOC_IRQREQA);
  41        barrier ();
  42        ioc_writeb (0, IOC_T0LATCH);
  43        barrier ();
  44        count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
  45        ticks = ioc_time + RPC_LATCH - count2;
  46        local_irq_restore(flags);
  47
  48        if (count2 < count1) {
  49                /*
  50                 * The timer has not reloaded between reading count1 and
  51                 * count2, check whether an interrupt was actually pending.
  52                 */
  53                if (status & (1 << 5))
  54                        ticks += RPC_LATCH;
  55        } else if (count2 > count1) {
  56                /*
  57                 * The timer has reloaded, so count2 indicates the new
  58                 * count since the wrap.  The interrupt would not have
  59                 * been processed, so add the missed ticks.
  60                 */
  61                ticks += RPC_LATCH;
  62        }
  63
  64        return ticks;
  65}
  66
  67static struct clocksource ioctime_clocksource = {
  68        .read = ioc_timer_read,
  69        .mask = CLOCKSOURCE_MASK(32),
  70        .rating = 100,
  71};
  72
  73void __init ioctime_init(void)
  74{
  75        ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL);
  76        ioc_writeb(RPC_LATCH >> 8, IOC_T0LTCHH);
  77        ioc_writeb(0, IOC_T0GO);
  78}
  79
  80static irqreturn_t
  81ioc_timer_interrupt(int irq, void *dev_id)
  82{
  83        ioc_time += RPC_LATCH;
  84        legacy_timer_tick(1);
  85        return IRQ_HANDLED;
  86}
  87
  88/*
  89 * Set up timer interrupt.
  90 */
  91void __init ioc_timer_init(void)
  92{
  93        WARN_ON(clocksource_register_hz(&ioctime_clocksource, RPC_CLOCK_FREQ));
  94        ioctime_init();
  95        if (request_irq(IRQ_TIMER0, ioc_timer_interrupt, 0, "timer", NULL))
  96                pr_err("Failed to request irq %d (timer)\n", IRQ_TIMER0);
  97}
  98