linux/arch/arm/mach-rpc/time.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/common/time-acorn.c
   3 *
   4 *  Copyright (c) 1996-2000 Russell King.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 *  Changelog:
  11 *   24-Sep-1996        RMK     Created
  12 *   10-Oct-1996        RMK     Brought up to date with arch-sa110eval
  13 *   04-Dec-1997        RMK     Updated for new arch/arm/time.c
  14 *   13=Jun-2004        DS      Moved to arch/arm/common b/c shared w/CLPS7500
  15 */
  16#include <linux/timex.h>
  17#include <linux/init.h>
  18#include <linux/interrupt.h>
  19#include <linux/irq.h>
  20#include <linux/io.h>
  21
  22#include <mach/hardware.h>
  23#include <asm/hardware/ioc.h>
  24
  25#include <asm/mach/time.h>
  26
  27#define RPC_CLOCK_FREQ 2000000
  28#define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ)
  29
  30static u32 ioc_timer_gettimeoffset(void)
  31{
  32        unsigned int count1, count2, status;
  33        long offset;
  34
  35        ioc_writeb (0, IOC_T0LATCH);
  36        barrier ();
  37        count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
  38        barrier ();
  39        status = ioc_readb(IOC_IRQREQA);
  40        barrier ();
  41        ioc_writeb (0, IOC_T0LATCH);
  42        barrier ();
  43        count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
  44
  45        offset = count2;
  46        if (count2 < count1) {
  47                /*
  48                 * We have not had an interrupt between reading count1
  49                 * and count2.
  50                 */
  51                if (status & (1 << 5))
  52                        offset -= RPC_LATCH;
  53        } else if (count2 > count1) {
  54                /*
  55                 * We have just had another interrupt between reading
  56                 * count1 and count2.
  57                 */
  58                offset -= RPC_LATCH;
  59        }
  60
  61        offset = (RPC_LATCH - offset) * (tick_nsec / 1000);
  62        return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000;
  63}
  64
  65void __init ioctime_init(void)
  66{
  67        ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL);
  68        ioc_writeb(RPC_LATCH >> 8, IOC_T0LTCHH);
  69        ioc_writeb(0, IOC_T0GO);
  70}
  71
  72static irqreturn_t
  73ioc_timer_interrupt(int irq, void *dev_id)
  74{
  75        timer_tick();
  76        return IRQ_HANDLED;
  77}
  78
  79static struct irqaction ioc_timer_irq = {
  80        .name           = "timer",
  81        .handler        = ioc_timer_interrupt
  82};
  83
  84/*
  85 * Set up timer interrupt.
  86 */
  87void __init ioc_timer_init(void)
  88{
  89        arch_gettimeoffset = ioc_timer_gettimeoffset;
  90        ioctime_init();
  91        setup_irq(IRQ_TIMER0, &ioc_timer_irq);
  92}
  93