1/* 2 * RTC routines for RICOH Rx5C348 SPI chip. 3 * Copyright (C) 2000-2001 Toshiba Corporation 4 * 5 * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the 6 * terms of the GNU General Public License version 2. This program is 7 * licensed "as is" without any warranty of any kind, whether express 8 * or implied. 9 * 10 * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) 11 */ 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/string.h> 15#include <linux/rtc.h> 16#include <linux/time.h> 17#include <linux/bcd.h> 18#include <asm/time.h> 19#include <asm/tx4938/spi.h> 20 21#define EPOCH 2000 22 23/* registers */ 24#define Rx5C348_REG_SECOND 0 25#define Rx5C348_REG_MINUTE 1 26#define Rx5C348_REG_HOUR 2 27#define Rx5C348_REG_WEEK 3 28#define Rx5C348_REG_DAY 4 29#define Rx5C348_REG_MONTH 5 30#define Rx5C348_REG_YEAR 6 31#define Rx5C348_REG_ADJUST 7 32#define Rx5C348_REG_ALARM_W_MIN 8 33#define Rx5C348_REG_ALARM_W_HOUR 9 34#define Rx5C348_REG_ALARM_W_WEEK 10 35#define Rx5C348_REG_ALARM_D_MIN 11 36#define Rx5C348_REG_ALARM_D_HOUR 12 37#define Rx5C348_REG_CTL1 14 38#define Rx5C348_REG_CTL2 15 39 40/* register bits */ 41#define Rx5C348_BIT_PM 0x20 /* REG_HOUR */ 42#define Rx5C348_BIT_Y2K 0x80 /* REG_MONTH */ 43#define Rx5C348_BIT_24H 0x20 /* REG_CTL1 */ 44#define Rx5C348_BIT_XSTP 0x10 /* REG_CTL2 */ 45 46/* commands */ 47#define Rx5C348_CMD_W(addr) (((addr) << 4) | 0x08) /* single write */ 48#define Rx5C348_CMD_R(addr) (((addr) << 4) | 0x0c) /* single read */ 49#define Rx5C348_CMD_MW(addr) (((addr) << 4) | 0x00) /* burst write */ 50#define Rx5C348_CMD_MR(addr) (((addr) << 4) | 0x04) /* burst read */ 51 52static struct spi_dev_desc srtc_dev_desc = { 53 .baud = 1000000, /* 1.0Mbps @ Vdd 2.0V */ 54 .tcss = 31, 55 .tcsh = 1, 56 .tcsr = 62, 57 /* 31us for Tcss (62us for Tcsr) is required for carry operation) */ 58 .byteorder = 1, /* MSB-First */ 59 .polarity = 0, /* High-Active */ 60 .phase = 1, /* Shift-Then-Sample */ 61 62}; 63static int srtc_chipid; 64static int srtc_24h; 65 66static inline int 67spi_rtc_io(unsigned char *inbuf, unsigned char *outbuf, unsigned int count) 68{ 69 unsigned char *inbufs[1], *outbufs[1]; 70 unsigned int incounts[2], outcounts[2]; 71 inbufs[0] = inbuf; 72 incounts[0] = count; 73 incounts[1] = 0; 74 outbufs[0] = outbuf; 75 outcounts[0] = count; 76 outcounts[1] = 0; 77 return txx9_spi_io(srtc_chipid, &srtc_dev_desc, 78 inbufs, incounts, outbufs, outcounts, 0); 79} 80 81/* RTC-dependent code for time.c */ 82 83static int 84rtc_rx5c348_set_time(unsigned long t) 85{ 86 unsigned char inbuf[8]; 87 struct rtc_time tm; 88 u8 year, month, day, hour, minute, second, century; 89 90 /* convert */ 91 to_tm(t, &tm); 92 93 year = tm.tm_year % 100; 94 month = tm.tm_mon+1; /* tm_mon starts from 0 to 11 */ 95 day = tm.tm_mday; 96 hour = tm.tm_hour; 97 minute = tm.tm_min; 98 second = tm.tm_sec; 99 century = tm.tm_year / 100; 100 101 inbuf[0] = Rx5C348_CMD_MW(Rx5C348_REG_SECOND); 102 BIN_TO_BCD(second); 103 inbuf[1] = second; 104 BIN_TO_BCD(minute); 105 inbuf[2] = minute; 106 107 if (srtc_24h) { 108 BIN_TO_BCD(hour); 109 inbuf[3] = hour; 110 } else { 111 /* hour 0 is AM12, noon is PM12 */ 112 inbuf[3] = 0; 113 if (hour >= 12) 114 inbuf[3] = Rx5C348_BIT_PM; 115 hour = (hour + 11) % 12 + 1; 116 BIN_TO_BCD(hour); 117 inbuf[3] |= hour; 118 } 119 inbuf[4] = 0; /* ignore week */ 120 BIN_TO_BCD(day); 121 inbuf[5] = day; 122 BIN_TO_BCD(month); 123 inbuf[6] = month; 124 if (century >= 20) 125 inbuf[6] |= Rx5C348_BIT_Y2K; 126 BIN_TO_BCD(year); 127 inbuf[7] = year; 128 /* write in one transfer to avoid data inconsistency */ 129 return spi_rtc_io(inbuf, NULL, 8); 130} 131 132static unsigned long 133rtc_rx5c348_get_time(void) 134{ 135 unsigned char inbuf[8], outbuf[8]; 136 unsigned int year, month, day, hour, minute, second; 137 138 inbuf[0] = Rx5C348_CMD_MR(Rx5C348_REG_SECOND); 139 memset(inbuf + 1, 0, 7); 140 /* read in one transfer to avoid data inconsistency */ 141 if (spi_rtc_io(inbuf, outbuf, 8)) 142 return 0; 143 second = outbuf[1]; 144 BCD_TO_BIN(second); 145 minute = outbuf[2]; 146 BCD_TO_BIN(minute); 147 if (srtc_24h) { 148 hour = outbuf[3]; 149 BCD_TO_BIN(hour); 150 } else { 151 hour = outbuf[3] & ~Rx5C348_BIT_PM; 152 BCD_TO_BIN(hour); 153 hour %= 12; 154 if (outbuf[3] & Rx5C348_BIT_PM) 155 hour += 12; 156 } 157 day = outbuf[5]; 158 BCD_TO_BIN(day); 159 month = outbuf[6] & ~Rx5C348_BIT_Y2K; 160 BCD_TO_BIN(month); 161 year = outbuf[7]; 162 BCD_TO_BIN(year); 163 year += EPOCH; 164 165 return mktime(year, month, day, hour, minute, second); 166} 167 168void __init 169rtc_rx5c348_init(int chipid) 170{ 171 unsigned char inbuf[2], outbuf[2]; 172 srtc_chipid = chipid; 173 /* turn on RTC if it is not on */ 174 inbuf[0] = Rx5C348_CMD_R(Rx5C348_REG_CTL2); 175 inbuf[1] = 0; 176 spi_rtc_io(inbuf, outbuf, 2); 177 if (outbuf[1] & Rx5C348_BIT_XSTP) { 178 inbuf[0] = Rx5C348_CMD_W(Rx5C348_REG_CTL2); 179 inbuf[1] = 0; 180 spi_rtc_io(inbuf, NULL, 2); 181 } 182 183 inbuf[0] = Rx5C348_CMD_R(Rx5C348_REG_CTL1); 184 inbuf[1] = 0; 185 spi_rtc_io(inbuf, outbuf, 2); 186 if (outbuf[1] & Rx5C348_BIT_24H) 187 srtc_24h = 1; 188 189 /* set the function pointers */ 190 rtc_mips_get_time = rtc_rx5c348_get_time; 191 rtc_mips_set_time = rtc_rx5c348_set_time; 192} 193