blob: 04e93c6597f8905b5cfeae366fc0e874f697973a [file] [log] [blame]
Sergey Lapinc6d8f402008-06-12 15:21:55 -07001/*
2 * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip.
3 *
4 * Copyright (C) 2008 Sergey Lapin
5 * Based on ds1307 driver by James Chapman and David Brownell
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/module.h>
13#include <linux/i2c.h>
14#include <linux/rtc.h>
15#include <linux/bcd.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Sergey Lapinc6d8f402008-06-12 15:21:55 -070017
18#define FM3130_RTC_CONTROL (0x0)
19#define FM3130_CAL_CONTROL (0x1)
20#define FM3130_RTC_SECONDS (0x2)
21#define FM3130_RTC_MINUTES (0x3)
22#define FM3130_RTC_HOURS (0x4)
23#define FM3130_RTC_DAY (0x5)
24#define FM3130_RTC_DATE (0x6)
25#define FM3130_RTC_MONTHS (0x7)
26#define FM3130_RTC_YEARS (0x8)
27
28#define FM3130_ALARM_SECONDS (0x9)
29#define FM3130_ALARM_MINUTES (0xa)
30#define FM3130_ALARM_HOURS (0xb)
31#define FM3130_ALARM_DATE (0xc)
32#define FM3130_ALARM_MONTHS (0xd)
33#define FM3130_ALARM_WP_CONTROL (0xe)
34
35#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */
36#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */
37#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */
38#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */
39#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */
40#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */
41#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */
42#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */
43#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */
44
45#define FM3130_CLOCK_REGS 7
46#define FM3130_ALARM_REGS 5
47
48struct fm3130 {
49 u8 reg_addr_time;
50 u8 reg_addr_alarm;
51 u8 regs[15];
52 struct i2c_msg msg[4];
53 struct i2c_client *client;
54 struct rtc_device *rtc;
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -070055 int alarm_valid;
Sergey Lapinc6d8f402008-06-12 15:21:55 -070056 int data_valid;
Sergey Lapinc6d8f402008-06-12 15:21:55 -070057};
58static const struct i2c_device_id fm3130_id[] = {
Alessandro Zummo876550a2008-07-12 13:47:55 -070059 { "fm3130", 0 },
Sergey Lapinc6d8f402008-06-12 15:21:55 -070060 { }
61};
62MODULE_DEVICE_TABLE(i2c, fm3130_id);
63
64#define FM3130_MODE_NORMAL 0
65#define FM3130_MODE_WRITE 1
66#define FM3130_MODE_READ 2
67
68static void fm3130_rtc_mode(struct device *dev, int mode)
69{
70 struct fm3130 *fm3130 = dev_get_drvdata(dev);
71
72 fm3130->regs[FM3130_RTC_CONTROL] =
73 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
74 switch (mode) {
75 case FM3130_MODE_NORMAL:
76 fm3130->regs[FM3130_RTC_CONTROL] &=
77 ~(FM3130_RTC_CONTROL_BIT_WRITE |
78 FM3130_RTC_CONTROL_BIT_READ);
79 break;
80 case FM3130_MODE_WRITE:
81 fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE;
82 break;
83 case FM3130_MODE_READ:
84 fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_READ;
85 break;
86 default:
87 dev_dbg(dev, "invalid mode %d\n", mode);
88 break;
89 }
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -070090
Sergey Lapinc6d8f402008-06-12 15:21:55 -070091 i2c_smbus_write_byte_data(fm3130->client,
92 FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]);
93}
94
95static int fm3130_get_time(struct device *dev, struct rtc_time *t)
96{
97 struct fm3130 *fm3130 = dev_get_drvdata(dev);
98 int tmp;
99
100 if (!fm3130->data_valid) {
101 /* We have invalid data in RTC, probably due
102 to battery faults or other problems. Return EIO
Uwe Kleine-Königfd0961f2010-06-11 12:16:56 +0200103 for now, it will allow us to set data later instead
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700104 of error during probing which disables device */
105 return -EIO;
106 }
107 fm3130_rtc_mode(dev, FM3130_MODE_READ);
108
109 /* read the RTC date and time registers all at once */
110 tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
111 fm3130->msg, 2);
112 if (tmp != 2) {
113 dev_err(dev, "%s error %d\n", "read", tmp);
114 return -EIO;
115 }
116
117 fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
118
119 dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
120 "%02x %02x %02x %02x %02x %02x %02x\n",
121 "read",
122 fm3130->regs[0], fm3130->regs[1],
123 fm3130->regs[2], fm3130->regs[3],
124 fm3130->regs[4], fm3130->regs[5],
125 fm3130->regs[6], fm3130->regs[7],
126 fm3130->regs[8], fm3130->regs[9],
127 fm3130->regs[0xa], fm3130->regs[0xb],
128 fm3130->regs[0xc], fm3130->regs[0xd],
129 fm3130->regs[0xe]);
130
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700131 t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
132 t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700133 tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f;
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700134 t->tm_hour = bcd2bin(tmp);
135 t->tm_wday = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
136 t->tm_mday = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700137 tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f;
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700138 t->tm_mon = bcd2bin(tmp) - 1;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700139
140 /* assume 20YY not 19YY, and ignore CF bit */
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700141 t->tm_year = bcd2bin(fm3130->regs[FM3130_RTC_YEARS]) + 100;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700142
143 dev_dbg(dev, "%s secs=%d, mins=%d, "
144 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
145 "read", t->tm_sec, t->tm_min,
146 t->tm_hour, t->tm_mday,
147 t->tm_mon, t->tm_year, t->tm_wday);
148
149 /* initial clock setting can be undefined */
150 return rtc_valid_tm(t);
151}
152
153
154static int fm3130_set_time(struct device *dev, struct rtc_time *t)
155{
156 struct fm3130 *fm3130 = dev_get_drvdata(dev);
157 int tmp, i;
158 u8 *buf = fm3130->regs;
159
160 dev_dbg(dev, "%s secs=%d, mins=%d, "
161 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
162 "write", t->tm_sec, t->tm_min,
163 t->tm_hour, t->tm_mday,
164 t->tm_mon, t->tm_year, t->tm_wday);
165
166 /* first register addr */
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700167 buf[FM3130_RTC_SECONDS] = bin2bcd(t->tm_sec);
168 buf[FM3130_RTC_MINUTES] = bin2bcd(t->tm_min);
169 buf[FM3130_RTC_HOURS] = bin2bcd(t->tm_hour);
170 buf[FM3130_RTC_DAY] = bin2bcd(t->tm_wday + 1);
171 buf[FM3130_RTC_DATE] = bin2bcd(t->tm_mday);
172 buf[FM3130_RTC_MONTHS] = bin2bcd(t->tm_mon + 1);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700173
174 /* assume 20YY not 19YY */
175 tmp = t->tm_year - 100;
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700176 buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700177
178 dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
179 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
180 "write", buf[0], buf[1], buf[2], buf[3],
181 buf[4], buf[5], buf[6], buf[7],
182 buf[8], buf[9], buf[0xa], buf[0xb],
183 buf[0xc], buf[0xd], buf[0xe]);
184
185 fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
186
187 /* Writing time registers, we don't support multibyte transfers */
188 for (i = 0; i < FM3130_CLOCK_REGS; i++) {
189 i2c_smbus_write_byte_data(fm3130->client,
190 FM3130_RTC_SECONDS + i,
191 fm3130->regs[FM3130_RTC_SECONDS + i]);
192 }
193
194 fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
195
196 /* We assume here that data are valid once written */
197 if (!fm3130->data_valid)
198 fm3130->data_valid = 1;
199 return 0;
200}
201
202static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
203{
204 struct fm3130 *fm3130 = dev_get_drvdata(dev);
205 int tmp;
206 struct rtc_time *tm = &alrm->time;
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700207
208 if (!fm3130->alarm_valid) {
209 /*
210 * We have invalid alarm in RTC, probably due to battery faults
211 * or other problems. Return EIO for now, it will allow us to
212 * set alarm value later instead of error during probing which
213 * disables device
214 */
215 return -EIO;
216 }
217
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700218 /* read the RTC alarm registers all at once */
219 tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
220 &fm3130->msg[2], 2);
221 if (tmp != 2) {
222 dev_err(dev, "%s error %d\n", "read", tmp);
223 return -EIO;
224 }
225 dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n",
226 fm3130->regs[FM3130_ALARM_SECONDS],
227 fm3130->regs[FM3130_ALARM_MINUTES],
228 fm3130->regs[FM3130_ALARM_HOURS],
229 fm3130->regs[FM3130_ALARM_DATE],
230 fm3130->regs[FM3130_ALARM_MONTHS]);
231
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700232 tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
233 tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
234 tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
235 tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
236 tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700237
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700238 if (tm->tm_mon > 0)
239 tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700240
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700241 dev_dbg(dev, "%s secs=%d, mins=%d, "
242 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
243 "read alarm", tm->tm_sec, tm->tm_min,
244 tm->tm_hour, tm->tm_mday,
245 tm->tm_mon, tm->tm_year, tm->tm_wday);
246
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700247 /* check if alarm enabled */
248 fm3130->regs[FM3130_RTC_CONTROL] =
249 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
250
251 if ((fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AEN) &&
252 (~fm3130->regs[FM3130_RTC_CONTROL] &
253 FM3130_RTC_CONTROL_BIT_CAL)) {
254 alrm->enabled = 1;
255 }
256
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700257 return 0;
258}
259
260static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
261{
262 struct fm3130 *fm3130 = dev_get_drvdata(dev);
263 struct rtc_time *tm = &alrm->time;
264 int i;
265
266 dev_dbg(dev, "%s secs=%d, mins=%d, "
267 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
268 "write alarm", tm->tm_sec, tm->tm_min,
269 tm->tm_hour, tm->tm_mday,
270 tm->tm_mon, tm->tm_year, tm->tm_wday);
271
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700272 fm3130->regs[FM3130_ALARM_SECONDS] =
273 (tm->tm_sec != -1) ? bin2bcd(tm->tm_sec) : 0x80;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700274
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700275 fm3130->regs[FM3130_ALARM_MINUTES] =
276 (tm->tm_min != -1) ? bin2bcd(tm->tm_min) : 0x80;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700277
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700278 fm3130->regs[FM3130_ALARM_HOURS] =
279 (tm->tm_hour != -1) ? bin2bcd(tm->tm_hour) : 0x80;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700280
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700281 fm3130->regs[FM3130_ALARM_DATE] =
282 (tm->tm_mday != -1) ? bin2bcd(tm->tm_mday) : 0x80;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700283
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700284 fm3130->regs[FM3130_ALARM_MONTHS] =
285 (tm->tm_mon != -1) ? bin2bcd(tm->tm_mon + 1) : 0x80;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700286
287 dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
288 fm3130->regs[FM3130_ALARM_SECONDS],
289 fm3130->regs[FM3130_ALARM_MINUTES],
290 fm3130->regs[FM3130_ALARM_HOURS],
291 fm3130->regs[FM3130_ALARM_DATE],
292 fm3130->regs[FM3130_ALARM_MONTHS]);
293 /* Writing time registers, we don't support multibyte transfers */
294 for (i = 0; i < FM3130_ALARM_REGS; i++) {
295 i2c_smbus_write_byte_data(fm3130->client,
296 FM3130_ALARM_SECONDS + i,
297 fm3130->regs[FM3130_ALARM_SECONDS + i]);
298 }
299 fm3130->regs[FM3130_RTC_CONTROL] =
300 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700301
302 /* enable or disable alarm */
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700303 if (alrm->enabled) {
304 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
305 (fm3130->regs[FM3130_RTC_CONTROL] &
306 ~(FM3130_RTC_CONTROL_BIT_CAL)) |
307 FM3130_RTC_CONTROL_BIT_AEN);
308 } else {
309 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
310 fm3130->regs[FM3130_RTC_CONTROL] &
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700311 ~(FM3130_RTC_CONTROL_BIT_CAL) &
312 ~(FM3130_RTC_CONTROL_BIT_AEN));
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700313 }
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700314
315 /* We assume here that data is valid once written */
316 if (!fm3130->alarm_valid)
317 fm3130->alarm_valid = 1;
318
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700319 return 0;
320}
321
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700322static int fm3130_alarm_irq_enable(struct device *dev, unsigned int enabled)
323{
324 struct fm3130 *fm3130 = dev_get_drvdata(dev);
325 int ret = 0;
326
327 fm3130->regs[FM3130_RTC_CONTROL] =
328 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
329
330 dev_dbg(dev, "alarm_irq_enable: enable=%d, FM3130_RTC_CONTROL=%02x\n",
331 enabled, fm3130->regs[FM3130_RTC_CONTROL]);
332
333 switch (enabled) {
334 case 0: /* alarm off */
335 ret = i2c_smbus_write_byte_data(fm3130->client,
336 FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] &
337 ~(FM3130_RTC_CONTROL_BIT_CAL) &
338 ~(FM3130_RTC_CONTROL_BIT_AEN));
339 break;
340 case 1: /* alarm on */
341 ret = i2c_smbus_write_byte_data(fm3130->client,
342 FM3130_RTC_CONTROL, (fm3130->regs[FM3130_RTC_CONTROL] &
343 ~(FM3130_RTC_CONTROL_BIT_CAL)) |
344 FM3130_RTC_CONTROL_BIT_AEN);
345 break;
346 default:
347 ret = -EINVAL;
348 break;
349 }
350
351 return ret;
352}
353
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700354static const struct rtc_class_ops fm3130_rtc_ops = {
355 .read_time = fm3130_get_time,
356 .set_time = fm3130_set_time,
357 .read_alarm = fm3130_read_alarm,
358 .set_alarm = fm3130_set_alarm,
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700359 .alarm_irq_enable = fm3130_alarm_irq_enable,
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700360};
361
362static struct i2c_driver fm3130_driver;
363
Greg Kroah-Hartman5a167f42012-12-21 13:09:38 -0800364static int fm3130_probe(struct i2c_client *client,
365 const struct i2c_device_id *id)
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700366{
367 struct fm3130 *fm3130;
368 int err = -ENODEV;
369 int tmp;
370 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
371
372 if (!i2c_check_functionality(adapter,
373 I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
374 return -EIO;
375
376 fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL);
377
378 if (!fm3130)
379 return -ENOMEM;
380
381 fm3130->client = client;
382 i2c_set_clientdata(client, fm3130);
383 fm3130->reg_addr_time = FM3130_RTC_SECONDS;
384 fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS;
385
386 /* Messages to read time */
387 fm3130->msg[0].addr = client->addr;
388 fm3130->msg[0].flags = 0;
389 fm3130->msg[0].len = 1;
390 fm3130->msg[0].buf = &fm3130->reg_addr_time;
391
392 fm3130->msg[1].addr = client->addr;
393 fm3130->msg[1].flags = I2C_M_RD;
394 fm3130->msg[1].len = FM3130_CLOCK_REGS;
395 fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS];
396
397 /* Messages to read alarm */
398 fm3130->msg[2].addr = client->addr;
399 fm3130->msg[2].flags = 0;
400 fm3130->msg[2].len = 1;
401 fm3130->msg[2].buf = &fm3130->reg_addr_alarm;
402
403 fm3130->msg[3].addr = client->addr;
404 fm3130->msg[3].flags = I2C_M_RD;
405 fm3130->msg[3].len = FM3130_ALARM_REGS;
406 fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS];
407
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700408 fm3130->alarm_valid = 0;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700409 fm3130->data_valid = 0;
410
411 tmp = i2c_transfer(adapter, fm3130->msg, 4);
412 if (tmp != 4) {
413 pr_debug("read error %d\n", tmp);
414 err = -EIO;
415 goto exit_free;
416 }
417
418 fm3130->regs[FM3130_RTC_CONTROL] =
419 i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL);
420 fm3130->regs[FM3130_CAL_CONTROL] =
421 i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL);
422
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700423 /* Disabling calibration mode */
Sergey Matyukevichf4b51622010-02-02 13:43:59 -0800424 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) {
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700425 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
426 fm3130->regs[FM3130_RTC_CONTROL] &
427 ~(FM3130_RTC_CONTROL_BIT_CAL));
428 dev_warn(&client->dev, "Disabling calibration mode!\n");
Sergey Matyukevichf4b51622010-02-02 13:43:59 -0800429 }
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700430
431 /* Disabling read and write modes */
432 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
Sergey Matyukevichf4b51622010-02-02 13:43:59 -0800433 fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) {
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700434 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
435 fm3130->regs[FM3130_RTC_CONTROL] &
436 ~(FM3130_RTC_CONTROL_BIT_READ |
437 FM3130_RTC_CONTROL_BIT_WRITE));
438 dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
Sergey Matyukevichf4b51622010-02-02 13:43:59 -0800439 }
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700440
441 /* oscillator off? turn it on, so clock can tick. */
442 if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
443 i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL,
444 fm3130->regs[FM3130_CAL_CONTROL] &
445 ~(FM3130_CAL_CONTROL_BIT_nOSCEN));
446
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700447 /* low battery? clear flag, and warn */
448 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) {
449 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
450 fm3130->regs[FM3130_RTC_CONTROL] &
451 ~(FM3130_RTC_CONTROL_BIT_LB));
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700452 dev_warn(&client->dev, "Low battery!\n");
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700453 }
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700454
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700455 /* check if Power On Reset bit is set */
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700456 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) {
457 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
458 fm3130->regs[FM3130_RTC_CONTROL] &
459 ~FM3130_RTC_CONTROL_BIT_POR);
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700460 dev_dbg(&client->dev, "POR bit is set\n");
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700461 }
462 /* ACS is controlled by alarm */
463 i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80);
464
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700465 /* alarm registers sanity check */
466 tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
467 if (tmp > 59)
468 goto bad_alarm;
469
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700470 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700471 if (tmp > 59)
472 goto bad_alarm;
473
474 tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f);
475 if (tmp > 23)
476 goto bad_alarm;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700477
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700478 tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700479 if (tmp == 0 || tmp > 31)
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700480 goto bad_alarm;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700481
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700482 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700483 if (tmp == 0 || tmp > 12)
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700484 goto bad_alarm;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700485
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700486 fm3130->alarm_valid = 1;
487
488bad_alarm:
489
490 /* clock registers sanity chek */
491 tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
492 if (tmp > 59)
493 goto bad_clock;
494
495 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
496 if (tmp > 59)
497 goto bad_clock;
498
499 tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f);
500 if (tmp > 23)
501 goto bad_clock;
502
503 tmp = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x7);
504 if (tmp == 0 || tmp > 7)
505 goto bad_clock;
506
507 tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
508 if (tmp == 0 || tmp > 31)
509 goto bad_clock;
510
511 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
512 if (tmp == 0 || tmp > 12)
513 goto bad_clock;
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700514
515 fm3130->data_valid = 1;
516
Sergey Matyukevichf3f99cf2010-08-10 18:02:10 -0700517bad_clock:
518
519 if (!fm3130->data_valid || !fm3130->alarm_valid)
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700520 dev_dbg(&client->dev,
521 "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
522 "%02x %02x %02x %02x %02x %02x %02x\n",
523 "bogus registers",
524 fm3130->regs[0], fm3130->regs[1],
525 fm3130->regs[2], fm3130->regs[3],
526 fm3130->regs[4], fm3130->regs[5],
527 fm3130->regs[6], fm3130->regs[7],
528 fm3130->regs[8], fm3130->regs[9],
529 fm3130->regs[0xa], fm3130->regs[0xb],
530 fm3130->regs[0xc], fm3130->regs[0xd],
531 fm3130->regs[0xe]);
532
533 /* We won't bail out here because we just got invalid data.
534 Time setting from u-boot doesn't work anyway */
535 fm3130->rtc = rtc_device_register(client->name, &client->dev,
536 &fm3130_rtc_ops, THIS_MODULE);
537 if (IS_ERR(fm3130->rtc)) {
538 err = PTR_ERR(fm3130->rtc);
539 dev_err(&client->dev,
540 "unable to register the class device\n");
541 goto exit_free;
542 }
543 return 0;
544exit_free:
545 kfree(fm3130);
546 return err;
547}
548
Greg Kroah-Hartman5a167f42012-12-21 13:09:38 -0800549static int fm3130_remove(struct i2c_client *client)
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700550{
551 struct fm3130 *fm3130 = i2c_get_clientdata(client);
552
553 rtc_device_unregister(fm3130->rtc);
554 kfree(fm3130);
555 return 0;
556}
557
558static struct i2c_driver fm3130_driver = {
559 .driver = {
560 .name = "rtc-fm3130",
561 .owner = THIS_MODULE,
562 },
563 .probe = fm3130_probe,
Greg Kroah-Hartman5a167f42012-12-21 13:09:38 -0800564 .remove = fm3130_remove,
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700565 .id_table = fm3130_id,
566};
567
Axel Lin0abc9202012-03-23 15:02:31 -0700568module_i2c_driver(fm3130_driver);
Sergey Lapinc6d8f402008-06-12 15:21:55 -0700569
570MODULE_DESCRIPTION("RTC driver for FM3130");
571MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
572MODULE_LICENSE("GPL");
573