diff options
author | Michael Büsch <m@bues.ch> | 2016-03-04 16:41:19 -0500 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2016-03-14 12:08:34 -0400 |
commit | e27e21603e1ff9f6897e5f2ffa7dec09ab0c955c (patch) | |
tree | 43a2d8fd226681de53eaa4b4346c501ca6666b6e /drivers/rtc | |
parent | a7f6e287419cf523c769e87bbef748ae7bd856ff (diff) |
rtc: rv3029: Add device tree property for trickle charger
The trickle charger resistor can be enabled via device tree
property trickle-resistor-ohms.
Signed-off-by: Michael Buesch <m@bues.ch>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-rv3029c2.c | 106 |
1 files changed, 103 insertions, 3 deletions
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index e59b8a54d9a7..b416ed026168 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c | |||
@@ -10,9 +10,6 @@ | |||
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * NOTE: Currently this driver only supports the bare minimum for read | ||
14 | * and write the RTC and alarms. The extra features provided by this chip | ||
15 | * (trickle charger, eeprom, T° compensation) are unavailable. | ||
16 | */ | 13 | */ |
17 | 14 | ||
18 | #include <linux/module.h> | 15 | #include <linux/module.h> |
@@ -528,6 +525,107 @@ static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
528 | return rv3029_i2c_set_time(to_i2c_client(dev), tm); | 525 | return rv3029_i2c_set_time(to_i2c_client(dev), tm); |
529 | } | 526 | } |
530 | 527 | ||
528 | static const struct rv3029_trickle_tab_elem { | ||
529 | u32 r; /* resistance in ohms */ | ||
530 | u8 conf; /* trickle config bits */ | ||
531 | } rv3029_trickle_tab[] = { | ||
532 | { | ||
533 | .r = 1076, | ||
534 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | | ||
535 | RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, | ||
536 | }, { | ||
537 | .r = 1091, | ||
538 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | | ||
539 | RV3029_TRICKLE_20K, | ||
540 | }, { | ||
541 | .r = 1137, | ||
542 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | | ||
543 | RV3029_TRICKLE_80K, | ||
544 | }, { | ||
545 | .r = 1154, | ||
546 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K, | ||
547 | }, { | ||
548 | .r = 1371, | ||
549 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K | | ||
550 | RV3029_TRICKLE_80K, | ||
551 | }, { | ||
552 | .r = 1395, | ||
553 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K, | ||
554 | }, { | ||
555 | .r = 1472, | ||
556 | .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K, | ||
557 | }, { | ||
558 | .r = 1500, | ||
559 | .conf = RV3029_TRICKLE_1K, | ||
560 | }, { | ||
561 | .r = 3810, | ||
562 | .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K | | ||
563 | RV3029_TRICKLE_80K, | ||
564 | }, { | ||
565 | .r = 4000, | ||
566 | .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K, | ||
567 | }, { | ||
568 | .r = 4706, | ||
569 | .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K, | ||
570 | }, { | ||
571 | .r = 5000, | ||
572 | .conf = RV3029_TRICKLE_5K, | ||
573 | }, { | ||
574 | .r = 16000, | ||
575 | .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, | ||
576 | }, { | ||
577 | .r = 20000, | ||
578 | .conf = RV3029_TRICKLE_20K, | ||
579 | }, { | ||
580 | .r = 80000, | ||
581 | .conf = RV3029_TRICKLE_80K, | ||
582 | }, | ||
583 | }; | ||
584 | |||
585 | static void rv3029_trickle_config(struct i2c_client *client) | ||
586 | { | ||
587 | struct device_node *of_node = client->dev.of_node; | ||
588 | const struct rv3029_trickle_tab_elem *elem; | ||
589 | int i, err; | ||
590 | u32 ohms; | ||
591 | u8 eectrl; | ||
592 | |||
593 | if (!of_node) | ||
594 | return; | ||
595 | |||
596 | /* Configure the trickle charger. */ | ||
597 | err = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL, | ||
598 | &eectrl, 1); | ||
599 | if (err < 0) { | ||
600 | dev_err(&client->dev, | ||
601 | "Failed to read trickle charger config\n"); | ||
602 | return; | ||
603 | } | ||
604 | err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms); | ||
605 | if (err) { | ||
606 | /* Disable trickle charger. */ | ||
607 | eectrl &= ~RV3029_TRICKLE_MASK; | ||
608 | } else { | ||
609 | /* Enable trickle charger. */ | ||
610 | for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) { | ||
611 | elem = &rv3029_trickle_tab[i]; | ||
612 | if (elem->r >= ohms) | ||
613 | break; | ||
614 | } | ||
615 | eectrl &= ~RV3029_TRICKLE_MASK; | ||
616 | eectrl |= elem->conf; | ||
617 | dev_info(&client->dev, | ||
618 | "Trickle charger enabled at %d ohms resistance.\n", | ||
619 | elem->r); | ||
620 | } | ||
621 | err = rv3029_eeprom_write(client, RV3029_CONTROL_E2P_EECTRL, | ||
622 | &eectrl, 1); | ||
623 | if (err < 0) { | ||
624 | dev_err(&client->dev, | ||
625 | "Failed to write trickle charger config\n"); | ||
626 | } | ||
627 | } | ||
628 | |||
531 | static const struct rtc_class_ops rv3029_rtc_ops = { | 629 | static const struct rtc_class_ops rv3029_rtc_ops = { |
532 | .read_time = rv3029_rtc_read_time, | 630 | .read_time = rv3029_rtc_read_time, |
533 | .set_time = rv3029_rtc_set_time, | 631 | .set_time = rv3029_rtc_set_time, |
@@ -558,6 +656,8 @@ static int rv3029_probe(struct i2c_client *client, | |||
558 | return rc; | 656 | return rc; |
559 | } | 657 | } |
560 | 658 | ||
659 | rv3029_trickle_config(client); | ||
660 | |||
561 | rtc = devm_rtc_device_register(&client->dev, client->name, | 661 | rtc = devm_rtc_device_register(&client->dev, client->name, |
562 | &rv3029_rtc_ops, THIS_MODULE); | 662 | &rv3029_rtc_ops, THIS_MODULE); |
563 | 663 | ||