Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[pandora-kernel.git] / drivers / rtc / rtc-m41t93.c
1 /*
2  *
3  * Driver for ST M41T93 SPI RTC
4  *
5  * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/bcd.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/rtc.h>
17 #include <linux/spi/spi.h>
18
19 #define M41T93_REG_SSEC                 0
20 #define M41T93_REG_ST_SEC               1
21 #define M41T93_REG_MIN                  2
22 #define M41T93_REG_CENT_HOUR            3
23 #define M41T93_REG_WDAY                 4
24 #define M41T93_REG_DAY                  5
25 #define M41T93_REG_MON                  6
26 #define M41T93_REG_YEAR                 7
27
28
29 #define M41T93_REG_ALM_HOUR_HT          0xc
30 #define M41T93_REG_FLAGS                0xf
31
32 #define M41T93_FLAG_ST                  (1 << 7)
33 #define M41T93_FLAG_OF                  (1 << 2)
34 #define M41T93_FLAG_BL                  (1 << 4)
35 #define M41T93_FLAG_HT                  (1 << 6)
36
37 static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
38 {
39         u8 buf[2];
40
41         /* MSB must be '1' to write */
42         buf[0] = addr | 0x80;
43         buf[1] = data;
44
45         return spi_write(spi, buf, sizeof(buf));
46 }
47
48 static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
49 {
50         struct spi_device *spi = to_spi_device(dev);
51         u8 buf[9] = {0x80};        /* write cmd + 8 data bytes */
52         u8 * const data = &buf[1]; /* ptr to first data byte */
53
54         dev_dbg(dev, "%s secs=%d, mins=%d, "
55                 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
56                 "write", tm->tm_sec, tm->tm_min,
57                 tm->tm_hour, tm->tm_mday,
58                 tm->tm_mon, tm->tm_year, tm->tm_wday);
59
60         if (tm->tm_year < 100) {
61                 dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
62                 return -EINVAL;
63         }
64
65         data[M41T93_REG_SSEC]           = 0;
66         data[M41T93_REG_ST_SEC]         = bin2bcd(tm->tm_sec);
67         data[M41T93_REG_MIN]            = bin2bcd(tm->tm_min);
68         data[M41T93_REG_CENT_HOUR]      = bin2bcd(tm->tm_hour) |
69                                                 ((tm->tm_year/100-1) << 6);
70         data[M41T93_REG_DAY]            = bin2bcd(tm->tm_mday);
71         data[M41T93_REG_WDAY]           = bin2bcd(tm->tm_wday + 1);
72         data[M41T93_REG_MON]            = bin2bcd(tm->tm_mon + 1);
73         data[M41T93_REG_YEAR]           = bin2bcd(tm->tm_year % 100);
74
75         return spi_write(spi, buf, sizeof(buf));
76 }
77
78
79 static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
80 {
81         struct spi_device *spi = to_spi_device(dev);
82         const u8 start_addr = 0;
83         u8 buf[8];
84         int century_after_1900;
85         int tmp;
86         int ret = 0;
87
88         /* Check status of clock. Two states must be considered:
89            1. halt bit (HT) is set: the clock is running but update of readout
90               registers has been disabled due to power failure. This is normal
91               case after poweron. Time is valid after resetting HT bit.
92            2. oscillator fail bit (OF) is set. Oscillator has be stopped and
93               time is invalid:
94               a) OF can be immeditely reset.
95               b) OF cannot be immediately reset: oscillator has to be restarted.
96         */
97         tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
98         if (tmp < 0)
99                 return tmp;
100
101         if (tmp & M41T93_FLAG_HT) {
102                 dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
103                 m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
104                                tmp & ~M41T93_FLAG_HT);
105         }
106
107         tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
108         if (tmp < 0)
109                 return tmp;
110
111         if (tmp & M41T93_FLAG_OF) {
112                 ret = -EINVAL;
113                 dev_warn(&spi->dev, "OF bit is set, resetting.\n");
114                 m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
115
116                 tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
117                 if (tmp < 0)
118                         return tmp;
119                 else if (tmp & M41T93_FLAG_OF) {
120                         u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
121
122                         dev_warn(&spi->dev,
123                                  "OF bit is still set, kickstarting clock.\n");
124                         m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
125                         reset_osc &= ~M41T93_FLAG_ST;
126                         m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
127                 }
128         }
129
130         if (tmp & M41T93_FLAG_BL)
131                 dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
132
133         /* read actual time/date */
134         tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
135         if (tmp < 0)
136                 return tmp;
137
138         tm->tm_sec      = bcd2bin(buf[M41T93_REG_ST_SEC]);
139         tm->tm_min      = bcd2bin(buf[M41T93_REG_MIN]);
140         tm->tm_hour     = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f);
141         tm->tm_mday     = bcd2bin(buf[M41T93_REG_DAY]);
142         tm->tm_mon      = bcd2bin(buf[M41T93_REG_MON]) - 1;
143         tm->tm_wday     = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1;
144
145         century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1;
146         tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100;
147
148         dev_dbg(dev, "%s secs=%d, mins=%d, "
149                 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
150                 "read", tm->tm_sec, tm->tm_min,
151                 tm->tm_hour, tm->tm_mday,
152                 tm->tm_mon, tm->tm_year, tm->tm_wday);
153
154         return ret < 0 ? ret : rtc_valid_tm(tm);
155 }
156
157
158 static const struct rtc_class_ops m41t93_rtc_ops = {
159         .read_time      = m41t93_get_time,
160         .set_time       = m41t93_set_time,
161 };
162
163 static struct spi_driver m41t93_driver;
164
165 static int __devinit m41t93_probe(struct spi_device *spi)
166 {
167         struct rtc_device *rtc;
168         int res;
169
170         spi->bits_per_word = 8;
171         spi_setup(spi);
172
173         res = spi_w8r8(spi, M41T93_REG_WDAY);
174         if (res < 0 || (res & 0xf8) != 0) {
175                 dev_err(&spi->dev, "not found 0x%x.\n", res);
176                 return -ENODEV;
177         }
178
179         rtc = rtc_device_register(m41t93_driver.driver.name,
180                 &spi->dev, &m41t93_rtc_ops, THIS_MODULE);
181         if (IS_ERR(rtc))
182                 return PTR_ERR(rtc);
183
184         dev_set_drvdata(&spi->dev, rtc);
185
186         return 0;
187 }
188
189
190 static int __devexit m41t93_remove(struct spi_device *spi)
191 {
192         struct rtc_device *rtc = spi_get_drvdata(spi);
193
194         if (rtc)
195                 rtc_device_unregister(rtc);
196
197         return 0;
198 }
199
200 static struct spi_driver m41t93_driver = {
201         .driver = {
202                 .name   = "rtc-m41t93",
203                 .bus    = &spi_bus_type,
204                 .owner  = THIS_MODULE,
205         },
206         .probe  = m41t93_probe,
207         .remove = __devexit_p(m41t93_remove),
208 };
209
210 static __init int m41t93_init(void)
211 {
212         return spi_register_driver(&m41t93_driver);
213 }
214 module_init(m41t93_init);
215
216 static __exit void m41t93_exit(void)
217 {
218         spi_unregister_driver(&m41t93_driver);
219 }
220 module_exit(m41t93_exit);
221
222 MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
223 MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
224 MODULE_LICENSE("GPL");
225 MODULE_ALIAS("spi:rtc-m41t93");