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