isa-timer.c 2.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6
/*
 *  linux/arch/arm/mach-footbridge/isa-timer.c
 *
 *  Copyright (C) 1998 Russell King.
 *  Copyright (C) 1998 Phil Blundell
 */
7 8
#include <linux/clockchips.h>
#include <linux/clocksource.h>
L
Linus Torvalds 已提交
9 10
#include <linux/init.h>
#include <linux/interrupt.h>
11
#include <linux/irq.h>
12
#include <linux/io.h>
13
#include <linux/timex.h>
L
Linus Torvalds 已提交
14 15 16 17 18 19 20

#include <asm/irq.h>

#include <asm/mach/time.h>

#include "common.h"

21 22 23 24
#define PIT_MODE	0x43
#define PIT_CH0		0x40

#define PIT_LATCH	((PIT_TICK_RATE + HZ / 2) / HZ)
L
Linus Torvalds 已提交
25

26
static cycle_t pit_read(struct clocksource *cs)
L
Linus Torvalds 已提交
27
{
28 29 30
	unsigned long flags;
	static int old_count;
	static u32 old_jifs;
L
Linus Torvalds 已提交
31
	int count;
32
	u32 jifs;
L
Linus Torvalds 已提交
33

34
	raw_local_irq_save(flags);
L
Linus Torvalds 已提交
35

36 37 38 39
	jifs = jiffies;
	outb_p(0x00, PIT_MODE);		/* latch the count */
	count = inb_p(PIT_CH0);		/* read the latched count */
	count |= inb_p(PIT_CH0) << 8;
L
Linus Torvalds 已提交
40

41 42
	if (count > old_count && jifs == old_jifs)
		count = old_count;
L
Linus Torvalds 已提交
43

44 45
	old_count = count;
	old_jifs = jifs;
L
Linus Torvalds 已提交
46

47
	raw_local_irq_restore(flags);
L
Linus Torvalds 已提交
48

49
	count = (PIT_LATCH - 1) - count;
L
Linus Torvalds 已提交
50

51 52
	return (cycle_t)(jifs * PIT_LATCH) + count;
}
L
Linus Torvalds 已提交
53

54 55 56 57 58 59
static struct clocksource pit_cs = {
	.name		= "pit",
	.rating		= 110,
	.read		= pit_read,
	.mask		= CLOCKSOURCE_MASK(32),
};
L
Linus Torvalds 已提交
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
static void pit_set_mode(enum clock_event_mode mode,
	struct clock_event_device *evt)
{
	unsigned long flags;

	raw_local_irq_save(flags);

	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		outb_p(0x34, PIT_MODE);
		outb_p(PIT_LATCH & 0xff, PIT_CH0);
		outb_p(PIT_LATCH >> 8, PIT_CH0);
		break;

	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_UNUSED:
		outb_p(0x30, PIT_MODE);
		outb_p(0, PIT_CH0);
		outb_p(0, PIT_CH0);
		break;

	case CLOCK_EVT_MODE_ONESHOT:
	case CLOCK_EVT_MODE_RESUME:
		break;
	}
	local_irq_restore(flags);
}
L
Linus Torvalds 已提交
88

89 90 91 92
static int pit_set_next_event(unsigned long delta,
	struct clock_event_device *evt)
{
	return 0;
L
Linus Torvalds 已提交
93 94
}

95 96 97 98 99 100 101 102 103
static struct clock_event_device pit_ce = {
	.name		= "pit",
	.features	= CLOCK_EVT_FEAT_PERIODIC,
	.set_mode	= pit_set_mode,
	.set_next_event	= pit_set_next_event,
	.shift		= 32,
};

static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
104
{
105 106
	struct clock_event_device *ce = dev_id;
	ce->event_handler(ce);
L
Linus Torvalds 已提交
107 108 109
	return IRQ_HANDLED;
}

110 111 112
static struct irqaction pit_timer_irq = {
	.name		= "pit",
	.handler	= pit_timer_interrupt,
B
Bernhard Walle 已提交
113
	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
114
	.dev_id		= &pit_ce,
L
Linus Torvalds 已提交
115 116 117 118
};

static void __init isa_timer_init(void)
{
119 120 121 122 123 124
	pit_ce.cpumask = cpumask_of(smp_processor_id());
	pit_ce.mult = div_sc(PIT_TICK_RATE, NSEC_PER_SEC, pit_ce.shift);
	pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce);
	pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce);

	clocksource_register_hz(&pit_cs, PIT_TICK_RATE);
L
Linus Torvalds 已提交
125

126 127
	setup_irq(pit_ce.irq, &pit_timer_irq);
	clockevents_register_device(&pit_ce);
L
Linus Torvalds 已提交
128 129 130 131 132
}

struct sys_timer isa_timer = {
	.init		= isa_timer_init,
};