timers.c 3.42 KB
Newer Older
정종선 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
/***************************************************************************/

/*
 *  timers.c - Generic hardware timer support.
 *
 *  Copyright (C) 1993 Hamish Macdonald
 *  Copyright (C) 1999 D. Jeff Dionne
 *  Copyright (C) 2001 Georges Menie, Ken Desmet
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */

/***************************************************************************/

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clocksource.h>
#include <linux/rtc.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
#include <asm/machdep.h>
#include <asm/MC68VZ328.h>

/***************************************************************************/

#if defined(CONFIG_DRAGEN2)
/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
#define CLOCK_SOURCE	TCTL_CLKSOURCE_SYSCLK
#define CLOCK_PRE	7
#define TICKS_PER_JIFFY	41450

#elif defined(CONFIG_XCOPILOT_BUGS)
/*
 * The only thing I know is that CLK32 is not available on Xcopilot
 * I have little idea about what frequency SYSCLK has on Xcopilot.
 * The values for prescaler and compare registers were simply
 * taken from the original source
 */
#define CLOCK_SOURCE	TCTL_CLKSOURCE_SYSCLK
#define CLOCK_PRE	2
#define TICKS_PER_JIFFY	0xd7e4

#else
/* default to using the 32Khz clock */
#define CLOCK_SOURCE	TCTL_CLKSOURCE_32KHZ
#define CLOCK_PRE	31
#define TICKS_PER_JIFFY	10
#endif

static u32 m68328_tick_cnt;
static irq_handler_t timer_interrupt;

/***************************************************************************/

static irqreturn_t hw_tick(int irq, void *dummy)
{
	/* Reset Timer1 */
	TSTAT &= 0;

	m68328_tick_cnt += TICKS_PER_JIFFY;
	return timer_interrupt(irq, dummy);
}

/***************************************************************************/

static struct irqaction m68328_timer_irq = {
	.name	 = "timer",
	.flags	 = IRQF_TIMER,
	.handler = hw_tick,
};

/***************************************************************************/

static cycle_t m68328_read_clk(struct clocksource *cs)
{
	unsigned long flags;
	u32 cycles;

	local_irq_save(flags);
	cycles = m68328_tick_cnt + TCN;
	local_irq_restore(flags);

	return cycles;
}

/***************************************************************************/

static struct clocksource m68328_clk = {
	.name	= "timer",
	.rating	= 250,
	.read	= m68328_read_clk,
	.mask	= CLOCKSOURCE_MASK(32),
	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
};

/***************************************************************************/

void hw_timer_init(irq_handler_t handler)
{
	/* disable timer 1 */
	TCTL = 0;

	/* set ISR */
	setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);

	/* Restart mode, Enable int, Set clock source */
	TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
	TPRER = CLOCK_PRE;
	TCMP = TICKS_PER_JIFFY;

	/* Enable timer 1 */
	TCTL |= TCTL_TEN;
	clocksource_register_hz(&m68328_clk, TICKS_PER_JIFFY*HZ);
	timer_interrupt = handler;
}

/***************************************************************************/

int m68328_hwclk(int set, struct rtc_time *t)
{
	if (!set) {
		long now = RTCTIME;
		t->tm_year = t->tm_mon = t->tm_mday = 1;
		t->tm_hour = (now >> 24) % 24;
		t->tm_min = (now >> 16) % 60;
		t->tm_sec = now % 60;
	}

	return 0;
}

/***************************************************************************/