blob: e97f93a0af1def139656dd79200d1f9872806500 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/arch/arm/common/time-acorn.c
4 *
5 * Copyright (c) 1996-2000 Russell King.
6 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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/timex.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +010016#include <linux/irq.h>
Russell Kingfced80c2008-09-06 12:10:45 +010017#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
Russell Kinga09e64f2008-08-05 16:14:15 +010019#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/hardware/ioc.h>
21
22#include <asm/mach/time.h>
23
Uwe Kleine-König53985372013-12-19 22:22:23 +010024#define RPC_CLOCK_FREQ 2000000
25#define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ)
26
Stephen Warren23c197b2012-11-08 11:51:58 -070027static u32 ioc_timer_gettimeoffset(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070028{
29 unsigned int count1, count2, status;
30 long offset;
31
32 ioc_writeb (0, IOC_T0LATCH);
33 barrier ();
34 count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
35 barrier ();
36 status = ioc_readb(IOC_IRQREQA);
37 barrier ();
38 ioc_writeb (0, IOC_T0LATCH);
39 barrier ();
40 count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
41
42 offset = count2;
43 if (count2 < count1) {
44 /*
45 * We have not had an interrupt between reading count1
46 * and count2.
47 */
48 if (status & (1 << 5))
Uwe Kleine-König53985372013-12-19 22:22:23 +010049 offset -= RPC_LATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 } else if (count2 > count1) {
51 /*
52 * We have just had another interrupt between reading
53 * count1 and count2.
54 */
Uwe Kleine-König53985372013-12-19 22:22:23 +010055 offset -= RPC_LATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 }
57
Uwe Kleine-König53985372013-12-19 22:22:23 +010058 offset = (RPC_LATCH - offset) * (tick_nsec / 1000);
59 return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060}
61
62void __init ioctime_init(void)
63{
Uwe Kleine-König53985372013-12-19 22:22:23 +010064 ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL);
65 ioc_writeb(RPC_LATCH >> 8, IOC_T0LTCHH);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 ioc_writeb(0, IOC_T0GO);
67}
68
69static irqreturn_t
Linus Torvalds0cd61b62006-10-06 10:53:39 -070070ioc_timer_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
Linus Torvalds0cd61b62006-10-06 10:53:39 -070072 timer_tick();
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 return IRQ_HANDLED;
74}
75
76static struct irqaction ioc_timer_irq = {
77 .name = "timer",
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 .handler = ioc_timer_interrupt
79};
80
81/*
82 * Set up timer interrupt.
83 */
Stephen Warren6bb27d72012-11-08 12:40:59 -070084void __init ioc_timer_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
Stephen Warren23c197b2012-11-08 11:51:58 -070086 arch_gettimeoffset = ioc_timer_gettimeoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 ioctime_init();
Russell King927b6c42012-03-01 16:55:44 +000088 setup_irq(IRQ_TIMER0, &ioc_timer_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}