Commit | Line | Data |
---|---|---|
c6d8f400 SL |
1 | /* |
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> | |
5a0e3ad6 | 16 | #include <linux/slab.h> |
c6d8f400 SL |
17 | |
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 | ||
48 | struct 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; | |
55 | int data_valid; | |
56 | int alarm; | |
57 | }; | |
58 | static const struct i2c_device_id fm3130_id[] = { | |
876550aa | 59 | { "fm3130", 0 }, |
c6d8f400 SL |
60 | { } |
61 | }; | |
62 | MODULE_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 | ||
68 | static 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 | } | |
90 | /* Checking for alarm */ | |
91 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { | |
92 | fm3130->alarm = 1; | |
93 | fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; | |
94 | } | |
95 | i2c_smbus_write_byte_data(fm3130->client, | |
96 | FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); | |
97 | } | |
98 | ||
99 | static int fm3130_get_time(struct device *dev, struct rtc_time *t) | |
100 | { | |
101 | struct fm3130 *fm3130 = dev_get_drvdata(dev); | |
102 | int tmp; | |
103 | ||
104 | if (!fm3130->data_valid) { | |
105 | /* We have invalid data in RTC, probably due | |
106 | to battery faults or other problems. Return EIO | |
107 | for now, it will allow us to set data later insted | |
108 | of error during probing which disables device */ | |
109 | return -EIO; | |
110 | } | |
111 | fm3130_rtc_mode(dev, FM3130_MODE_READ); | |
112 | ||
113 | /* read the RTC date and time registers all at once */ | |
114 | tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), | |
115 | fm3130->msg, 2); | |
116 | if (tmp != 2) { | |
117 | dev_err(dev, "%s error %d\n", "read", tmp); | |
118 | return -EIO; | |
119 | } | |
120 | ||
121 | fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); | |
122 | ||
123 | dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x" | |
124 | "%02x %02x %02x %02x %02x %02x %02x\n", | |
125 | "read", | |
126 | fm3130->regs[0], fm3130->regs[1], | |
127 | fm3130->regs[2], fm3130->regs[3], | |
128 | fm3130->regs[4], fm3130->regs[5], | |
129 | fm3130->regs[6], fm3130->regs[7], | |
130 | fm3130->regs[8], fm3130->regs[9], | |
131 | fm3130->regs[0xa], fm3130->regs[0xb], | |
132 | fm3130->regs[0xc], fm3130->regs[0xd], | |
133 | fm3130->regs[0xe]); | |
134 | ||
fe20ba70 AB |
135 | t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); |
136 | t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); | |
c6d8f400 | 137 | tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f; |
fe20ba70 AB |
138 | t->tm_hour = bcd2bin(tmp); |
139 | t->tm_wday = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1; | |
140 | t->tm_mday = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); | |
c6d8f400 | 141 | tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f; |
fe20ba70 | 142 | t->tm_mon = bcd2bin(tmp) - 1; |
c6d8f400 SL |
143 | |
144 | /* assume 20YY not 19YY, and ignore CF bit */ | |
fe20ba70 | 145 | t->tm_year = bcd2bin(fm3130->regs[FM3130_RTC_YEARS]) + 100; |
c6d8f400 SL |
146 | |
147 | dev_dbg(dev, "%s secs=%d, mins=%d, " | |
148 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | |
149 | "read", t->tm_sec, t->tm_min, | |
150 | t->tm_hour, t->tm_mday, | |
151 | t->tm_mon, t->tm_year, t->tm_wday); | |
152 | ||
153 | /* initial clock setting can be undefined */ | |
154 | return rtc_valid_tm(t); | |
155 | } | |
156 | ||
157 | ||
158 | static int fm3130_set_time(struct device *dev, struct rtc_time *t) | |
159 | { | |
160 | struct fm3130 *fm3130 = dev_get_drvdata(dev); | |
161 | int tmp, i; | |
162 | u8 *buf = fm3130->regs; | |
163 | ||
164 | dev_dbg(dev, "%s secs=%d, mins=%d, " | |
165 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | |
166 | "write", t->tm_sec, t->tm_min, | |
167 | t->tm_hour, t->tm_mday, | |
168 | t->tm_mon, t->tm_year, t->tm_wday); | |
169 | ||
170 | /* first register addr */ | |
fe20ba70 AB |
171 | buf[FM3130_RTC_SECONDS] = bin2bcd(t->tm_sec); |
172 | buf[FM3130_RTC_MINUTES] = bin2bcd(t->tm_min); | |
173 | buf[FM3130_RTC_HOURS] = bin2bcd(t->tm_hour); | |
174 | buf[FM3130_RTC_DAY] = bin2bcd(t->tm_wday + 1); | |
175 | buf[FM3130_RTC_DATE] = bin2bcd(t->tm_mday); | |
176 | buf[FM3130_RTC_MONTHS] = bin2bcd(t->tm_mon + 1); | |
c6d8f400 SL |
177 | |
178 | /* assume 20YY not 19YY */ | |
179 | tmp = t->tm_year - 100; | |
fe20ba70 | 180 | buf[FM3130_RTC_YEARS] = bin2bcd(tmp); |
c6d8f400 SL |
181 | |
182 | dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x" | |
183 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | |
184 | "write", buf[0], buf[1], buf[2], buf[3], | |
185 | buf[4], buf[5], buf[6], buf[7], | |
186 | buf[8], buf[9], buf[0xa], buf[0xb], | |
187 | buf[0xc], buf[0xd], buf[0xe]); | |
188 | ||
189 | fm3130_rtc_mode(dev, FM3130_MODE_WRITE); | |
190 | ||
191 | /* Writing time registers, we don't support multibyte transfers */ | |
192 | for (i = 0; i < FM3130_CLOCK_REGS; i++) { | |
193 | i2c_smbus_write_byte_data(fm3130->client, | |
194 | FM3130_RTC_SECONDS + i, | |
195 | fm3130->regs[FM3130_RTC_SECONDS + i]); | |
196 | } | |
197 | ||
198 | fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); | |
199 | ||
200 | /* We assume here that data are valid once written */ | |
201 | if (!fm3130->data_valid) | |
202 | fm3130->data_valid = 1; | |
203 | return 0; | |
204 | } | |
205 | ||
206 | static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
207 | { | |
208 | struct fm3130 *fm3130 = dev_get_drvdata(dev); | |
209 | int tmp; | |
210 | struct rtc_time *tm = &alrm->time; | |
211 | /* read the RTC alarm registers all at once */ | |
212 | tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), | |
213 | &fm3130->msg[2], 2); | |
214 | if (tmp != 2) { | |
215 | dev_err(dev, "%s error %d\n", "read", tmp); | |
216 | return -EIO; | |
217 | } | |
218 | dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n", | |
219 | fm3130->regs[FM3130_ALARM_SECONDS], | |
220 | fm3130->regs[FM3130_ALARM_MINUTES], | |
221 | fm3130->regs[FM3130_ALARM_HOURS], | |
222 | fm3130->regs[FM3130_ALARM_DATE], | |
223 | fm3130->regs[FM3130_ALARM_MONTHS]); | |
224 | ||
225 | ||
fe20ba70 AB |
226 | tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); |
227 | tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); | |
228 | tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); | |
229 | tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); | |
230 | tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); | |
c6d8f400 SL |
231 | if (tm->tm_mon > 0) |
232 | tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ | |
233 | dev_dbg(dev, "%s secs=%d, mins=%d, " | |
234 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | |
235 | "read alarm", tm->tm_sec, tm->tm_min, | |
236 | tm->tm_hour, tm->tm_mday, | |
237 | tm->tm_mon, tm->tm_year, tm->tm_wday); | |
238 | ||
239 | return 0; | |
240 | } | |
241 | ||
242 | static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |
243 | { | |
244 | struct fm3130 *fm3130 = dev_get_drvdata(dev); | |
245 | struct rtc_time *tm = &alrm->time; | |
246 | int i; | |
247 | ||
248 | dev_dbg(dev, "%s secs=%d, mins=%d, " | |
249 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | |
250 | "write alarm", tm->tm_sec, tm->tm_min, | |
251 | tm->tm_hour, tm->tm_mday, | |
252 | tm->tm_mon, tm->tm_year, tm->tm_wday); | |
253 | ||
254 | if (tm->tm_sec != -1) | |
255 | fm3130->regs[FM3130_ALARM_SECONDS] = | |
fe20ba70 | 256 | bin2bcd(tm->tm_sec) | 0x80; |
c6d8f400 SL |
257 | |
258 | if (tm->tm_min != -1) | |
259 | fm3130->regs[FM3130_ALARM_MINUTES] = | |
fe20ba70 | 260 | bin2bcd(tm->tm_min) | 0x80; |
c6d8f400 SL |
261 | |
262 | if (tm->tm_hour != -1) | |
263 | fm3130->regs[FM3130_ALARM_HOURS] = | |
fe20ba70 | 264 | bin2bcd(tm->tm_hour) | 0x80; |
c6d8f400 SL |
265 | |
266 | if (tm->tm_mday != -1) | |
267 | fm3130->regs[FM3130_ALARM_DATE] = | |
fe20ba70 | 268 | bin2bcd(tm->tm_mday) | 0x80; |
c6d8f400 SL |
269 | |
270 | if (tm->tm_mon != -1) | |
271 | fm3130->regs[FM3130_ALARM_MONTHS] = | |
fe20ba70 | 272 | bin2bcd(tm->tm_mon + 1) | 0x80; |
c6d8f400 SL |
273 | |
274 | dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", | |
275 | fm3130->regs[FM3130_ALARM_SECONDS], | |
276 | fm3130->regs[FM3130_ALARM_MINUTES], | |
277 | fm3130->regs[FM3130_ALARM_HOURS], | |
278 | fm3130->regs[FM3130_ALARM_DATE], | |
279 | fm3130->regs[FM3130_ALARM_MONTHS]); | |
280 | /* Writing time registers, we don't support multibyte transfers */ | |
281 | for (i = 0; i < FM3130_ALARM_REGS; i++) { | |
282 | i2c_smbus_write_byte_data(fm3130->client, | |
283 | FM3130_ALARM_SECONDS + i, | |
284 | fm3130->regs[FM3130_ALARM_SECONDS + i]); | |
285 | } | |
286 | fm3130->regs[FM3130_RTC_CONTROL] = | |
287 | i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); | |
288 | /* Checking for alarm */ | |
289 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { | |
290 | fm3130->alarm = 1; | |
291 | fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; | |
292 | } | |
293 | if (alrm->enabled) { | |
294 | i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, | |
295 | (fm3130->regs[FM3130_RTC_CONTROL] & | |
296 | ~(FM3130_RTC_CONTROL_BIT_CAL)) | | |
297 | FM3130_RTC_CONTROL_BIT_AEN); | |
298 | } else { | |
299 | i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, | |
300 | fm3130->regs[FM3130_RTC_CONTROL] & | |
301 | ~(FM3130_RTC_CONTROL_BIT_AEN)); | |
302 | } | |
303 | return 0; | |
304 | } | |
305 | ||
306 | static const struct rtc_class_ops fm3130_rtc_ops = { | |
307 | .read_time = fm3130_get_time, | |
308 | .set_time = fm3130_set_time, | |
309 | .read_alarm = fm3130_read_alarm, | |
310 | .set_alarm = fm3130_set_alarm, | |
311 | }; | |
312 | ||
313 | static struct i2c_driver fm3130_driver; | |
314 | ||
315 | static int __devinit fm3130_probe(struct i2c_client *client, | |
316 | const struct i2c_device_id *id) | |
317 | { | |
318 | struct fm3130 *fm3130; | |
319 | int err = -ENODEV; | |
320 | int tmp; | |
321 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | |
322 | ||
323 | if (!i2c_check_functionality(adapter, | |
324 | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | |
325 | return -EIO; | |
326 | ||
327 | fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL); | |
328 | ||
329 | if (!fm3130) | |
330 | return -ENOMEM; | |
331 | ||
332 | fm3130->client = client; | |
333 | i2c_set_clientdata(client, fm3130); | |
334 | fm3130->reg_addr_time = FM3130_RTC_SECONDS; | |
335 | fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS; | |
336 | ||
337 | /* Messages to read time */ | |
338 | fm3130->msg[0].addr = client->addr; | |
339 | fm3130->msg[0].flags = 0; | |
340 | fm3130->msg[0].len = 1; | |
341 | fm3130->msg[0].buf = &fm3130->reg_addr_time; | |
342 | ||
343 | fm3130->msg[1].addr = client->addr; | |
344 | fm3130->msg[1].flags = I2C_M_RD; | |
345 | fm3130->msg[1].len = FM3130_CLOCK_REGS; | |
346 | fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS]; | |
347 | ||
348 | /* Messages to read alarm */ | |
349 | fm3130->msg[2].addr = client->addr; | |
350 | fm3130->msg[2].flags = 0; | |
351 | fm3130->msg[2].len = 1; | |
352 | fm3130->msg[2].buf = &fm3130->reg_addr_alarm; | |
353 | ||
354 | fm3130->msg[3].addr = client->addr; | |
355 | fm3130->msg[3].flags = I2C_M_RD; | |
356 | fm3130->msg[3].len = FM3130_ALARM_REGS; | |
357 | fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; | |
358 | ||
359 | fm3130->data_valid = 0; | |
360 | ||
361 | tmp = i2c_transfer(adapter, fm3130->msg, 4); | |
362 | if (tmp != 4) { | |
363 | pr_debug("read error %d\n", tmp); | |
364 | err = -EIO; | |
365 | goto exit_free; | |
366 | } | |
367 | ||
368 | fm3130->regs[FM3130_RTC_CONTROL] = | |
369 | i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL); | |
370 | fm3130->regs[FM3130_CAL_CONTROL] = | |
371 | i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); | |
372 | ||
373 | /* Checking for alarm */ | |
374 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { | |
375 | fm3130->alarm = 1; | |
376 | fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; | |
377 | } | |
378 | ||
379 | /* Disabling calibration mode */ | |
f4b51628 | 380 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) { |
c6d8f400 SL |
381 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, |
382 | fm3130->regs[FM3130_RTC_CONTROL] & | |
383 | ~(FM3130_RTC_CONTROL_BIT_CAL)); | |
384 | dev_warn(&client->dev, "Disabling calibration mode!\n"); | |
f4b51628 | 385 | } |
c6d8f400 SL |
386 | |
387 | /* Disabling read and write modes */ | |
388 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE || | |
f4b51628 | 389 | fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) { |
c6d8f400 SL |
390 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, |
391 | fm3130->regs[FM3130_RTC_CONTROL] & | |
392 | ~(FM3130_RTC_CONTROL_BIT_READ | | |
393 | FM3130_RTC_CONTROL_BIT_WRITE)); | |
394 | dev_warn(&client->dev, "Disabling READ or WRITE mode!\n"); | |
f4b51628 | 395 | } |
c6d8f400 SL |
396 | |
397 | /* oscillator off? turn it on, so clock can tick. */ | |
398 | if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN) | |
399 | i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL, | |
400 | fm3130->regs[FM3130_CAL_CONTROL] & | |
401 | ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); | |
402 | ||
403 | /* oscillator fault? clear flag, and warn */ | |
404 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) | |
405 | dev_warn(&client->dev, "Low battery!\n"); | |
406 | ||
407 | /* oscillator fault? clear flag, and warn */ | |
408 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { | |
409 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, | |
410 | fm3130->regs[FM3130_RTC_CONTROL] & | |
411 | ~FM3130_RTC_CONTROL_BIT_POR); | |
412 | dev_warn(&client->dev, "SET TIME!\n"); | |
413 | } | |
414 | /* ACS is controlled by alarm */ | |
415 | i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); | |
416 | ||
417 | /* TODO */ | |
418 | /* TODO need to sanity check alarm */ | |
419 | tmp = fm3130->regs[FM3130_RTC_SECONDS]; | |
fe20ba70 | 420 | tmp = bcd2bin(tmp & 0x7f); |
c6d8f400 SL |
421 | if (tmp > 60) |
422 | goto exit_bad; | |
fe20ba70 | 423 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); |
c6d8f400 SL |
424 | if (tmp > 60) |
425 | goto exit_bad; | |
426 | ||
fe20ba70 | 427 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); |
c6d8f400 SL |
428 | if (tmp == 0 || tmp > 31) |
429 | goto exit_bad; | |
430 | ||
fe20ba70 | 431 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); |
c6d8f400 SL |
432 | if (tmp == 0 || tmp > 12) |
433 | goto exit_bad; | |
434 | ||
435 | tmp = fm3130->regs[FM3130_RTC_HOURS]; | |
436 | ||
437 | fm3130->data_valid = 1; | |
438 | ||
439 | exit_bad: | |
440 | if (!fm3130->data_valid) | |
441 | dev_dbg(&client->dev, | |
442 | "%s: %02x %02x %02x %02x %02x %02x %02x %02x" | |
443 | "%02x %02x %02x %02x %02x %02x %02x\n", | |
444 | "bogus registers", | |
445 | fm3130->regs[0], fm3130->regs[1], | |
446 | fm3130->regs[2], fm3130->regs[3], | |
447 | fm3130->regs[4], fm3130->regs[5], | |
448 | fm3130->regs[6], fm3130->regs[7], | |
449 | fm3130->regs[8], fm3130->regs[9], | |
450 | fm3130->regs[0xa], fm3130->regs[0xb], | |
451 | fm3130->regs[0xc], fm3130->regs[0xd], | |
452 | fm3130->regs[0xe]); | |
453 | ||
454 | /* We won't bail out here because we just got invalid data. | |
455 | Time setting from u-boot doesn't work anyway */ | |
456 | fm3130->rtc = rtc_device_register(client->name, &client->dev, | |
457 | &fm3130_rtc_ops, THIS_MODULE); | |
458 | if (IS_ERR(fm3130->rtc)) { | |
459 | err = PTR_ERR(fm3130->rtc); | |
460 | dev_err(&client->dev, | |
461 | "unable to register the class device\n"); | |
462 | goto exit_free; | |
463 | } | |
464 | return 0; | |
465 | exit_free: | |
466 | kfree(fm3130); | |
467 | return err; | |
468 | } | |
469 | ||
470 | static int __devexit fm3130_remove(struct i2c_client *client) | |
471 | { | |
472 | struct fm3130 *fm3130 = i2c_get_clientdata(client); | |
473 | ||
474 | rtc_device_unregister(fm3130->rtc); | |
475 | kfree(fm3130); | |
476 | return 0; | |
477 | } | |
478 | ||
479 | static struct i2c_driver fm3130_driver = { | |
480 | .driver = { | |
481 | .name = "rtc-fm3130", | |
482 | .owner = THIS_MODULE, | |
483 | }, | |
484 | .probe = fm3130_probe, | |
485 | .remove = __devexit_p(fm3130_remove), | |
486 | .id_table = fm3130_id, | |
487 | }; | |
488 | ||
489 | static int __init fm3130_init(void) | |
490 | { | |
491 | return i2c_add_driver(&fm3130_driver); | |
492 | } | |
493 | module_init(fm3130_init); | |
494 | ||
495 | static void __exit fm3130_exit(void) | |
496 | { | |
497 | i2c_del_driver(&fm3130_driver); | |
498 | } | |
499 | module_exit(fm3130_exit); | |
500 | ||
501 | MODULE_DESCRIPTION("RTC driver for FM3130"); | |
502 | MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>"); | |
503 | MODULE_LICENSE("GPL"); | |
504 |