/*
 * Copyright(C) 2014 Yoshinori Sato <ysato@users.sourceforge.jp>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <rtc.h>
#include <bcd.h>
#include <asm/io.h>

#define R64CNT	0x8c400
#define RSECCNT	0x8c402
#define RMINCNT	0x8c404
#define RHRCNT	0x8c406
#define RWKCNT	0x8c408
#define RDAYCNT	0x8c40a
#define RMONCNT	0x8c40c
#define RYRCNT	0x8c40e
#define RSECAR	0x8c410
#define RMINAR	0x8c412
#define RHRAR	0x8c414
#define RWKAR	0x8c416
#define RDAYAR	0x8c418
#define RMONAR	0x8c41a
#define RYRAR	0x8c41c
#define RYRAREN	0x8c41e
#define RCR1	0x8c422
#define RCR2	0x8c424
#define RCR3	0x8c426
#define RCR4	0x8c428
#define RFRH	0x8c42a
#define RFRL	0x8c42c
#define RADJ	0x8c42e
#define RTCCR0	0x8c440
#define RTCCR1	0x8c442
#define RTCCR2	0x8c444
#define RSECCP0	0x8c452
#define RSECCP1	0x8c462
#define RSECCP2	0x8c472
#define RMINCP0	0x8c454
#define RMINCP1	0x8c464
#define RMINCP2	0x8c474
#define RHRCP0	0x8c456
#define RHRCP1	0x8c466
#define RHRCP2	0x8c476
#define RDAYCP0	0x8c45a
#define RDAYCP1	0x8c46a
#define RDAYCP2	0x8c47a
#define RMONCP0	0x8c45c
#define RMONCP1	0x8c46c
#define RMONCP2	0x8c47c

static inline unsigned int bcd2bin16(u16 val)
{
	return bcd2bin(val >> 8) * 100 + bcd2bin(val & 0xff);
}

static inline u16 bin2bcd16(unsigned int val)
{
	return bin2bcd(val / 100) << 8 | bin2bcd(val % 100);
}

int rtc_get (struct rtc_time *tmp)
{
	char month,day,week,hour,min,sec;
	char sec1;
	short year;

	do {
		sec = __raw_readb(RSECCNT);
		min = __raw_readb(RMINCNT);
		hour = __raw_readb(RHRCNT) & 0x3f;
		week = __raw_readb(RWKCNT);
		day = __raw_readb(RDAYCNT);
		month = __raw_readb(RMONCNT);
		year = __raw_readw(RYRCNT);
		sec1 = __raw_readb(RSECCNT);
	} while(sec != sec1);
	tmp->tm_sec = bcd2bin(sec);
	tmp->tm_min = bcd2bin(min);
	tmp->tm_hour = bcd2bin(hour);
	tmp->tm_wday = week;
	tmp->tm_mday = bcd2bin(day);
	tmp->tm_mon = bcd2bin(month);
#if !defined(CONFIG_CPU_RX62X)
	tmp->tm_year = bcd2bin16(year) + 2000;
#else
	tmp->tm_year = bcd2bin16(year);
#endif
	return 0;
}

int rtc_set (struct rtc_time *tmp)
{
	__raw_writeb(__raw_readb(RCR2) & 0xfe, RCR2);
	while(__raw_readb(RCR2) & 0x01);
	__raw_writeb(bin2bcd(tmp->tm_sec), RSECCNT);
	__raw_writeb(bin2bcd(tmp->tm_min), RMINCNT);
	__raw_writeb(bin2bcd(tmp->tm_hour), RHRCNT);
	__raw_writeb(bin2bcd(tmp->tm_wday), RWKCNT);
	__raw_writeb(bin2bcd(tmp->tm_mday), RDAYCNT);
	__raw_writeb(bin2bcd(tmp->tm_mon), RMONCNT);
#if !defined(CONFIG_CPU_RX62X)
	__raw_writew(bin2bcd16(tmp->tm_year) - 0x2000, RYRCNT);
	__raw_writeb(__raw_readb(RCR2) | 0x41, RCR2);
#else
	__raw_writew(bin2bcd16(tmp->tm_year), RYRCNT);
	__raw_writeb(__raw_readb(RCR2) | 0x01, RCR2);
#endif
	while(!(__raw_readb(RCR2) & 0x01));
	return 0;
}

void rtc_reset (void)
{
	__raw_writeb(__raw_readb(RCR2) | 0x02, RCR2);
	while(__raw_readb(RCR2) & 0x02);
}
