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