/*
 * Copyright (C) 2006  Ikanos Communications. All rights reserved.
 * The information and source code contained herein is the property
 * of Ikanos Communications. 
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 */

/***
 * AD6843 Control Processor Timer Routines
 * Copyright (C) 2001-2005 Analog Devices Incorporated
 * Author: Leo @ analog devices
 
 ***/

#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <asm/io.h>
#include <asm/hardirq.h>
#include <adi6843.h>
#include <timer.h>
#include <exports.h>

static volatile struct timer_regs *tregs = 
			(volatile struct timer_regs *)KSEG1ADDR(0x19070000);

void adi_6843_timer_interrupt(struct pt_regs *regs)
{
	u16 temp;

	/* find out who has interrupted us */
	temp = tregs->status & 0x1;

	if(temp)  
	{
		/* acknowledge the interrupt(s) */
		tregs->status = temp;
		do_IRQ(GPT1_INT, regs);
	}
}

/* In linux, the clock is set to a tick rate of 100 hz. */
void plat_timer_setup(struct irqaction *irq)
{
	unsigned long period;
	unsigned long width;
	unsigned long flags;

	/* Lock Local Interrupts */
	local_irq_save(flags);

	tregs->status = 0x0200;

	setup_irq(GPT1_INT, irq);

        /* I want to make sure that for timer interrupt, SA_INTERRUPT bit is always there
	   other my PIC will trouble me as I am handling timer interrupt seperately from
	   other priority level interrupts. Good Luck Timer.
	   Well, I know this FLAG is already asserted in kernel/time.c but still I want to
	   make 100% sure it is there because this is the point where I am programming my
	   IRQ so let it be MUST. 
	 */
	irq->flags = SA_INTERRUPT;
	period = 99*1000*1000 / HZ;
	width = period / 2;

	/* This configures the timer as follows:
	 * PWM_OUT Mode
	 * Positive Active Pulse
	 * Count to end of Period
	 * Interrupt Request Enable
	 */
	
	tregs->config = 0x001d;

	/* Write top half of period register */
	tregs->period_hi = period >> 16;

	/* Write bottom half of period register */
	tregs->period_lo = (period & 0xffff);

	/* Write top half of width register */
	tregs->width_hi = width >> 16;
    
	/* Write bottom half of width register */
	tregs->width_lo = (width & 0xffff);

	/* Set TIMEN0 and clear any lingering interrupts */
	tregs->status = 0x0101;
	
	/* Restore Interrupts */
	local_irq_restore(flags);


}
