diff options
| -rw-r--r-- | arch/arm/mach-at91rm9200/Makefile | 4 | ||||
| -rw-r--r-- | arch/arm/mach-at91rm9200/at91sam926x_time.c | 114 | ||||
| -rw-r--r-- | include/asm-arm/arch-at91rm9200/at91_pit.h | 29 |
3 files changed, 145 insertions, 2 deletions
diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91rm9200/Makefile index 40e89bf459f1..b8684ba60ceb 100644 --- a/arch/arm/mach-at91rm9200/Makefile +++ b/arch/arm/mach-at91rm9200/Makefile | |||
| @@ -11,8 +11,8 @@ obj-$(CONFIG_PM) += pm.o | |||
| 11 | 11 | ||
| 12 | # CPU-specific support | 12 | # CPU-specific support |
| 13 | obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.c | 13 | obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.c |
| 14 | obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o | 14 | obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o |
| 15 | obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o | 15 | obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o |
| 16 | 16 | ||
| 17 | # AT91RM9200 board-specific support | 17 | # AT91RM9200 board-specific support |
| 18 | obj-$(CONFIG_MACH_ONEARM) += board-1arm.o | 18 | obj-$(CONFIG_MACH_ONEARM) += board-1arm.o |
diff --git a/arch/arm/mach-at91rm9200/at91sam926x_time.c b/arch/arm/mach-at91rm9200/at91sam926x_time.c new file mode 100644 index 000000000000..99df5f6ee42e --- /dev/null +++ b/arch/arm/mach-at91rm9200/at91sam926x_time.c | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-at91rm9200/at91sam926x_time.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France | ||
| 5 | * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/interrupt.h> | ||
| 14 | #include <linux/irq.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/sched.h> | ||
| 17 | #include <linux/time.h> | ||
| 18 | |||
| 19 | #include <asm/hardware.h> | ||
| 20 | #include <asm/io.h> | ||
| 21 | #include <asm/mach/time.h> | ||
| 22 | |||
| 23 | #include <asm/arch/at91_pit.h> | ||
| 24 | |||
| 25 | |||
| 26 | #define PIT_CPIV(x) ((x) & AT91_PIT_CPIV) | ||
| 27 | #define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20) | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Returns number of microseconds since last timer interrupt. Note that interrupts | ||
| 31 | * will have been disabled by do_gettimeofday() | ||
| 32 | * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. | ||
| 33 | * 'tick' is usecs per jiffy (linux/timex.h). | ||
| 34 | */ | ||
| 35 | static unsigned long at91sam926x_gettimeoffset(void) | ||
| 36 | { | ||
| 37 | unsigned long elapsed; | ||
| 38 | unsigned long t = at91_sys_read(AT91_PIT_PIIR); | ||
| 39 | |||
| 40 | elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t); /* hardware clock cycles */ | ||
| 41 | |||
| 42 | return (unsigned long)(elapsed * 1000000) / LATCH; | ||
| 43 | } | ||
| 44 | |||
| 45 | /* | ||
| 46 | * IRQ handler for the timer. | ||
| 47 | */ | ||
| 48 | static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id) | ||
| 49 | { | ||
| 50 | volatile long nr_ticks; | ||
| 51 | |||
| 52 | if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */ | ||
| 53 | write_seqlock(&xtime_lock); | ||
| 54 | |||
| 55 | /* Get number to ticks performed before interrupt and clear PIT interrupt */ | ||
| 56 | nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR)); | ||
| 57 | do { | ||
| 58 | timer_tick(); | ||
| 59 | nr_ticks--; | ||
| 60 | } while (nr_ticks); | ||
| 61 | |||
| 62 | write_sequnlock(&xtime_lock); | ||
| 63 | return IRQ_HANDLED; | ||
| 64 | } else | ||
| 65 | return IRQ_NONE; /* not handled */ | ||
| 66 | } | ||
| 67 | |||
| 68 | static struct irqaction at91sam926x_timer_irq = { | ||
| 69 | .name = "at91_tick", | ||
| 70 | .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER, | ||
| 71 | .handler = at91sam926x_timer_interrupt | ||
| 72 | }; | ||
| 73 | |||
| 74 | void at91sam926x_timer_reset(void) | ||
| 75 | { | ||
| 76 | /* Disable timer */ | ||
| 77 | at91_sys_write(AT91_PIT_MR, 0); | ||
| 78 | |||
| 79 | /* Clear any pending interrupts */ | ||
| 80 | (void) at91_sys_read(AT91_PIT_PIVR); | ||
| 81 | |||
| 82 | /* Set Period Interval timer and enable its interrupt */ | ||
| 83 | at91_sys_write(AT91_PIT_MR, (LATCH & AT91_PIT_PIV) | AT91_PIT_PITIEN | AT91_PIT_PITEN); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Set up timer interrupt. | ||
| 88 | */ | ||
| 89 | void __init at91sam926x_timer_init(void) | ||
| 90 | { | ||
| 91 | /* Initialize and enable the timer */ | ||
| 92 | at91sam926x_timer_reset(); | ||
| 93 | |||
| 94 | /* Make IRQs happen for the system timer. */ | ||
| 95 | setup_irq(AT91_ID_SYS, &at91sam926x_timer_irq); | ||
| 96 | } | ||
| 97 | |||
| 98 | #ifdef CONFIG_PM | ||
| 99 | static void at91sam926x_timer_suspend(void) | ||
| 100 | { | ||
| 101 | /* Disable timer */ | ||
| 102 | at91_sys_write(AT91_PIT_MR, 0); | ||
| 103 | } | ||
| 104 | #else | ||
| 105 | #define at91sam926x_timer_suspend NULL | ||
| 106 | #endif | ||
| 107 | |||
| 108 | struct sys_timer at91sam926x_timer = { | ||
| 109 | .init = at91sam926x_timer_init, | ||
| 110 | .offset = at91sam926x_gettimeoffset, | ||
| 111 | .suspend = at91sam926x_timer_suspend, | ||
| 112 | .resume = at91sam926x_timer_reset, | ||
| 113 | }; | ||
| 114 | |||
diff --git a/include/asm-arm/arch-at91rm9200/at91_pit.h b/include/asm-arm/arch-at91rm9200/at91_pit.h new file mode 100644 index 000000000000..4a30d009c588 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91_pit.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * include/asm-arm/arch-at91rm9200/at91_pit.h | ||
| 3 | * | ||
| 4 | * Periodic Interval Timer (PIT) - System peripherals regsters. | ||
| 5 | * Based on AT91SAM9261 datasheet revision D. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef AT91_PIT_H | ||
| 14 | #define AT91_PIT_H | ||
| 15 | |||
| 16 | #define AT91_PIT_MR (AT91_PIT + 0x00) /* Mode Register */ | ||
| 17 | #define AT91_PIT_PITIEN (1 << 25) /* Timer Interrupt Enable */ | ||
| 18 | #define AT91_PIT_PITEN (1 << 24) /* Timer Enabled */ | ||
| 19 | #define AT91_PIT_PIV (0xfffff) /* Periodic Interval Value */ | ||
| 20 | |||
| 21 | #define AT91_PIT_SR (AT91_PIT + 0x04) /* Status Register */ | ||
| 22 | #define AT91_PIT_PITS (1 << 0) /* Timer Status */ | ||
| 23 | |||
| 24 | #define AT91_PIT_PIVR (AT91_PIT + 0x08) /* Periodic Interval Value Register */ | ||
| 25 | #define AT91_PIT_PIIR (AT91_PIT + 0x0c) /* Periodic Interval Image Register */ | ||
| 26 | #define AT91_PIT_PICNT (0xfff << 20) /* Interval Counter */ | ||
| 27 | #define AT91_PIT_CPIV (0xfffff) /* Inverval Value */ | ||
| 28 | |||
| 29 | #endif | ||
