aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorSergey Matyukevich <geomatsi@gmail.com>2010-08-10 21:02:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:07 -0400
commitf3f99cf39180fc04a36cd376f434092fae85f317 (patch)
tree7ef76a97c4e44def9549f20cd3ef625ea847d3a8 /drivers/rtc
parent5824c7e66724d4d42f01c69feb818d7ac5f11bd9 (diff)
rtc: fixes and new functionality for fm3130
- add sanity check for alarm data in fm3130_probe - fix fm3130_set_alarm. According to the datasheet, setting match bit '0' indicates that the corresponding alarm field will be used in the match process - add operation alarm_irq_enable operation which is responsible for handling RTC_AIE_ON, RTC_AIE_OFF ioctls - remove clearing of AF bit after reading rtc/alarm control register: according to datasheet this bit is cleared anyway when rtc/alarm control register is read [akpm@linux-foundation.org: make fm3130_alarm_irq_enable() static, fix comment layout] Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com> Acked-by: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Sergey Lapin <slapin@ossfans.org> 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/rtc-fm3130.c181
1 files changed, 130 insertions, 51 deletions
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index e4de8f37ae4a..4cf2e70c5078 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -52,8 +52,8 @@ struct fm3130 {
52 struct i2c_msg msg[4]; 52 struct i2c_msg msg[4];
53 struct i2c_client *client; 53 struct i2c_client *client;
54 struct rtc_device *rtc; 54 struct rtc_device *rtc;
55 int alarm_valid;
55 int data_valid; 56 int data_valid;
56 int alarm;
57}; 57};
58static const struct i2c_device_id fm3130_id[] = { 58static const struct i2c_device_id fm3130_id[] = {
59 { "fm3130", 0 }, 59 { "fm3130", 0 },
@@ -87,11 +87,7 @@ static void fm3130_rtc_mode(struct device *dev, int mode)
87 dev_dbg(dev, "invalid mode %d\n", mode); 87 dev_dbg(dev, "invalid mode %d\n", mode);
88 break; 88 break;
89 } 89 }
90 /* Checking for alarm */ 90
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, 91 i2c_smbus_write_byte_data(fm3130->client,
96 FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); 92 FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]);
97} 93}
@@ -208,6 +204,17 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
208 struct fm3130 *fm3130 = dev_get_drvdata(dev); 204 struct fm3130 *fm3130 = dev_get_drvdata(dev);
209 int tmp; 205 int tmp;
210 struct rtc_time *tm = &alrm->time; 206 struct rtc_time *tm = &alrm->time;
207
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
211 /* read the RTC alarm registers all at once */ 218 /* read the RTC alarm registers all at once */
212 tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), 219 tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
213 &fm3130->msg[2], 2); 220 &fm3130->msg[2], 2);
@@ -222,20 +229,31 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
222 fm3130->regs[FM3130_ALARM_DATE], 229 fm3130->regs[FM3130_ALARM_DATE],
223 fm3130->regs[FM3130_ALARM_MONTHS]); 230 fm3130->regs[FM3130_ALARM_MONTHS]);
224 231
225
226 tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); 232 tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
227 tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); 233 tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
228 tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); 234 tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
229 tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); 235 tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
230 tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); 236 tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
237
231 if (tm->tm_mon > 0) 238 if (tm->tm_mon > 0)
232 tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ 239 tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
240
233 dev_dbg(dev, "%s secs=%d, mins=%d, " 241 dev_dbg(dev, "%s secs=%d, mins=%d, "
234 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", 242 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
235 "read alarm", tm->tm_sec, tm->tm_min, 243 "read alarm", tm->tm_sec, tm->tm_min,
236 tm->tm_hour, tm->tm_mday, 244 tm->tm_hour, tm->tm_mday,
237 tm->tm_mon, tm->tm_year, tm->tm_wday); 245 tm->tm_mon, tm->tm_year, tm->tm_wday);
238 246
247 /* 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
239 return 0; 257 return 0;
240} 258}
241 259
@@ -251,25 +269,20 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
251 tm->tm_hour, tm->tm_mday, 269 tm->tm_hour, tm->tm_mday,
252 tm->tm_mon, tm->tm_year, tm->tm_wday); 270 tm->tm_mon, tm->tm_year, tm->tm_wday);
253 271
254 if (tm->tm_sec != -1) 272 fm3130->regs[FM3130_ALARM_SECONDS] =
255 fm3130->regs[FM3130_ALARM_SECONDS] = 273 (tm->tm_sec != -1) ? bin2bcd(tm->tm_sec) : 0x80;
256 bin2bcd(tm->tm_sec) | 0x80;
257 274
258 if (tm->tm_min != -1) 275 fm3130->regs[FM3130_ALARM_MINUTES] =
259 fm3130->regs[FM3130_ALARM_MINUTES] = 276 (tm->tm_min != -1) ? bin2bcd(tm->tm_min) : 0x80;
260 bin2bcd(tm->tm_min) | 0x80;
261 277
262 if (tm->tm_hour != -1) 278 fm3130->regs[FM3130_ALARM_HOURS] =
263 fm3130->regs[FM3130_ALARM_HOURS] = 279 (tm->tm_hour != -1) ? bin2bcd(tm->tm_hour) : 0x80;
264 bin2bcd(tm->tm_hour) | 0x80;
265 280
266 if (tm->tm_mday != -1) 281 fm3130->regs[FM3130_ALARM_DATE] =
267 fm3130->regs[FM3130_ALARM_DATE] = 282 (tm->tm_mday != -1) ? bin2bcd(tm->tm_mday) : 0x80;
268 bin2bcd(tm->tm_mday) | 0x80;
269 283
270 if (tm->tm_mon != -1) 284 fm3130->regs[FM3130_ALARM_MONTHS] =
271 fm3130->regs[FM3130_ALARM_MONTHS] = 285 (tm->tm_mon != -1) ? bin2bcd(tm->tm_mon + 1) : 0x80;
272 bin2bcd(tm->tm_mon + 1) | 0x80;
273 286
274 dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", 287 dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
275 fm3130->regs[FM3130_ALARM_SECONDS], 288 fm3130->regs[FM3130_ALARM_SECONDS],
@@ -285,11 +298,8 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
285 } 298 }
286 fm3130->regs[FM3130_RTC_CONTROL] = 299 fm3130->regs[FM3130_RTC_CONTROL] =
287 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); 300 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
288 /* Checking for alarm */ 301
289 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { 302 /* enable or disable alarm */
290 fm3130->alarm = 1;
291 fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
292 }
293 if (alrm->enabled) { 303 if (alrm->enabled) {
294 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, 304 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
295 (fm3130->regs[FM3130_RTC_CONTROL] & 305 (fm3130->regs[FM3130_RTC_CONTROL] &
@@ -298,16 +308,55 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
298 } else { 308 } else {
299 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, 309 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
300 fm3130->regs[FM3130_RTC_CONTROL] & 310 fm3130->regs[FM3130_RTC_CONTROL] &
301 ~(FM3130_RTC_CONTROL_BIT_AEN)); 311 ~(FM3130_RTC_CONTROL_BIT_CAL) &
312 ~(FM3130_RTC_CONTROL_BIT_AEN));
302 } 313 }
314
315 /* We assume here that data is valid once written */
316 if (!fm3130->alarm_valid)
317 fm3130->alarm_valid = 1;
318
303 return 0; 319 return 0;
304} 320}
305 321
322static 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
306static const struct rtc_class_ops fm3130_rtc_ops = { 354static const struct rtc_class_ops fm3130_rtc_ops = {
307 .read_time = fm3130_get_time, 355 .read_time = fm3130_get_time,
308 .set_time = fm3130_set_time, 356 .set_time = fm3130_set_time,
309 .read_alarm = fm3130_read_alarm, 357 .read_alarm = fm3130_read_alarm,
310 .set_alarm = fm3130_set_alarm, 358 .set_alarm = fm3130_set_alarm,
359 .alarm_irq_enable = fm3130_alarm_irq_enable,
311}; 360};
312 361
313static struct i2c_driver fm3130_driver; 362static struct i2c_driver fm3130_driver;
@@ -356,6 +405,7 @@ static int __devinit fm3130_probe(struct i2c_client *client,
356 fm3130->msg[3].len = FM3130_ALARM_REGS; 405 fm3130->msg[3].len = FM3130_ALARM_REGS;
357 fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; 406 fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS];
358 407
408 fm3130->alarm_valid = 0;
359 fm3130->data_valid = 0; 409 fm3130->data_valid = 0;
360 410
361 tmp = i2c_transfer(adapter, fm3130->msg, 4); 411 tmp = i2c_transfer(adapter, fm3130->msg, 4);
@@ -370,12 +420,6 @@ static int __devinit fm3130_probe(struct i2c_client *client,
370 fm3130->regs[FM3130_CAL_CONTROL] = 420 fm3130->regs[FM3130_CAL_CONTROL] =
371 i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); 421 i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL);
372 422
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 */ 423 /* Disabling calibration mode */
380 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) { 424 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) {
381 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, 425 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
@@ -400,44 +444,79 @@ static int __devinit fm3130_probe(struct i2c_client *client,
400 fm3130->regs[FM3130_CAL_CONTROL] & 444 fm3130->regs[FM3130_CAL_CONTROL] &
401 ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); 445 ~(FM3130_CAL_CONTROL_BIT_nOSCEN));
402 446
403 /* oscillator fault? clear flag, and warn */ 447 /* low battery? clear flag, and warn */
404 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) 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));
405 dev_warn(&client->dev, "Low battery!\n"); 452 dev_warn(&client->dev, "Low battery!\n");
453 }
406 454
407 /* oscillator fault? clear flag, and warn */ 455 /* check if Power On Reset bit is set */
408 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { 456 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) {
409 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, 457 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
410 fm3130->regs[FM3130_RTC_CONTROL] & 458 fm3130->regs[FM3130_RTC_CONTROL] &
411 ~FM3130_RTC_CONTROL_BIT_POR); 459 ~FM3130_RTC_CONTROL_BIT_POR);
412 dev_warn(&client->dev, "SET TIME!\n"); 460 dev_dbg(&client->dev, "POR bit is set\n");
413 } 461 }
414 /* ACS is controlled by alarm */ 462 /* ACS is controlled by alarm */
415 i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); 463 i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80);
416 464
417 /* TODO */ 465 /* alarm registers sanity check */
418 /* TODO need to sanity check alarm */ 466 tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
419 tmp = fm3130->regs[FM3130_RTC_SECONDS]; 467 if (tmp > 59)
420 tmp = bcd2bin(tmp & 0x7f); 468 goto bad_alarm;
421 if (tmp > 60) 469
422 goto exit_bad;
423 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); 470 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
424 if (tmp > 60) 471 if (tmp > 59)
425 goto exit_bad; 472 goto bad_alarm;
473
474 tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f);
475 if (tmp > 23)
476 goto bad_alarm;
426 477
427 tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); 478 tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
428 if (tmp == 0 || tmp > 31) 479 if (tmp == 0 || tmp > 31)
429 goto exit_bad; 480 goto bad_alarm;
430 481
431 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); 482 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
432 if (tmp == 0 || tmp > 12) 483 if (tmp == 0 || tmp > 12)
433 goto exit_bad; 484 goto bad_alarm;
434 485
435 tmp = fm3130->regs[FM3130_RTC_HOURS]; 486 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;
436 514
437 fm3130->data_valid = 1; 515 fm3130->data_valid = 1;
438 516
439exit_bad: 517bad_clock:
440 if (!fm3130->data_valid) 518
519 if (!fm3130->data_valid || !fm3130->alarm_valid)
441 dev_dbg(&client->dev, 520 dev_dbg(&client->dev,
442 "%s: %02x %02x %02x %02x %02x %02x %02x %02x" 521 "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
443 "%02x %02x %02x %02x %02x %02x %02x\n", 522 "%02x %02x %02x %02x %02x %02x %02x\n",