diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 154 | ||||
-rw-r--r-- | drivers/rtc/rtc-parisc.c | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf50633.c | 344 |
5 files changed, 393 insertions, 116 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4ad831de41ad..cced4d108319 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -502,6 +502,13 @@ config RTC_DRV_WM8350 | |||
502 | This driver can also be built as a module. If so, the module | 502 | This driver can also be built as a module. If so, the module |
503 | will be called "rtc-wm8350". | 503 | will be called "rtc-wm8350". |
504 | 504 | ||
505 | config RTC_DRV_PCF50633 | ||
506 | depends on MFD_PCF50633 | ||
507 | tristate "NXP PCF50633 RTC" | ||
508 | help | ||
509 | If you say yes here you get support for the RTC subsystem of the | ||
510 | NXP PCF50633 used in embedded systems. | ||
511 | |||
505 | comment "on-CPU RTC drivers" | 512 | comment "on-CPU RTC drivers" |
506 | 513 | ||
507 | config RTC_DRV_OMAP | 514 | config RTC_DRV_OMAP |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 9a4340d48f26..6e28021abb9d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -74,3 +74,4 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | |||
74 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 74 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
75 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o | 75 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o |
76 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 76 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
77 | obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o | ||
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 162330b9d1dc..7e5155e88ac7 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -86,13 +86,11 @@ enum ds_type { | |||
86 | 86 | ||
87 | 87 | ||
88 | struct ds1307 { | 88 | struct ds1307 { |
89 | u8 reg_addr; | ||
90 | u8 regs[11]; | 89 | u8 regs[11]; |
91 | enum ds_type type; | 90 | enum ds_type type; |
92 | unsigned long flags; | 91 | unsigned long flags; |
93 | #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ | 92 | #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ |
94 | #define HAS_ALARM 1 /* bit 1 == irq claimed */ | 93 | #define HAS_ALARM 1 /* bit 1 == irq claimed */ |
95 | struct i2c_msg msg[2]; | ||
96 | struct i2c_client *client; | 94 | struct i2c_client *client; |
97 | struct rtc_device *rtc; | 95 | struct rtc_device *rtc; |
98 | struct work_struct work; | 96 | struct work_struct work; |
@@ -204,13 +202,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) | |||
204 | int tmp; | 202 | int tmp; |
205 | 203 | ||
206 | /* read the RTC date and time registers all at once */ | 204 | /* read the RTC date and time registers all at once */ |
207 | ds1307->reg_addr = 0; | 205 | tmp = i2c_smbus_read_i2c_block_data(ds1307->client, |
208 | ds1307->msg[1].flags = I2C_M_RD; | 206 | DS1307_REG_SECS, 7, ds1307->regs); |
209 | ds1307->msg[1].len = 7; | 207 | if (tmp != 7) { |
210 | |||
211 | tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), | ||
212 | ds1307->msg, 2); | ||
213 | if (tmp != 2) { | ||
214 | dev_err(dev, "%s error %d\n", "read", tmp); | 208 | dev_err(dev, "%s error %d\n", "read", tmp); |
215 | return -EIO; | 209 | return -EIO; |
216 | } | 210 | } |
@@ -257,7 +251,6 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | |||
257 | t->tm_hour, t->tm_mday, | 251 | t->tm_hour, t->tm_mday, |
258 | t->tm_mon, t->tm_year, t->tm_wday); | 252 | t->tm_mon, t->tm_year, t->tm_wday); |
259 | 253 | ||
260 | *buf++ = 0; /* first register addr */ | ||
261 | buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec); | 254 | buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec); |
262 | buf[DS1307_REG_MIN] = bin2bcd(t->tm_min); | 255 | buf[DS1307_REG_MIN] = bin2bcd(t->tm_min); |
263 | buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); | 256 | buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); |
@@ -282,23 +275,19 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | |||
282 | break; | 275 | break; |
283 | } | 276 | } |
284 | 277 | ||
285 | ds1307->msg[1].flags = 0; | ||
286 | ds1307->msg[1].len = 8; | ||
287 | |||
288 | dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", | 278 | dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", |
289 | "write", buf[0], buf[1], buf[2], buf[3], | 279 | "write", buf[0], buf[1], buf[2], buf[3], |
290 | buf[4], buf[5], buf[6]); | 280 | buf[4], buf[5], buf[6]); |
291 | 281 | ||
292 | result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), | 282 | result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); |
293 | &ds1307->msg[1], 1); | 283 | if (result < 0) { |
294 | if (result != 1) { | 284 | dev_err(dev, "%s error %d\n", "write", result); |
295 | dev_err(dev, "%s error %d\n", "write", tmp); | 285 | return result; |
296 | return -EIO; | ||
297 | } | 286 | } |
298 | return 0; | 287 | return 0; |
299 | } | 288 | } |
300 | 289 | ||
301 | static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) | 290 | static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) |
302 | { | 291 | { |
303 | struct i2c_client *client = to_i2c_client(dev); | 292 | struct i2c_client *client = to_i2c_client(dev); |
304 | struct ds1307 *ds1307 = i2c_get_clientdata(client); | 293 | struct ds1307 *ds1307 = i2c_get_clientdata(client); |
@@ -308,13 +297,9 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
308 | return -EINVAL; | 297 | return -EINVAL; |
309 | 298 | ||
310 | /* read all ALARM1, ALARM2, and status registers at once */ | 299 | /* read all ALARM1, ALARM2, and status registers at once */ |
311 | ds1307->reg_addr = DS1339_REG_ALARM1_SECS; | 300 | ret = i2c_smbus_read_i2c_block_data(client, |
312 | ds1307->msg[1].flags = I2C_M_RD; | 301 | DS1339_REG_ALARM1_SECS, 9, ds1307->regs); |
313 | ds1307->msg[1].len = 9; | 302 | if (ret != 9) { |
314 | |||
315 | ret = i2c_transfer(to_i2c_adapter(client->dev.parent), | ||
316 | ds1307->msg, 2); | ||
317 | if (ret != 2) { | ||
318 | dev_err(dev, "%s error %d\n", "alarm read", ret); | 303 | dev_err(dev, "%s error %d\n", "alarm read", ret); |
319 | return -EIO; | 304 | return -EIO; |
320 | } | 305 | } |
@@ -353,7 +338,7 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
353 | return 0; | 338 | return 0; |
354 | } | 339 | } |
355 | 340 | ||
356 | static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) | 341 | static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) |
357 | { | 342 | { |
358 | struct i2c_client *client = to_i2c_client(dev); | 343 | struct i2c_client *client = to_i2c_client(dev); |
359 | struct ds1307 *ds1307 = i2c_get_clientdata(client); | 344 | struct ds1307 *ds1307 = i2c_get_clientdata(client); |
@@ -371,13 +356,9 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
371 | t->enabled, t->pending); | 356 | t->enabled, t->pending); |
372 | 357 | ||
373 | /* read current status of both alarms and the chip */ | 358 | /* read current status of both alarms and the chip */ |
374 | ds1307->reg_addr = DS1339_REG_ALARM1_SECS; | 359 | ret = i2c_smbus_read_i2c_block_data(client, |
375 | ds1307->msg[1].flags = I2C_M_RD; | 360 | DS1339_REG_ALARM1_SECS, 9, buf); |
376 | ds1307->msg[1].len = 9; | 361 | if (ret != 9) { |
377 | |||
378 | ret = i2c_transfer(to_i2c_adapter(client->dev.parent), | ||
379 | ds1307->msg, 2); | ||
380 | if (ret != 2) { | ||
381 | dev_err(dev, "%s error %d\n", "alarm write", ret); | 362 | dev_err(dev, "%s error %d\n", "alarm write", ret); |
382 | return -EIO; | 363 | return -EIO; |
383 | } | 364 | } |
@@ -392,7 +373,6 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
392 | ds1307->regs[6], control, status); | 373 | ds1307->regs[6], control, status); |
393 | 374 | ||
394 | /* set ALARM1, using 24 hour and day-of-month modes */ | 375 | /* set ALARM1, using 24 hour and day-of-month modes */ |
395 | *buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */ | ||
396 | buf[0] = bin2bcd(t->time.tm_sec); | 376 | buf[0] = bin2bcd(t->time.tm_sec); |
397 | buf[1] = bin2bcd(t->time.tm_min); | 377 | buf[1] = bin2bcd(t->time.tm_min); |
398 | buf[2] = bin2bcd(t->time.tm_hour); | 378 | buf[2] = bin2bcd(t->time.tm_hour); |
@@ -411,14 +391,11 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
411 | } | 391 | } |
412 | buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); | 392 | buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); |
413 | 393 | ||
414 | ds1307->msg[1].flags = 0; | 394 | ret = i2c_smbus_write_i2c_block_data(client, |
415 | ds1307->msg[1].len = 10; | 395 | DS1339_REG_ALARM1_SECS, 9, buf); |
416 | 396 | if (ret < 0) { | |
417 | ret = i2c_transfer(to_i2c_adapter(client->dev.parent), | ||
418 | &ds1307->msg[1], 1); | ||
419 | if (ret != 1) { | ||
420 | dev_err(dev, "can't set alarm time\n"); | 397 | dev_err(dev, "can't set alarm time\n"); |
421 | return -EIO; | 398 | return ret; |
422 | } | 399 | } |
423 | 400 | ||
424 | return 0; | 401 | return 0; |
@@ -475,8 +452,8 @@ static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |||
475 | static const struct rtc_class_ops ds13xx_rtc_ops = { | 452 | static const struct rtc_class_ops ds13xx_rtc_ops = { |
476 | .read_time = ds1307_get_time, | 453 | .read_time = ds1307_get_time, |
477 | .set_time = ds1307_set_time, | 454 | .set_time = ds1307_set_time, |
478 | .read_alarm = ds1307_read_alarm, | 455 | .read_alarm = ds1337_read_alarm, |
479 | .set_alarm = ds1307_set_alarm, | 456 | .set_alarm = ds1337_set_alarm, |
480 | .ioctl = ds1307_ioctl, | 457 | .ioctl = ds1307_ioctl, |
481 | }; | 458 | }; |
482 | 459 | ||
@@ -490,7 +467,6 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, | |||
490 | { | 467 | { |
491 | struct i2c_client *client; | 468 | struct i2c_client *client; |
492 | struct ds1307 *ds1307; | 469 | struct ds1307 *ds1307; |
493 | struct i2c_msg msg[2]; | ||
494 | int result; | 470 | int result; |
495 | 471 | ||
496 | client = kobj_to_i2c_client(kobj); | 472 | client = kobj_to_i2c_client(kobj); |
@@ -503,24 +479,10 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, | |||
503 | if (unlikely(!count)) | 479 | if (unlikely(!count)) |
504 | return count; | 480 | return count; |
505 | 481 | ||
506 | msg[0].addr = client->addr; | 482 | result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); |
507 | msg[0].flags = 0; | 483 | if (result < 0) |
508 | msg[0].len = 1; | ||
509 | msg[0].buf = buf; | ||
510 | |||
511 | buf[0] = 8 + off; | ||
512 | |||
513 | msg[1].addr = client->addr; | ||
514 | msg[1].flags = I2C_M_RD; | ||
515 | msg[1].len = count; | ||
516 | msg[1].buf = buf; | ||
517 | |||
518 | result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2); | ||
519 | if (result != 2) { | ||
520 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); | 484 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); |
521 | return -EIO; | 485 | return result; |
522 | } | ||
523 | return count; | ||
524 | } | 486 | } |
525 | 487 | ||
526 | static ssize_t | 488 | static ssize_t |
@@ -528,8 +490,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, | |||
528 | char *buf, loff_t off, size_t count) | 490 | char *buf, loff_t off, size_t count) |
529 | { | 491 | { |
530 | struct i2c_client *client; | 492 | struct i2c_client *client; |
531 | u8 buffer[NVRAM_SIZE + 1]; | 493 | int result; |
532 | int ret; | ||
533 | 494 | ||
534 | client = kobj_to_i2c_client(kobj); | 495 | client = kobj_to_i2c_client(kobj); |
535 | 496 | ||
@@ -540,11 +501,12 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, | |||
540 | if (unlikely(!count)) | 501 | if (unlikely(!count)) |
541 | return count; | 502 | return count; |
542 | 503 | ||
543 | buffer[0] = 8 + off; | 504 | result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); |
544 | memcpy(buffer + 1, buf, count); | 505 | if (result < 0) { |
545 | 506 | dev_err(&client->dev, "%s error %d\n", "nvram write", result); | |
546 | ret = i2c_master_send(client, buffer, count + 1); | 507 | return result; |
547 | return (ret < 0) ? ret : (ret - 1); | 508 | } |
509 | return count; | ||
548 | } | 510 | } |
549 | 511 | ||
550 | static struct bin_attribute nvram = { | 512 | static struct bin_attribute nvram = { |
@@ -571,9 +533,11 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
571 | const struct chip_desc *chip = &chips[id->driver_data]; | 533 | const struct chip_desc *chip = &chips[id->driver_data]; |
572 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 534 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
573 | int want_irq = false; | 535 | int want_irq = false; |
536 | unsigned char *buf; | ||
574 | 537 | ||
575 | if (!i2c_check_functionality(adapter, | 538 | if (!i2c_check_functionality(adapter, |
576 | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | 539 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | |
540 | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
577 | return -EIO; | 541 | return -EIO; |
578 | 542 | ||
579 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) | 543 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) |
@@ -581,18 +545,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
581 | 545 | ||
582 | ds1307->client = client; | 546 | ds1307->client = client; |
583 | i2c_set_clientdata(client, ds1307); | 547 | i2c_set_clientdata(client, ds1307); |
584 | |||
585 | ds1307->msg[0].addr = client->addr; | ||
586 | ds1307->msg[0].flags = 0; | ||
587 | ds1307->msg[0].len = 1; | ||
588 | ds1307->msg[0].buf = &ds1307->reg_addr; | ||
589 | |||
590 | ds1307->msg[1].addr = client->addr; | ||
591 | ds1307->msg[1].flags = I2C_M_RD; | ||
592 | ds1307->msg[1].len = sizeof(ds1307->regs); | ||
593 | ds1307->msg[1].buf = ds1307->regs; | ||
594 | |||
595 | ds1307->type = id->driver_data; | 548 | ds1307->type = id->driver_data; |
549 | buf = ds1307->regs; | ||
596 | 550 | ||
597 | switch (ds1307->type) { | 551 | switch (ds1307->type) { |
598 | case ds_1337: | 552 | case ds_1337: |
@@ -602,21 +556,15 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
602 | INIT_WORK(&ds1307->work, ds1307_work); | 556 | INIT_WORK(&ds1307->work, ds1307_work); |
603 | want_irq = true; | 557 | want_irq = true; |
604 | } | 558 | } |
605 | |||
606 | ds1307->reg_addr = DS1337_REG_CONTROL; | ||
607 | ds1307->msg[1].len = 2; | ||
608 | |||
609 | /* get registers that the "rtc" read below won't read... */ | 559 | /* get registers that the "rtc" read below won't read... */ |
610 | tmp = i2c_transfer(adapter, ds1307->msg, 2); | 560 | tmp = i2c_smbus_read_i2c_block_data(ds1307->client, |
561 | DS1337_REG_CONTROL, 2, buf); | ||
611 | if (tmp != 2) { | 562 | if (tmp != 2) { |
612 | pr_debug("read error %d\n", tmp); | 563 | pr_debug("read error %d\n", tmp); |
613 | err = -EIO; | 564 | err = -EIO; |
614 | goto exit_free; | 565 | goto exit_free; |
615 | } | 566 | } |
616 | 567 | ||
617 | ds1307->reg_addr = 0; | ||
618 | ds1307->msg[1].len = sizeof(ds1307->regs); | ||
619 | |||
620 | /* oscillator off? turn it on, so clock can tick. */ | 568 | /* oscillator off? turn it on, so clock can tick. */ |
621 | if (ds1307->regs[0] & DS1337_BIT_nEOSC) | 569 | if (ds1307->regs[0] & DS1337_BIT_nEOSC) |
622 | ds1307->regs[0] &= ~DS1337_BIT_nEOSC; | 570 | ds1307->regs[0] &= ~DS1337_BIT_nEOSC; |
@@ -647,9 +595,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
647 | 595 | ||
648 | read_rtc: | 596 | read_rtc: |
649 | /* read RTC registers */ | 597 | /* read RTC registers */ |
650 | 598 | tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); | |
651 | tmp = i2c_transfer(adapter, ds1307->msg, 2); | 599 | if (tmp != 8) { |
652 | if (tmp != 2) { | ||
653 | pr_debug("read error %d\n", tmp); | 600 | pr_debug("read error %d\n", tmp); |
654 | err = -EIO; | 601 | err = -EIO; |
655 | goto exit_free; | 602 | goto exit_free; |
@@ -707,22 +654,6 @@ read_rtc: | |||
707 | break; | 654 | break; |
708 | } | 655 | } |
709 | 656 | ||
710 | tmp = ds1307->regs[DS1307_REG_SECS]; | ||
711 | tmp = bcd2bin(tmp & 0x7f); | ||
712 | if (tmp > 60) | ||
713 | goto exit_bad; | ||
714 | tmp = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); | ||
715 | if (tmp > 60) | ||
716 | goto exit_bad; | ||
717 | |||
718 | tmp = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f); | ||
719 | if (tmp == 0 || tmp > 31) | ||
720 | goto exit_bad; | ||
721 | |||
722 | tmp = bcd2bin(ds1307->regs[DS1307_REG_MONTH] & 0x1f); | ||
723 | if (tmp == 0 || tmp > 12) | ||
724 | goto exit_bad; | ||
725 | |||
726 | tmp = ds1307->regs[DS1307_REG_HOUR]; | 657 | tmp = ds1307->regs[DS1307_REG_HOUR]; |
727 | switch (ds1307->type) { | 658 | switch (ds1307->type) { |
728 | case ds_1340: | 659 | case ds_1340: |
@@ -779,13 +710,6 @@ read_rtc: | |||
779 | 710 | ||
780 | return 0; | 711 | return 0; |
781 | 712 | ||
782 | exit_bad: | ||
783 | dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", | ||
784 | "bogus register", | ||
785 | ds1307->regs[0], ds1307->regs[1], | ||
786 | ds1307->regs[2], ds1307->regs[3], | ||
787 | ds1307->regs[4], ds1307->regs[5], | ||
788 | ds1307->regs[6]); | ||
789 | exit_irq: | 713 | exit_irq: |
790 | if (ds1307->rtc) | 714 | if (ds1307->rtc) |
791 | rtc_device_unregister(ds1307->rtc); | 715 | rtc_device_unregister(ds1307->rtc); |
diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 346d633655e7..c6bfa6fe1a2a 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c | |||
@@ -34,7 +34,8 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) | |||
34 | static int parisc_set_time(struct device *dev, struct rtc_time *tm) | 34 | static int parisc_set_time(struct device *dev, struct rtc_time *tm) |
35 | { | 35 | { |
36 | struct parisc_rtc *p = dev_get_drvdata(dev); | 36 | struct parisc_rtc *p = dev_get_drvdata(dev); |
37 | unsigned long flags, ret; | 37 | unsigned long flags; |
38 | int ret; | ||
38 | 39 | ||
39 | spin_lock_irqsave(&p->lock, flags); | 40 | spin_lock_irqsave(&p->lock, flags); |
40 | ret = set_rtc_time(tm); | 41 | ret = set_rtc_time(tm); |
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c new file mode 100644 index 000000000000..f4dd87e29075 --- /dev/null +++ b/drivers/rtc/rtc-pcf50633.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* NXP PCF50633 RTC Driver | ||
2 | * | ||
3 | * (C) 2006-2008 by Openmoko, Inc. | ||
4 | * Author: Balaji Rao <balajirrao@openmoko.org> | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Broken down from monstrous PCF50633 driver mainly by | ||
8 | * Harald Welte, Andy Green and Werner Almesberger | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/rtc.h> | ||
23 | #include <linux/bcd.h> | ||
24 | #include <linux/err.h> | ||
25 | |||
26 | #include <linux/mfd/pcf50633/core.h> | ||
27 | |||
28 | #define PCF50633_REG_RTCSC 0x59 /* Second */ | ||
29 | #define PCF50633_REG_RTCMN 0x5a /* Minute */ | ||
30 | #define PCF50633_REG_RTCHR 0x5b /* Hour */ | ||
31 | #define PCF50633_REG_RTCWD 0x5c /* Weekday */ | ||
32 | #define PCF50633_REG_RTCDT 0x5d /* Day */ | ||
33 | #define PCF50633_REG_RTCMT 0x5e /* Month */ | ||
34 | #define PCF50633_REG_RTCYR 0x5f /* Year */ | ||
35 | #define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */ | ||
36 | #define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */ | ||
37 | #define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */ | ||
38 | #define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */ | ||
39 | #define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */ | ||
40 | #define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */ | ||
41 | #define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */ | ||
42 | |||
43 | enum pcf50633_time_indexes { | ||
44 | PCF50633_TI_SEC, | ||
45 | PCF50633_TI_MIN, | ||
46 | PCF50633_TI_HOUR, | ||
47 | PCF50633_TI_WKDAY, | ||
48 | PCF50633_TI_DAY, | ||
49 | PCF50633_TI_MONTH, | ||
50 | PCF50633_TI_YEAR, | ||
51 | PCF50633_TI_EXTENT /* always last */ | ||
52 | }; | ||
53 | |||
54 | struct pcf50633_time { | ||
55 | u_int8_t time[PCF50633_TI_EXTENT]; | ||
56 | }; | ||
57 | |||
58 | struct pcf50633_rtc { | ||
59 | int alarm_enabled; | ||
60 | int second_enabled; | ||
61 | |||
62 | struct pcf50633 *pcf; | ||
63 | struct rtc_device *rtc_dev; | ||
64 | }; | ||
65 | |||
66 | static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf) | ||
67 | { | ||
68 | rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]); | ||
69 | rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]); | ||
70 | rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]); | ||
71 | rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]); | ||
72 | rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]); | ||
73 | rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]); | ||
74 | rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100; | ||
75 | } | ||
76 | |||
77 | static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc) | ||
78 | { | ||
79 | pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec); | ||
80 | pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min); | ||
81 | pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour); | ||
82 | pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday); | ||
83 | pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday); | ||
84 | pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon); | ||
85 | pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100); | ||
86 | } | ||
87 | |||
88 | static int | ||
89 | pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
90 | { | ||
91 | struct pcf50633_rtc *rtc = dev_get_drvdata(dev); | ||
92 | int err; | ||
93 | |||
94 | if (enabled) | ||
95 | err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
96 | else | ||
97 | err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
98 | |||
99 | if (err < 0) | ||
100 | return err; | ||
101 | |||
102 | rtc->alarm_enabled = enabled; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int | ||
108 | pcf50633_rtc_update_irq_enable(struct device *dev, unsigned int enabled) | ||
109 | { | ||
110 | struct pcf50633_rtc *rtc = dev_get_drvdata(dev); | ||
111 | int err; | ||
112 | |||
113 | if (enabled) | ||
114 | err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
115 | else | ||
116 | err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
117 | |||
118 | if (err < 0) | ||
119 | return err; | ||
120 | |||
121 | rtc->second_enabled = enabled; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
127 | { | ||
128 | struct pcf50633_rtc *rtc; | ||
129 | struct pcf50633_time pcf_tm; | ||
130 | int ret; | ||
131 | |||
132 | rtc = dev_get_drvdata(dev); | ||
133 | |||
134 | ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC, | ||
135 | PCF50633_TI_EXTENT, | ||
136 | &pcf_tm.time[0]); | ||
137 | if (ret != PCF50633_TI_EXTENT) { | ||
138 | dev_err(dev, "Failed to read time\n"); | ||
139 | return -EIO; | ||
140 | } | ||
141 | |||
142 | dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", | ||
143 | pcf_tm.time[PCF50633_TI_DAY], | ||
144 | pcf_tm.time[PCF50633_TI_MONTH], | ||
145 | pcf_tm.time[PCF50633_TI_YEAR], | ||
146 | pcf_tm.time[PCF50633_TI_HOUR], | ||
147 | pcf_tm.time[PCF50633_TI_MIN], | ||
148 | pcf_tm.time[PCF50633_TI_SEC]); | ||
149 | |||
150 | pcf2rtc_time(tm, &pcf_tm); | ||
151 | |||
152 | dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", | ||
153 | tm->tm_mday, tm->tm_mon, tm->tm_year, | ||
154 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
155 | |||
156 | return rtc_valid_tm(tm); | ||
157 | } | ||
158 | |||
159 | static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
160 | { | ||
161 | struct pcf50633_rtc *rtc; | ||
162 | struct pcf50633_time pcf_tm; | ||
163 | int second_masked, alarm_masked, ret = 0; | ||
164 | |||
165 | rtc = dev_get_drvdata(dev); | ||
166 | |||
167 | dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", | ||
168 | tm->tm_mday, tm->tm_mon, tm->tm_year, | ||
169 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
170 | |||
171 | rtc2pcf_time(&pcf_tm, tm); | ||
172 | |||
173 | dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", | ||
174 | pcf_tm.time[PCF50633_TI_DAY], | ||
175 | pcf_tm.time[PCF50633_TI_MONTH], | ||
176 | pcf_tm.time[PCF50633_TI_YEAR], | ||
177 | pcf_tm.time[PCF50633_TI_HOUR], | ||
178 | pcf_tm.time[PCF50633_TI_MIN], | ||
179 | pcf_tm.time[PCF50633_TI_SEC]); | ||
180 | |||
181 | |||
182 | second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND); | ||
183 | alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); | ||
184 | |||
185 | if (!second_masked) | ||
186 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
187 | if (!alarm_masked) | ||
188 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
189 | |||
190 | /* Returns 0 on success */ | ||
191 | ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC, | ||
192 | PCF50633_TI_EXTENT, | ||
193 | &pcf_tm.time[0]); | ||
194 | |||
195 | if (!second_masked) | ||
196 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
197 | if (!alarm_masked) | ||
198 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
199 | |||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
204 | { | ||
205 | struct pcf50633_rtc *rtc; | ||
206 | struct pcf50633_time pcf_tm; | ||
207 | int ret = 0; | ||
208 | |||
209 | rtc = dev_get_drvdata(dev); | ||
210 | |||
211 | alrm->enabled = rtc->alarm_enabled; | ||
212 | |||
213 | ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, | ||
214 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); | ||
215 | if (ret != PCF50633_TI_EXTENT) { | ||
216 | dev_err(dev, "Failed to read time\n"); | ||
217 | return -EIO; | ||
218 | } | ||
219 | |||
220 | pcf2rtc_time(&alrm->time, &pcf_tm); | ||
221 | |||
222 | return rtc_valid_tm(&alrm->time); | ||
223 | } | ||
224 | |||
225 | static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
226 | { | ||
227 | struct pcf50633_rtc *rtc; | ||
228 | struct pcf50633_time pcf_tm; | ||
229 | int alarm_masked, ret = 0; | ||
230 | |||
231 | rtc = dev_get_drvdata(dev); | ||
232 | |||
233 | rtc2pcf_time(&pcf_tm, &alrm->time); | ||
234 | |||
235 | /* do like mktime does and ignore tm_wday */ | ||
236 | pcf_tm.time[PCF50633_TI_WKDAY] = 7; | ||
237 | |||
238 | alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); | ||
239 | |||
240 | /* disable alarm interrupt */ | ||
241 | if (!alarm_masked) | ||
242 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
243 | |||
244 | /* Returns 0 on success */ | ||
245 | ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, | ||
246 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); | ||
247 | |||
248 | if (!alarm_masked) | ||
249 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
250 | |||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | static struct rtc_class_ops pcf50633_rtc_ops = { | ||
255 | .read_time = pcf50633_rtc_read_time, | ||
256 | .set_time = pcf50633_rtc_set_time, | ||
257 | .read_alarm = pcf50633_rtc_read_alarm, | ||
258 | .set_alarm = pcf50633_rtc_set_alarm, | ||
259 | .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable, | ||
260 | .update_irq_enable = pcf50633_rtc_update_irq_enable, | ||
261 | }; | ||
262 | |||
263 | static void pcf50633_rtc_irq(int irq, void *data) | ||
264 | { | ||
265 | struct pcf50633_rtc *rtc = data; | ||
266 | |||
267 | switch (irq) { | ||
268 | case PCF50633_IRQ_ALARM: | ||
269 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); | ||
270 | break; | ||
271 | case PCF50633_IRQ_SECOND: | ||
272 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); | ||
273 | break; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) | ||
278 | { | ||
279 | struct pcf50633_subdev_pdata *pdata; | ||
280 | struct pcf50633_rtc *rtc; | ||
281 | |||
282 | |||
283 | rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); | ||
284 | if (!rtc) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | pdata = pdev->dev.platform_data; | ||
288 | rtc->pcf = pdata->pcf; | ||
289 | platform_set_drvdata(pdev, rtc); | ||
290 | rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev, | ||
291 | &pcf50633_rtc_ops, THIS_MODULE); | ||
292 | |||
293 | if (IS_ERR(rtc->rtc_dev)) { | ||
294 | kfree(rtc); | ||
295 | return PTR_ERR(rtc->rtc_dev); | ||
296 | } | ||
297 | |||
298 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, | ||
299 | pcf50633_rtc_irq, rtc); | ||
300 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND, | ||
301 | pcf50633_rtc_irq, rtc); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) | ||
307 | { | ||
308 | struct pcf50633_rtc *rtc; | ||
309 | |||
310 | rtc = platform_get_drvdata(pdev); | ||
311 | |||
312 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); | ||
313 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND); | ||
314 | |||
315 | rtc_device_unregister(rtc->rtc_dev); | ||
316 | kfree(rtc); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static struct platform_driver pcf50633_rtc_driver = { | ||
322 | .driver = { | ||
323 | .name = "pcf50633-rtc", | ||
324 | }, | ||
325 | .probe = pcf50633_rtc_probe, | ||
326 | .remove = __devexit_p(pcf50633_rtc_remove), | ||
327 | }; | ||
328 | |||
329 | static int __init pcf50633_rtc_init(void) | ||
330 | { | ||
331 | return platform_driver_register(&pcf50633_rtc_driver); | ||
332 | } | ||
333 | module_init(pcf50633_rtc_init); | ||
334 | |||
335 | static void __exit pcf50633_rtc_exit(void) | ||
336 | { | ||
337 | platform_driver_unregister(&pcf50633_rtc_driver); | ||
338 | } | ||
339 | module_exit(pcf50633_rtc_exit); | ||
340 | |||
341 | MODULE_DESCRIPTION("PCF50633 RTC driver"); | ||
342 | MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); | ||
343 | MODULE_LICENSE("GPL"); | ||
344 | |||