#include "timer.h"
#include "interrupt.h"
#include "uart.h"
#include "event.h"

#define TIMER0BASE  0xE0004000
#define TIMER1BASE  0xE0008000

#define IR    0x00
#define TCR   0x04
#define TC    0x08
#define PR    0x0c
#define PC    0x10
#define MCR   0x14
#define MR0   0x18
#define MR1   0x1C
#define MR2   0x20
#define MR3   0x24
#define CCR   0x28
#define CR0   0x2C
#define CR1   0x30
#define CR2   0x34
#define CR3   0x38
#define EMR   0x3C
#define CTCR  0x70
#define PWM   0x74

#define TREG(x) (((volatile unsigned char *)TIMER0BASE)[x])
#define TWREG(x) (((volatile unsigned int *)TIMER0BASE)[(x)/sizeof(unsigned int)])

#define TCR_ENABLE (1<<0)
#define TCR_RESET  (1<<1)

#define MR0I (1<<0)
#define MR0R (1<<1)
#define MR0S (1<<2)
#define MR1I (1<<3)
#define MR1R (1<<4)
#define MR1S (1<<5)
#define MR2I (1<<6)
#define MR2R (1<<7)
#define MR2S (1<<8)
#define MR3I (1<<9)
#define MR3R (1<<10)
#define MR3S (1<<11)

void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void);

void timer_event_handler(void);

void init_timer(void)
{
	TREG(TCR) = TCR_ENABLE | TCR_RESET;

	TREG(CTCR) = 0; /* Use PCLK */
	TWREG(TC) = 0;
	TWREG(PR) = TIMER_PRESCALE ;
	TWREG(PC) = 0;

	TREG(TCR) = TCR_ENABLE;
}

unsigned int timer_read(void)
{
	return TWREG(TC);
}

void timer_delay_clocks(unsigned int clocks)
{
	signed int time = TWREG(TC) + clocks;
	while (((signed int) (time-TWREG(TC))) > 0);
}

void timer_set_period(unsigned int period)
{
	interrupt_register(TIMER0, timer_interrupt_handler);
	TWREG(MR0) = period;
	TWREG(MCR) = MR0I | MR0R;
	TWREG(TC) = 0;
}

void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void)
{
	unsigned int ir;
	ir = TREG(IR);
	TREG(IR) = ir;

	if (ir & (1<<0)) {
		/* Match channel 0 */
		event_set(EVENT_TIMER);
	}

	interrupt_clear();
}
