#ifndef __TIME_H__
#define __TIME_H__

/*
 * Copyright (C) 2003 Claudio Scordino
 * This is Free Software; see GPL.txt for details
 */

#include <linux/module.h>
#include <asm-arm/arch-pxa/hardware.h>
#include <asm-arm/arch-pxa/timex.h>
#include <linux/timex.h>
#include <asm-arm/arch-pxa/pxa-regs.h>
#include <sys/time.h>

#define SCALE  1

long tick = (1000000 + HZ/2) / HZ;      /* timer interrupt period */

static inline unsigned long long llimd(unsigned long long ll, unsigned long mult, unsigned long div);

static inline unsigned long long int rdtsc (void)
{
   struct timeval t;
   unsigned long long int res;
   gettimeofday(&t,NULL);
   res = llimd(t.tv_sec,1000000,1);
   res += t.tv_usec;
   return res;
}


static inline unsigned long long int us2clock(unsigned long u)
{
  return llimd(u, LATCH, tick);
}

static inline unsigned long int clock2ms(unsigned long long c)
{
  return (unsigned long int)(llimd(c, tick, LATCH)/1000);
}

static inline unsigned long int clock2us(unsigned long long c)
{
  return (unsigned long int) llimd(c, tick, LATCH);
}

static inline unsigned long int clock2jiffies(unsigned long long c)
{
  unsigned long long int tmp;
  tmp = llimd(c, tick, LATCH);

  return llimd(tmp, HZ, 1000000);
}


/* These functions come from RTAI (http://www.rtai.org) */

/* not all ARM cores support 32bit x 32bit = 64bit native ... */
static inline unsigned long long ullmul(unsigned long m0, unsigned long m1)
{
        unsigned long long res;

        res = (unsigned long long)m0 * (unsigned long long)m1;

        return res;
}

static inline unsigned long long ulldiv(unsigned long long ull, unsigned long uld, unsigned long *r)
{
	unsigned long long q = ull/(unsigned long long) uld;

	*r = (unsigned long) (ull - q * (unsigned long long) uld);

	return q;	
}

static inline unsigned long long llimd(unsigned long long ull, unsigned long mult, unsigned long div)
{
	unsigned long long low, high, q;
	unsigned long r;

	low  = ullmul(((unsigned long *)&ull)[0], mult);
	high = ullmul(((unsigned long *)&ull)[1], mult);
	q = ulldiv(high,div,&r) << 32;
	high = ((unsigned long long) r) << 32;
	q += ulldiv( high + low, div , &r);
	return (r + r) < div ? q : q + 1;
}
#endif /* __TIME_H__ */
