123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- /*
- * 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 <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/rtc.h>
- #include <linux/time.h>
- #include <linux/bcd.h>
- #include <asm/time.h>
- #include <asm/tx4938/spi.h>
- #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;
- }
|