Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/cpufreq-2.6
[sfrench/cifs-2.6.git] / arch / mips / tx4938 / common / rtc_rx5c348.c
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 <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
51 static 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 };
62 static int srtc_chipid;
63 static int srtc_24h;
64
65 static inline int
66 spi_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
93 static int
94 rtc_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
142 static unsigned long
143 rtc_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
178 void __init
179 rtc_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 */
200         rtc_mips_get_time = rtc_rx5c348_get_time;
201         rtc_mips_set_time = rtc_rx5c348_set_time;
202 }