/*
 * 8254.c: High resolution timer support for PCs and other machines using
 *         the 8254 timer chip (or compatible).
 *
 * Copyright (C) 2000 TimeSys Corporation
 *
 * This is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * This file is derived from software distributed under the following terms:
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/timex.h>
#include <rk/rk_linux.h>
#include <rk/rk.h>

/* this defines the minimum # of microseconds used for the timer */
#define RK_MIN_TIMER		1

int timer_val = 0;
extern int debug;

/* Set the 8254 to go off when the first timer expires */
void rk_update_hw_timer(struct rk_timer *tmr)
{
    extern void check_timer_list(void);
    cpu_tick_data_t now;
    int val;

    outb_p(0x30, 0x43);		/* binary, counter 0, int on terminal count */

    rk_rdtsc(&now);
    if (tmr->tmr_expire < now) {
	/* timer has already passed the current time! set 1us timer */
	val = RK_MIN_TIMER;
    } else {
	val =
	    ((tmr->tmr_expire - now) * CLOCK_TICK_RATE) /
	    rk_cpu_ticks_per_second;

	if (val > 0xffff) {
	    printk("8254: rk_update_hw_timer (type: %d): "
		   "delay 0x%x too long, no jiffies? (now=%Ld)\n",
		   tmr->tmr_type, val, now);
	    val = 0xffff;
	    check_timer_list();
	} else if (val <= 0)
	    val = RK_MIN_TIMER;	/* expires very soon: impose minimum delay */
    }
    outb_p(val & 0xff, 0x40);
    outb(val >> 8, 0x40);
}

/* Set the 8254 to 100Hz (or whatever else HZ is set to) periodic mode */
void rk_hw_timer_set_periodic(void)
{
    int val = CLOCK_TICK_RATE / HZ;

    outb_p(0x34, 0x43);		/* binary, counter 0, periodic */
    outb_p(val & 0xff, 0x40);
    outb(val >> 8, 0x40);
}
