/* * RTC routines for RICOH Rx5C348 SPI chip. * Copyright (C) 2000-2001 Toshiba Corporation * * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the * terms of the GNU General Public License version 2. This program is * licensed "as is" without any warranty of any kind, whether express * or implied. * * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) */ #include #include #include #include #include #include #include #include #define EPOCH 2000 /* registers */ #define Rx5C348_REG_SECOND 0 #define Rx5C348_REG_MINUTE 1 #define Rx5C348_REG_HOUR 2 #define Rx5C348_REG_WEEK 3 #define Rx5C348_REG_DAY 4 #define Rx5C348_REG_MONTH 5 #define Rx5C348_REG_YEAR 6 #define Rx5C348_REG_ADJUST 7 #define Rx5C348_REG_ALARM_W_MIN 8 #define Rx5C348_REG_ALARM_W_HOUR 9 #define Rx5C348_REG_ALARM_W_WEEK 10 #define Rx5C348_REG_ALARM_D_MIN 11 #define Rx5C348_REG_ALARM_D_HOUR 12 #define Rx5C348_REG_CTL1 14 #define Rx5C348_REG_CTL2 15 /* register bits */ #define Rx5C348_BIT_PM 0x20 /* REG_HOUR */ #define Rx5C348_BIT_Y2K 0x80 /* REG_MONTH */ #define Rx5C348_BIT_24H 0x20 /* REG_CTL1 */ #define Rx5C348_BIT_XSTP 0x10 /* REG_CTL2 */ /* commands */ #define Rx5C348_CMD_W(addr) (((addr) << 4) | 0x08) /* single write */ #define Rx5C348_CMD_R(addr) (((addr) << 4) | 0x0c) /* single read */ #define Rx5C348_CMD_MW(addr) (((addr) << 4) | 0x00) /* burst write */ #define Rx5C348_CMD_MR(addr) (((addr) << 4) | 0x04) /* burst read */ static struct spi_dev_desc srtc_dev_desc = { .baud = 1000000, /* 1.0Mbps @ Vdd 2.0V */ .tcss = 31, .tcsh = 1, .tcsr = 62, /* 31us for Tcss (62us for Tcsr) is required for carry operation) */ .byteorder = 1, /* MSB-First */ .polarity = 0, /* High-Active */ .phase = 1, /* Shift-Then-Sample */ }; static int srtc_chipid; static int srtc_24h; static inline int spi_rtc_io(unsigned char *inbuf, unsigned char *outbuf, unsigned int count) { unsigned char *inbufs[1], *outbufs[1]; unsigned int incounts[2], outcounts[2]; inbufs[0] = inbuf; incounts[0] = count; incounts[1] = 0; outbufs[0] = outbuf; outcounts[0] = count; outcounts[1] = 0; return txx9_spi_io(srtc_chipid, &srtc_dev_desc, inbufs, incounts, outbufs, outcounts, 0); } /* RTC-dependent code for time.c */ static int rtc_rx5c348_set_time(unsigned long t) { unsigned char inbuf[8]; struct rtc_time tm; u8 year, month, day, hour, minute, second, century; /* convert */ to_tm(t, &tm); year = tm.tm_year % 100; month = tm.tm_mon+1; /* tm_mon starts from 0 to 11 */ day = tm.tm_mday; hour = tm.tm_hour; minute = tm.tm_min; second = tm.tm_sec; century = tm.tm_year / 100; inbuf[0] = Rx5C348_CMD_MW(Rx5C348_REG_SECOND); BIN_TO_BCD(second); inbuf[1] = second; BIN_TO_BCD(minute); inbuf[2] = minute; if (srtc_24h) { BIN_TO_BCD(hour); inbuf[3] = hour; } else { /* hour 0 is AM12, noon is PM12 */ inbuf[3] = 0; if (hour >= 12) inbuf[3] = Rx5C348_BIT_PM; hour = (hour + 11) % 12 + 1; BIN_TO_BCD(hour); inbuf[3] |= hour; } inbuf[4] = 0; /* ignore week */ BIN_TO_BCD(day); inbuf[5] = day; BIN_TO_BCD(month); inbuf[6] = month; if (century >= 20) inbuf[6] |= Rx5C348_BIT_Y2K; BIN_TO_BCD(year); inbuf[7] = year; /* write in one transfer to avoid data inconsistency */ return spi_rtc_io(inbuf, NULL, 8); } static unsigned long rtc_rx5c348_get_time(void) { unsigned char inbuf[8], outbuf[8]; unsigned int year, month, day, hour, minute, second; inbuf[0] = Rx5C348_CMD_MR(Rx5C348_REG_SECOND); memset(inbuf + 1, 0, 7); /* read in one transfer to avoid data inconsistency */ if (spi_rtc_io(inbuf, outbuf, 8)) return 0; second = outbuf[1]; BCD_TO_BIN(second); minute = outbuf[2]; BCD_TO_BIN(minute); if (srtc_24h) { hour = outbuf[3]; BCD_TO_BIN(hour); } else { hour = outbuf[3] & ~Rx5C348_BIT_PM; BCD_TO_BIN(hour); hour %= 12; if (outbuf[3] & Rx5C348_BIT_PM) hour += 12; } day = outbuf[5]; BCD_TO_BIN(day); month = outbuf[6] & ~Rx5C348_BIT_Y2K; BCD_TO_BIN(month); year = outbuf[7]; BCD_TO_BIN(year); year += EPOCH; return mktime(year, month, day, hour, minute, second); } void __init rtc_rx5c348_init(int chipid) { unsigned char inbuf[2], outbuf[2]; srtc_chipid = chipid; /* turn on RTC if it is not on */ inbuf[0] = Rx5C348_CMD_R(Rx5C348_REG_CTL2); inbuf[1] = 0; spi_rtc_io(inbuf, outbuf, 2); if (outbuf[1] & Rx5C348_BIT_XSTP) { inbuf[0] = Rx5C348_CMD_W(Rx5C348_REG_CTL2); inbuf[1] = 0; spi_rtc_io(inbuf, NULL, 2); } inbuf[0] = Rx5C348_CMD_R(Rx5C348_REG_CTL1); inbuf[1] = 0; spi_rtc_io(inbuf, outbuf, 2); if (outbuf[1] & Rx5C348_BIT_24H) srtc_24h = 1; /* set the function pointers */ rtc_mips_get_time = rtc_rx5c348_get_time; rtc_mips_set_time = rtc_rx5c348_set_time; }