1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a1be5d64SRussell King /* 3a1be5d64SRussell King * linux/arch/arm/common/time-acorn.c 4a1be5d64SRussell King * 5a1be5d64SRussell King * Copyright (c) 1996-2000 Russell King. 6a1be5d64SRussell King * 7a1be5d64SRussell King * Changelog: 8a1be5d64SRussell King * 24-Sep-1996 RMK Created 9a1be5d64SRussell King * 10-Oct-1996 RMK Brought up to date with arch-sa110eval 10a1be5d64SRussell King * 04-Dec-1997 RMK Updated for new arch/arm/time.c 11a1be5d64SRussell King * 13=Jun-2004 DS Moved to arch/arm/common b/c shared w/CLPS7500 12a1be5d64SRussell King */ 13a1be5d64SRussell King #include <linux/timex.h> 14a1be5d64SRussell King #include <linux/init.h> 15a1be5d64SRussell King #include <linux/interrupt.h> 16a1be5d64SRussell King #include <linux/irq.h> 17a1be5d64SRussell King #include <linux/io.h> 18a1be5d64SRussell King 19a1be5d64SRussell King #include <mach/hardware.h> 20a1be5d64SRussell King #include <asm/hardware/ioc.h> 21a1be5d64SRussell King 22a1be5d64SRussell King #include <asm/mach/time.h> 23a1be5d64SRussell King 2453985371SUwe Kleine-König #define RPC_CLOCK_FREQ 2000000 2553985371SUwe Kleine-König #define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ) 2653985371SUwe Kleine-König 2723c197b7SStephen 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)) 4953985371SUwe Kleine-König offset -= RPC_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 */ 5553985371SUwe Kleine-König offset -= RPC_LATCH; 56a1be5d64SRussell King } 57a1be5d64SRussell King 5853985371SUwe Kleine-König offset = (RPC_LATCH - offset) * (tick_nsec / 1000); 5953985371SUwe Kleine-König return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000; 60a1be5d64SRussell King } 61a1be5d64SRussell King 62a1be5d64SRussell King void __init ioctime_init(void) 63a1be5d64SRussell King { 6453985371SUwe Kleine-König ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL); 6553985371SUwe Kleine-König ioc_writeb(RPC_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 .handler = ioc_timer_interrupt 79a1be5d64SRussell King }; 80a1be5d64SRussell King 81a1be5d64SRussell King /* 82a1be5d64SRussell King * Set up timer interrupt. 83a1be5d64SRussell King */ 846bb27d73SStephen Warren void __init ioc_timer_init(void) 85a1be5d64SRussell King { 8623c197b7SStephen Warren arch_gettimeoffset = ioc_timer_gettimeoffset; 87a1be5d64SRussell King ioctime_init(); 88927b6c4dSRussell King setup_irq(IRQ_TIMER0, &ioc_timer_irq); 89a1be5d64SRussell King } 90