/* * Copyright 2001 MontaVista Software Inc. * Author: jsun@mvista.com or jsun@junsun.net * * arch/mips/ddb5xxx/common/rtc_ds1386.c * low-level RTC hookups for s for Dallas 1396 chip. * * 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. */ /* * This file exports a function, rtc_ds1386_init(), which expects an * uncached base address as the argument. It will set the two function * pointers expected by the MIPS generic timer code. */ #include #include #include #include #include #include #include #define EPOCH 2000 #define READ_RTC(x) *(volatile unsigned char*)(rtc_base+x) #define WRITE_RTC(x, y) *(volatile unsigned char*)(rtc_base+x) = y static unsigned long rtc_base; static unsigned long rtc_ds1386_get_time(void) { u8 byte; u8 temp; unsigned int year, month, day, hour, minute, second; unsigned long flags; spin_lock_irqsave(&rtc_lock, flags); /* let us freeze external registers */ byte = READ_RTC(0xB); byte &= 0x3f; WRITE_RTC(0xB, byte); /* read time data */ year = BCD2BIN(READ_RTC(0xA)) + EPOCH; month = BCD2BIN(READ_RTC(0x9) & 0x1f); day = BCD2BIN(READ_RTC(0x8)); minute = BCD2BIN(READ_RTC(0x2)); second = BCD2BIN(READ_RTC(0x1)); /* hour is special - deal with it later */ temp = READ_RTC(0x4); /* enable time transfer */ byte |= 0x80; WRITE_RTC(0xB, byte); spin_unlock_irqrestore(&rtc_lock, flags); /* calc hour */ if (temp & 0x40) { /* 12 hour format */ hour = BCD2BIN(temp & 0x1f); if (temp & 0x20) hour += 12; /* PM */ } else { /* 24 hour format */ hour = BCD2BIN(temp & 0x3f); } return mktime(year, month, day, hour, minute, second); } static int rtc_ds1386_set_time(unsigned long t) { struct rtc_time tm; u8 byte; u8 temp; u8 year, month, day, hour, minute, second; unsigned long flags; spin_lock_irqsave(&rtc_lock, flags); /* let us freeze external registers */ byte = READ_RTC(0xB); byte &= 0x3f; WRITE_RTC(0xB, byte); /* convert */ to_tm(t, &tm); /* check each field one by one */ year = BIN2BCD(tm.tm_year - EPOCH); if (year != READ_RTC(0xA)) { WRITE_RTC(0xA, year); } temp = READ_RTC(0x9); month = BIN2BCD(tm.tm_mon+1); /* tm_mon starts from 0 to 11 */ if (month != (temp & 0x1f)) { WRITE_RTC( 0x9, (month & 0x1f) | (temp & ~0x1f) ); } day = BIN2BCD(tm.tm_mday); if (day != READ_RTC(0x8)) { WRITE_RTC(0x8, day); } temp = READ_RTC(0x4); if (temp & 0x40) { /* 12 hour format */ hour = 0x40; if (tm.tm_hour > 12) { hour |= 0x20 | (BIN2BCD(hour-12) & 0x1f); } else { hour |= BIN2BCD(tm.tm_hour); } } else { /* 24 hour format */ hour = BIN2BCD(tm.tm_hour) & 0x3f; } if (hour != temp) WRITE_RTC(0x4, hour); minute = BIN2BCD(tm.tm_min); if (minute != READ_RTC(0x2)) { WRITE_RTC(0x2, minute); } second = BIN2BCD(tm.tm_sec); if (second != READ_RTC(0x1)) { WRITE_RTC(0x1, second); } spin_unlock_irqrestore(&rtc_lock, flags); return 0; } void rtc_ds1386_init(unsigned long base) { unsigned char byte; /* remember the base */ rtc_base = base; db_assert((rtc_base & 0xe0000000) == KSEG1); /* turn on RTC if it is not on */ byte = READ_RTC(0x9); if (byte & 0x80) { byte &= 0x7f; WRITE_RTC(0x9, byte); } /* enable time transfer */ byte = READ_RTC(0xB); byte |= 0x80; WRITE_RTC(0xB, byte); /* set the function pointers */ rtc_mips_get_time = rtc_ds1386_get_time; rtc_mips_set_time = rtc_ds1386_set_time; }