aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorRoman Fietze <roman.fietze@telemotive.de>2010-08-10 21:02:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:07 -0400
commitd6c7428f9c2b1df1356a21837301647cb4f76e60 (patch)
tree24041cc3dd63a0b9330e5dbabfe8320b0ea084a0 /drivers/rtc
parenteba545465fca35a413e4d62c42ce5e032e48ad60 (diff)
rtc: add Intersil ISL12022 RTC driver
- derived from rtc-pcf8563 - no SRAM driver Signed-off-by: Roman Fietze <roman.fietze@telemotive.de> Cc: Wan ZongShun <mcuos.com@gmail.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig9
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-isl12022.c327
3 files changed, 337 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 6ed5e7e7e79f..999db51e6a58 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -203,6 +203,15 @@ config RTC_DRV_ISL1208
203 This driver can also be built as a module. If so, the module 203 This driver can also be built as a module. If so, the module
204 will be called rtc-isl1208. 204 will be called rtc-isl1208.
205 205
206config RTC_DRV_ISL12022
207 tristate "Intersil ISL12022"
208 help
209 If you say yes here you get support for the
210 Intersil ISL12022 RTC chip.
211
212 This driver can also be built as a module. If so, the module
213 will be called rtc-isl12022.
214
206config RTC_DRV_X1205 215config RTC_DRV_X1205
207 tristate "Xicor/Intersil X1205" 216 tristate "Xicor/Intersil X1205"
208 help 217 help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f58129906e1d..e29b7f9377df 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
48obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o 48obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
49obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o 49obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
50obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o 50obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
51obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
51obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o 52obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
52obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o 53obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
53obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o 54obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
new file mode 100644
index 000000000000..4a8c9dd12a7f
--- /dev/null
+++ b/drivers/rtc/rtc-isl12022.c
@@ -0,0 +1,327 @@
1/*
2 * An I2C driver for the Intersil ISL 12022
3 *
4 * Author: Roman Fietze <roman.fietze@telemotive.de>
5 *
6 * Based on the Philips PCF8563 RTC
7 * by Alessandro Zummo <a.zummo@towertech.it>.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 */
13
14#include <linux/i2c.h>
15#include <linux/bcd.h>
16#include <linux/rtc.h>
17#include <linux/slab.h>
18
19#define DRV_VERSION "0.1"
20
21/* ISL register offsets */
22#define ISL12022_REG_SC 0x00
23#define ISL12022_REG_MN 0x01
24#define ISL12022_REG_HR 0x02
25#define ISL12022_REG_DT 0x03
26#define ISL12022_REG_MO 0x04
27#define ISL12022_REG_YR 0x05
28#define ISL12022_REG_DW 0x06
29
30#define ISL12022_REG_SR 0x07
31#define ISL12022_REG_INT 0x08
32
33/* ISL register bits */
34#define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */
35
36#define ISL12022_SR_LBAT85 (1 << 2)
37#define ISL12022_SR_LBAT75 (1 << 1)
38
39#define ISL12022_INT_WRTC (1 << 6)
40
41
42static struct i2c_driver isl12022_driver;
43
44struct isl12022 {
45 struct rtc_device *rtc;
46
47 bool write_enabled; /* true if write enable is set */
48};
49
50
51static int isl12022_read_regs(struct i2c_client *client, uint8_t reg,
52 uint8_t *data, size_t n)
53{
54 struct i2c_msg msgs[] = {
55 {
56 .addr = client->addr,
57 .flags = 0,
58 .len = 1,
59 .buf = data
60 }, /* setup read ptr */
61 {
62 .addr = client->addr,
63 .flags = I2C_M_RD,
64 .len = n,
65 .buf = data
66 }
67 };
68
69 int ret;
70
71 data[0] = reg;
72 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
73 if (ret != ARRAY_SIZE(msgs)) {
74 dev_err(&client->dev, "%s: read error, ret=%d\n",
75 __func__, ret);
76 return -EIO;
77 }
78
79 return 0;
80}
81
82
83static int isl12022_write_reg(struct i2c_client *client,
84 uint8_t reg, uint8_t val)
85{
86 uint8_t data[2] = { reg, val };
87 int err;
88
89 err = i2c_master_send(client, data, sizeof(data));
90 if (err != sizeof(data)) {
91 dev_err(&client->dev,
92 "%s: err=%d addr=%02x, data=%02x\n",
93 __func__, err, data[0], data[1]);
94 return -EIO;
95 }
96
97 return 0;
98}
99
100
101/*
102 * In the routines that deal directly with the isl12022 hardware, we use
103 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
104 */
105static int isl12022_get_datetime(struct i2c_client *client, struct rtc_time *tm)
106{
107 uint8_t buf[ISL12022_REG_INT + 1];
108 int ret;
109
110 ret = isl12022_read_regs(client, ISL12022_REG_SC, buf, sizeof(buf));
111 if (ret)
112 return ret;
113
114 if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
115 dev_warn(&client->dev,
116 "voltage dropped below %u%%, "
117 "date and time is not reliable.\n",
118 buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
119 }
120
121 dev_dbg(&client->dev,
122 "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
123 "mday=%02x, mon=%02x, year=%02x, wday=%02x, "
124 "sr=%02x, int=%02x",
125 __func__,
126 buf[ISL12022_REG_SC],
127 buf[ISL12022_REG_MN],
128 buf[ISL12022_REG_HR],
129 buf[ISL12022_REG_DT],
130 buf[ISL12022_REG_MO],
131 buf[ISL12022_REG_YR],
132 buf[ISL12022_REG_DW],
133 buf[ISL12022_REG_SR],
134 buf[ISL12022_REG_INT]);
135
136 tm->tm_sec = bcd2bin(buf[ISL12022_REG_SC] & 0x7F);
137 tm->tm_min = bcd2bin(buf[ISL12022_REG_MN] & 0x7F);
138 tm->tm_hour = bcd2bin(buf[ISL12022_REG_HR] & 0x3F);
139 tm->tm_mday = bcd2bin(buf[ISL12022_REG_DT] & 0x3F);
140 tm->tm_wday = buf[ISL12022_REG_DW] & 0x07;
141 tm->tm_mon = bcd2bin(buf[ISL12022_REG_MO] & 0x1F) - 1;
142 tm->tm_year = bcd2bin(buf[ISL12022_REG_YR]) + 100;
143
144 dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
145 "mday=%d, mon=%d, year=%d, wday=%d\n",
146 __func__,
147 tm->tm_sec, tm->tm_min, tm->tm_hour,
148 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
149
150 /* The clock can give out invalid datetime, but we cannot return
151 * -EINVAL otherwise hwclock will refuse to set the time on bootup. */
152 if (rtc_valid_tm(tm) < 0)
153 dev_err(&client->dev, "retrieved date and time is invalid.\n");
154
155 return 0;
156}
157
158static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
159{
160 struct isl12022 *isl12022 = i2c_get_clientdata(client);
161 size_t i;
162 int ret;
163 uint8_t buf[ISL12022_REG_DW + 1];
164
165 dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
166 "mday=%d, mon=%d, year=%d, wday=%d\n",
167 __func__,
168 tm->tm_sec, tm->tm_min, tm->tm_hour,
169 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
170
171 if (!isl12022->write_enabled) {
172
173 ret = isl12022_read_regs(client, ISL12022_REG_INT, buf, 1);
174 if (ret)
175 return ret;
176
177 /* Check if WRTC (write rtc enable) is set factory default is
178 * 0 (not set) */
179 if (!(buf[0] & ISL12022_INT_WRTC)) {
180 dev_info(&client->dev,
181 "init write enable and 24 hour format\n");
182
183 /* Set the write enable bit. */
184 ret = isl12022_write_reg(client,
185 ISL12022_REG_INT,
186 buf[0] | ISL12022_INT_WRTC);
187 if (ret)
188 return ret;
189
190 /* Write to any RTC register to start RTC, we use the
191 * HR register, setting the MIL bit to use the 24 hour
192 * format. */
193 ret = isl12022_read_regs(client, ISL12022_REG_HR,
194 buf, 1);
195 if (ret)
196 return ret;
197
198 ret = isl12022_write_reg(client,
199 ISL12022_REG_HR,
200 buf[0] | ISL12022_HR_MIL);
201 if (ret)
202 return ret;
203 }
204
205 isl12022->write_enabled = 1;
206 }
207
208 /* hours, minutes and seconds */
209 buf[ISL12022_REG_SC] = bin2bcd(tm->tm_sec);
210 buf[ISL12022_REG_MN] = bin2bcd(tm->tm_min);
211 buf[ISL12022_REG_HR] = bin2bcd(tm->tm_hour);
212
213 buf[ISL12022_REG_DT] = bin2bcd(tm->tm_mday);
214
215 /* month, 1 - 12 */
216 buf[ISL12022_REG_MO] = bin2bcd(tm->tm_mon + 1);
217
218 /* year and century */
219 buf[ISL12022_REG_YR] = bin2bcd(tm->tm_year % 100);
220
221 buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
222
223 /* write register's data */
224 for (i = 0; i < ARRAY_SIZE(buf); i++) {
225 ret = isl12022_write_reg(client, ISL12022_REG_SC + i,
226 buf[ISL12022_REG_SC + i]);
227 if (ret)
228 return -EIO;
229 };
230
231 return 0;
232}
233
234static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
235{
236 return isl12022_get_datetime(to_i2c_client(dev), tm);
237}
238
239static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
240{
241 return isl12022_set_datetime(to_i2c_client(dev), tm);
242}
243
244static const struct rtc_class_ops isl12022_rtc_ops = {
245 .read_time = isl12022_rtc_read_time,
246 .set_time = isl12022_rtc_set_time,
247};
248
249static int isl12022_probe(struct i2c_client *client,
250 const struct i2c_device_id *id)
251{
252 struct isl12022 *isl12022;
253
254 int ret = 0;
255
256 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
257 return -ENODEV;
258
259 isl12022 = kzalloc(sizeof(struct isl12022), GFP_KERNEL);
260 if (!isl12022)
261 return -ENOMEM;
262
263 dev_dbg(&client->dev, "chip found, driver version " DRV_VERSION "\n");
264
265 i2c_set_clientdata(client, isl12022);
266
267 isl12022->rtc = rtc_device_register(isl12022_driver.driver.name,
268 &client->dev,
269 &isl12022_rtc_ops,
270 THIS_MODULE);
271
272 if (IS_ERR(isl12022->rtc)) {
273 ret = PTR_ERR(isl12022->rtc);
274 goto exit_kfree;
275 }
276
277 return 0;
278
279exit_kfree:
280 kfree(isl12022);
281
282 return ret;
283}
284
285static int isl12022_remove(struct i2c_client *client)
286{
287 struct isl12022 *isl12022 = i2c_get_clientdata(client);
288
289 rtc_device_unregister(isl12022->rtc);
290 kfree(isl12022);
291
292 return 0;
293}
294
295static const struct i2c_device_id isl12022_id[] = {
296 { "isl12022", 0 },
297 { "rtc8564", 0 },
298 { }
299};
300MODULE_DEVICE_TABLE(i2c, isl12022_id);
301
302static struct i2c_driver isl12022_driver = {
303 .driver = {
304 .name = "rtc-isl12022",
305 },
306 .probe = isl12022_probe,
307 .remove = isl12022_remove,
308 .id_table = isl12022_id,
309};
310
311static int __init isl12022_init(void)
312{
313 return i2c_add_driver(&isl12022_driver);
314}
315
316static void __exit isl12022_exit(void)
317{
318 i2c_del_driver(&isl12022_driver);
319}
320
321module_init(isl12022_init);
322module_exit(isl12022_exit);
323
324MODULE_AUTHOR("roman.fietze@telemotive.de");
325MODULE_DESCRIPTION("ISL 12022 RTC driver");
326MODULE_LICENSE("GPL");
327MODULE_VERSION(DRV_VERSION);