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