.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Universal power supply monitor class |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * Copyright © 2003 Ian Molton <spyro@f2s.com> |
---|
7 | 8 | * |
---|
8 | 9 | * Modified: 2004, Oct Szabolcs Gyurko |
---|
9 | | - * |
---|
10 | | - * You may use this code as per GPL version 2 |
---|
11 | 10 | */ |
---|
12 | 11 | |
---|
13 | 12 | #include <linux/module.h> |
---|
.. | .. |
---|
32 | 31 | EXPORT_SYMBOL_GPL(power_supply_notifier); |
---|
33 | 32 | |
---|
34 | 33 | static struct device_type power_supply_dev_type; |
---|
| 34 | + |
---|
| 35 | +struct match_device_node_array_param { |
---|
| 36 | + struct device_node *parent_of_node; |
---|
| 37 | + struct power_supply **psy; |
---|
| 38 | + ssize_t psy_size; |
---|
| 39 | + ssize_t psy_count; |
---|
| 40 | +}; |
---|
35 | 41 | |
---|
36 | 42 | #define POWER_SUPPLY_DEFERRED_REGISTER_TIME msecs_to_jiffies(10) |
---|
37 | 43 | |
---|
.. | .. |
---|
126 | 132 | } |
---|
127 | 133 | EXPORT_SYMBOL_GPL(power_supply_changed); |
---|
128 | 134 | |
---|
| 135 | +static int psy_register_cooler(struct power_supply *psy); |
---|
129 | 136 | /* |
---|
130 | 137 | * Notify that power supply was registered after parent finished the probing. |
---|
131 | 138 | * |
---|
.. | .. |
---|
133 | 140 | * calling power_supply_changed() directly from power_supply_register() |
---|
134 | 141 | * would lead to execution of get_property() function provided by the driver |
---|
135 | 142 | * too early - before the probe ends. |
---|
| 143 | + * Also, registering cooling device from the probe will execute the |
---|
| 144 | + * get_property() function. So register the cooling device after the probe. |
---|
136 | 145 | * |
---|
137 | 146 | * Avoid that by waiting on parent's mutex. |
---|
138 | 147 | */ |
---|
.. | .. |
---|
150 | 159 | } |
---|
151 | 160 | |
---|
152 | 161 | power_supply_changed(psy); |
---|
| 162 | + psy_register_cooler(psy); |
---|
153 | 163 | |
---|
154 | 164 | if (psy->dev.parent) |
---|
155 | 165 | mutex_unlock(&psy->dev.parent->mutex); |
---|
156 | 166 | } |
---|
157 | 167 | |
---|
158 | 168 | #ifdef CONFIG_OF |
---|
159 | | -#include <linux/of.h> |
---|
160 | | - |
---|
161 | 169 | static int __power_supply_populate_supplied_from(struct device *dev, |
---|
162 | 170 | void *data) |
---|
163 | 171 | { |
---|
.. | .. |
---|
525 | 533 | } |
---|
526 | 534 | EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); |
---|
527 | 535 | |
---|
| 536 | +static int power_supply_match_device_node_array(struct device *dev, |
---|
| 537 | + void *data) |
---|
| 538 | +{ |
---|
| 539 | + struct match_device_node_array_param *param = |
---|
| 540 | + (struct match_device_node_array_param *)data; |
---|
| 541 | + struct power_supply **psy = param->psy; |
---|
| 542 | + ssize_t size = param->psy_size; |
---|
| 543 | + ssize_t *count = ¶m->psy_count; |
---|
| 544 | + |
---|
| 545 | + if (!dev->parent || dev->parent->of_node != param->parent_of_node) |
---|
| 546 | + return 0; |
---|
| 547 | + |
---|
| 548 | + if (*count >= size) |
---|
| 549 | + return -EOVERFLOW; |
---|
| 550 | + |
---|
| 551 | + psy[*count] = dev_get_drvdata(dev); |
---|
| 552 | + atomic_inc(&psy[*count]->use_cnt); |
---|
| 553 | + (*count)++; |
---|
| 554 | + |
---|
| 555 | + return 0; |
---|
| 556 | +} |
---|
| 557 | + |
---|
| 558 | +/** |
---|
| 559 | + * power_supply_get_by_phandle_array() - Similar to |
---|
| 560 | + * power_supply_get_by_phandle but returns an array of power supply |
---|
| 561 | + * objects which are associated with the phandle. |
---|
| 562 | + * @np: Pointer to device node holding phandle property. |
---|
| 563 | + * @property: Name of property holding a power supply name. |
---|
| 564 | + * @psy: Array of power_supply pointers provided by the client which is |
---|
| 565 | + * filled by power_supply_get_by_phandle_array. |
---|
| 566 | + * @size: size of power_supply pointer array. |
---|
| 567 | + * |
---|
| 568 | + * If power supply was found, it increases reference count for the |
---|
| 569 | + * internal power supply's device. The user should power_supply_put() |
---|
| 570 | + * after usage. |
---|
| 571 | + * |
---|
| 572 | + * Return: On success returns the number of power supply objects filled |
---|
| 573 | + * in the @psy array. |
---|
| 574 | + * -EOVERFLOW when size of @psy array is not suffice. |
---|
| 575 | + * -EINVAL when @psy is NULL or @size is 0. |
---|
| 576 | + * -ENODEV when matching device_node is not found. |
---|
| 577 | + */ |
---|
| 578 | +int power_supply_get_by_phandle_array(struct device_node *np, |
---|
| 579 | + const char *property, |
---|
| 580 | + struct power_supply **psy, |
---|
| 581 | + ssize_t size) |
---|
| 582 | +{ |
---|
| 583 | + struct device_node *power_supply_np; |
---|
| 584 | + int ret; |
---|
| 585 | + struct match_device_node_array_param param; |
---|
| 586 | + |
---|
| 587 | + if (!psy || !size) |
---|
| 588 | + return -EINVAL; |
---|
| 589 | + |
---|
| 590 | + power_supply_np = of_parse_phandle(np, property, 0); |
---|
| 591 | + if (!power_supply_np) |
---|
| 592 | + return -ENODEV; |
---|
| 593 | + |
---|
| 594 | + param.parent_of_node = power_supply_np; |
---|
| 595 | + param.psy = psy; |
---|
| 596 | + param.psy_size = size; |
---|
| 597 | + param.psy_count = 0; |
---|
| 598 | + ret = class_for_each_device(power_supply_class, NULL, ¶m, |
---|
| 599 | + power_supply_match_device_node_array); |
---|
| 600 | + |
---|
| 601 | + of_node_put(power_supply_np); |
---|
| 602 | + |
---|
| 603 | + return param.psy_count; |
---|
| 604 | +} |
---|
| 605 | +EXPORT_SYMBOL_GPL(power_supply_get_by_phandle_array); |
---|
| 606 | + |
---|
528 | 607 | static void devm_power_supply_put(struct device *dev, void *res) |
---|
529 | 608 | { |
---|
530 | 609 | struct power_supply **psy = res; |
---|
.. | .. |
---|
568 | 647 | int power_supply_get_battery_info(struct power_supply *psy, |
---|
569 | 648 | struct power_supply_battery_info *info) |
---|
570 | 649 | { |
---|
| 650 | + struct power_supply_resistance_temp_table *resist_table; |
---|
571 | 651 | struct device_node *battery_np; |
---|
572 | 652 | const char *value; |
---|
573 | | - int err; |
---|
| 653 | + int err, len, index; |
---|
| 654 | + const __be32 *list; |
---|
574 | 655 | |
---|
575 | 656 | info->energy_full_design_uwh = -EINVAL; |
---|
576 | 657 | info->charge_full_design_uah = -EINVAL; |
---|
577 | 658 | info->voltage_min_design_uv = -EINVAL; |
---|
| 659 | + info->voltage_max_design_uv = -EINVAL; |
---|
578 | 660 | info->precharge_current_ua = -EINVAL; |
---|
579 | 661 | info->charge_term_current_ua = -EINVAL; |
---|
580 | 662 | info->constant_charge_current_max_ua = -EINVAL; |
---|
581 | 663 | info->constant_charge_voltage_max_uv = -EINVAL; |
---|
| 664 | + info->temp_ambient_alert_min = INT_MIN; |
---|
| 665 | + info->temp_ambient_alert_max = INT_MAX; |
---|
| 666 | + info->temp_alert_min = INT_MIN; |
---|
| 667 | + info->temp_alert_max = INT_MAX; |
---|
| 668 | + info->temp_min = INT_MIN; |
---|
| 669 | + info->temp_max = INT_MAX; |
---|
| 670 | + info->factory_internal_resistance_uohm = -EINVAL; |
---|
| 671 | + info->resist_table = NULL; |
---|
| 672 | + |
---|
| 673 | + for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) { |
---|
| 674 | + info->ocv_table[index] = NULL; |
---|
| 675 | + info->ocv_temp[index] = -EINVAL; |
---|
| 676 | + info->ocv_table_size[index] = -EINVAL; |
---|
| 677 | + } |
---|
582 | 678 | |
---|
583 | 679 | if (!psy->of_node) { |
---|
584 | 680 | dev_warn(&psy->dev, "%s currently only supports devicetree\n", |
---|
.. | .. |
---|
592 | 688 | |
---|
593 | 689 | err = of_property_read_string(battery_np, "compatible", &value); |
---|
594 | 690 | if (err) |
---|
595 | | - return err; |
---|
| 691 | + goto out_put_node; |
---|
596 | 692 | |
---|
597 | | - if (strcmp("simple-battery", value)) |
---|
598 | | - return -ENODEV; |
---|
| 693 | + if (strcmp("simple-battery", value)) { |
---|
| 694 | + err = -ENODEV; |
---|
| 695 | + goto out_put_node; |
---|
| 696 | + } |
---|
599 | 697 | |
---|
600 | 698 | /* The property and field names below must correspond to elements |
---|
601 | 699 | * in enum power_supply_property. For reasoning, see |
---|
602 | | - * Documentation/power/power_supply_class.txt. |
---|
| 700 | + * Documentation/power/power_supply_class.rst. |
---|
603 | 701 | */ |
---|
604 | 702 | |
---|
605 | 703 | of_property_read_u32(battery_np, "energy-full-design-microwatt-hours", |
---|
.. | .. |
---|
608 | 706 | &info->charge_full_design_uah); |
---|
609 | 707 | of_property_read_u32(battery_np, "voltage-min-design-microvolt", |
---|
610 | 708 | &info->voltage_min_design_uv); |
---|
| 709 | + of_property_read_u32(battery_np, "voltage-max-design-microvolt", |
---|
| 710 | + &info->voltage_max_design_uv); |
---|
| 711 | + of_property_read_u32(battery_np, "trickle-charge-current-microamp", |
---|
| 712 | + &info->tricklecharge_current_ua); |
---|
611 | 713 | of_property_read_u32(battery_np, "precharge-current-microamp", |
---|
612 | 714 | &info->precharge_current_ua); |
---|
| 715 | + of_property_read_u32(battery_np, "precharge-upper-limit-microvolt", |
---|
| 716 | + &info->precharge_voltage_max_uv); |
---|
613 | 717 | of_property_read_u32(battery_np, "charge-term-current-microamp", |
---|
614 | 718 | &info->charge_term_current_ua); |
---|
615 | | - of_property_read_u32(battery_np, "constant_charge_current_max_microamp", |
---|
| 719 | + of_property_read_u32(battery_np, "re-charge-voltage-microvolt", |
---|
| 720 | + &info->charge_restart_voltage_uv); |
---|
| 721 | + of_property_read_u32(battery_np, "over-voltage-threshold-microvolt", |
---|
| 722 | + &info->overvoltage_limit_uv); |
---|
| 723 | + of_property_read_u32(battery_np, "constant-charge-current-max-microamp", |
---|
616 | 724 | &info->constant_charge_current_max_ua); |
---|
617 | | - of_property_read_u32(battery_np, "constant_charge_voltage_max_microvolt", |
---|
| 725 | + of_property_read_u32(battery_np, "constant-charge-voltage-max-microvolt", |
---|
618 | 726 | &info->constant_charge_voltage_max_uv); |
---|
| 727 | + of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms", |
---|
| 728 | + &info->factory_internal_resistance_uohm); |
---|
619 | 729 | |
---|
620 | | - return 0; |
---|
| 730 | + of_property_read_u32_index(battery_np, "ambient-celsius", |
---|
| 731 | + 0, &info->temp_ambient_alert_min); |
---|
| 732 | + of_property_read_u32_index(battery_np, "ambient-celsius", |
---|
| 733 | + 1, &info->temp_ambient_alert_max); |
---|
| 734 | + of_property_read_u32_index(battery_np, "alert-celsius", |
---|
| 735 | + 0, &info->temp_alert_min); |
---|
| 736 | + of_property_read_u32_index(battery_np, "alert-celsius", |
---|
| 737 | + 1, &info->temp_alert_max); |
---|
| 738 | + of_property_read_u32_index(battery_np, "operating-range-celsius", |
---|
| 739 | + 0, &info->temp_min); |
---|
| 740 | + of_property_read_u32_index(battery_np, "operating-range-celsius", |
---|
| 741 | + 1, &info->temp_max); |
---|
| 742 | + |
---|
| 743 | + len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius"); |
---|
| 744 | + if (len < 0 && len != -EINVAL) { |
---|
| 745 | + err = len; |
---|
| 746 | + goto out_put_node; |
---|
| 747 | + } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) { |
---|
| 748 | + dev_err(&psy->dev, "Too many temperature values\n"); |
---|
| 749 | + err = -EINVAL; |
---|
| 750 | + goto out_put_node; |
---|
| 751 | + } else if (len > 0) { |
---|
| 752 | + of_property_read_u32_array(battery_np, "ocv-capacity-celsius", |
---|
| 753 | + info->ocv_temp, len); |
---|
| 754 | + } |
---|
| 755 | + |
---|
| 756 | + for (index = 0; index < len; index++) { |
---|
| 757 | + struct power_supply_battery_ocv_table *table; |
---|
| 758 | + char *propname; |
---|
| 759 | + int i, tab_len, size; |
---|
| 760 | + |
---|
| 761 | + propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", index); |
---|
| 762 | + list = of_get_property(battery_np, propname, &size); |
---|
| 763 | + if (!list || !size) { |
---|
| 764 | + dev_err(&psy->dev, "failed to get %s\n", propname); |
---|
| 765 | + kfree(propname); |
---|
| 766 | + power_supply_put_battery_info(psy, info); |
---|
| 767 | + err = -EINVAL; |
---|
| 768 | + goto out_put_node; |
---|
| 769 | + } |
---|
| 770 | + |
---|
| 771 | + kfree(propname); |
---|
| 772 | + tab_len = size / (2 * sizeof(__be32)); |
---|
| 773 | + info->ocv_table_size[index] = tab_len; |
---|
| 774 | + |
---|
| 775 | + table = info->ocv_table[index] = |
---|
| 776 | + devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL); |
---|
| 777 | + if (!info->ocv_table[index]) { |
---|
| 778 | + power_supply_put_battery_info(psy, info); |
---|
| 779 | + err = -ENOMEM; |
---|
| 780 | + goto out_put_node; |
---|
| 781 | + } |
---|
| 782 | + |
---|
| 783 | + for (i = 0; i < tab_len; i++) { |
---|
| 784 | + table[i].ocv = be32_to_cpu(*list); |
---|
| 785 | + list++; |
---|
| 786 | + table[i].capacity = be32_to_cpu(*list); |
---|
| 787 | + list++; |
---|
| 788 | + } |
---|
| 789 | + } |
---|
| 790 | + |
---|
| 791 | + list = of_get_property(battery_np, "resistance-temp-table", &len); |
---|
| 792 | + if (!list || !len) |
---|
| 793 | + goto out_put_node; |
---|
| 794 | + |
---|
| 795 | + info->resist_table_size = len / (2 * sizeof(__be32)); |
---|
| 796 | + resist_table = info->resist_table = devm_kcalloc(&psy->dev, |
---|
| 797 | + info->resist_table_size, |
---|
| 798 | + sizeof(*resist_table), |
---|
| 799 | + GFP_KERNEL); |
---|
| 800 | + if (!info->resist_table) { |
---|
| 801 | + power_supply_put_battery_info(psy, info); |
---|
| 802 | + err = -ENOMEM; |
---|
| 803 | + goto out_put_node; |
---|
| 804 | + } |
---|
| 805 | + |
---|
| 806 | + for (index = 0; index < info->resist_table_size; index++) { |
---|
| 807 | + resist_table[index].temp = be32_to_cpu(*list++); |
---|
| 808 | + resist_table[index].resistance = be32_to_cpu(*list++); |
---|
| 809 | + } |
---|
| 810 | + |
---|
| 811 | +out_put_node: |
---|
| 812 | + of_node_put(battery_np); |
---|
| 813 | + return err; |
---|
621 | 814 | } |
---|
622 | 815 | EXPORT_SYMBOL_GPL(power_supply_get_battery_info); |
---|
| 816 | + |
---|
| 817 | +void power_supply_put_battery_info(struct power_supply *psy, |
---|
| 818 | + struct power_supply_battery_info *info) |
---|
| 819 | +{ |
---|
| 820 | + int i; |
---|
| 821 | + |
---|
| 822 | + for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) { |
---|
| 823 | + if (info->ocv_table[i]) |
---|
| 824 | + devm_kfree(&psy->dev, info->ocv_table[i]); |
---|
| 825 | + } |
---|
| 826 | + |
---|
| 827 | + if (info->resist_table) |
---|
| 828 | + devm_kfree(&psy->dev, info->resist_table); |
---|
| 829 | +} |
---|
| 830 | +EXPORT_SYMBOL_GPL(power_supply_put_battery_info); |
---|
| 831 | + |
---|
| 832 | +/** |
---|
| 833 | + * power_supply_temp2resist_simple() - find the battery internal resistance |
---|
| 834 | + * percent |
---|
| 835 | + * @table: Pointer to battery resistance temperature table |
---|
| 836 | + * @table_len: The table length |
---|
| 837 | + * @temp: Current temperature |
---|
| 838 | + * |
---|
| 839 | + * This helper function is used to look up battery internal resistance percent |
---|
| 840 | + * according to current temperature value from the resistance temperature table, |
---|
| 841 | + * and the table must be ordered descending. Then the actual battery internal |
---|
| 842 | + * resistance = the ideal battery internal resistance * percent / 100. |
---|
| 843 | + * |
---|
| 844 | + * Return: the battery internal resistance percent |
---|
| 845 | + */ |
---|
| 846 | +int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table, |
---|
| 847 | + int table_len, int temp) |
---|
| 848 | +{ |
---|
| 849 | + int i, resist; |
---|
| 850 | + |
---|
| 851 | + for (i = 0; i < table_len; i++) |
---|
| 852 | + if (temp > table[i].temp) |
---|
| 853 | + break; |
---|
| 854 | + |
---|
| 855 | + if (i > 0 && i < table_len) { |
---|
| 856 | + int tmp; |
---|
| 857 | + |
---|
| 858 | + tmp = (table[i - 1].resistance - table[i].resistance) * |
---|
| 859 | + (temp - table[i].temp); |
---|
| 860 | + tmp /= table[i - 1].temp - table[i].temp; |
---|
| 861 | + resist = tmp + table[i].resistance; |
---|
| 862 | + } else if (i == 0) { |
---|
| 863 | + resist = table[0].resistance; |
---|
| 864 | + } else { |
---|
| 865 | + resist = table[table_len - 1].resistance; |
---|
| 866 | + } |
---|
| 867 | + |
---|
| 868 | + return resist; |
---|
| 869 | +} |
---|
| 870 | +EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); |
---|
| 871 | + |
---|
| 872 | +/** |
---|
| 873 | + * power_supply_ocv2cap_simple() - find the battery capacity |
---|
| 874 | + * @table: Pointer to battery OCV lookup table |
---|
| 875 | + * @table_len: OCV table length |
---|
| 876 | + * @ocv: Current OCV value |
---|
| 877 | + * |
---|
| 878 | + * This helper function is used to look up battery capacity according to |
---|
| 879 | + * current OCV value from one OCV table, and the OCV table must be ordered |
---|
| 880 | + * descending. |
---|
| 881 | + * |
---|
| 882 | + * Return: the battery capacity. |
---|
| 883 | + */ |
---|
| 884 | +int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, |
---|
| 885 | + int table_len, int ocv) |
---|
| 886 | +{ |
---|
| 887 | + int i, cap, tmp; |
---|
| 888 | + |
---|
| 889 | + for (i = 0; i < table_len; i++) |
---|
| 890 | + if (ocv > table[i].ocv) |
---|
| 891 | + break; |
---|
| 892 | + |
---|
| 893 | + if (i > 0 && i < table_len) { |
---|
| 894 | + tmp = (table[i - 1].capacity - table[i].capacity) * |
---|
| 895 | + (ocv - table[i].ocv); |
---|
| 896 | + tmp /= table[i - 1].ocv - table[i].ocv; |
---|
| 897 | + cap = tmp + table[i].capacity; |
---|
| 898 | + } else if (i == 0) { |
---|
| 899 | + cap = table[0].capacity; |
---|
| 900 | + } else { |
---|
| 901 | + cap = table[table_len - 1].capacity; |
---|
| 902 | + } |
---|
| 903 | + |
---|
| 904 | + return cap; |
---|
| 905 | +} |
---|
| 906 | +EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple); |
---|
| 907 | + |
---|
| 908 | +struct power_supply_battery_ocv_table * |
---|
| 909 | +power_supply_find_ocv2cap_table(struct power_supply_battery_info *info, |
---|
| 910 | + int temp, int *table_len) |
---|
| 911 | +{ |
---|
| 912 | + int best_temp_diff = INT_MAX, temp_diff; |
---|
| 913 | + u8 i, best_index = 0; |
---|
| 914 | + |
---|
| 915 | + if (!info->ocv_table[0]) |
---|
| 916 | + return NULL; |
---|
| 917 | + |
---|
| 918 | + for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) { |
---|
| 919 | + /* Out of capacity tables */ |
---|
| 920 | + if (!info->ocv_table[i]) |
---|
| 921 | + break; |
---|
| 922 | + |
---|
| 923 | + temp_diff = abs(info->ocv_temp[i] - temp); |
---|
| 924 | + |
---|
| 925 | + if (temp_diff < best_temp_diff) { |
---|
| 926 | + best_temp_diff = temp_diff; |
---|
| 927 | + best_index = i; |
---|
| 928 | + } |
---|
| 929 | + } |
---|
| 930 | + |
---|
| 931 | + *table_len = info->ocv_table_size[best_index]; |
---|
| 932 | + return info->ocv_table[best_index]; |
---|
| 933 | +} |
---|
| 934 | +EXPORT_SYMBOL_GPL(power_supply_find_ocv2cap_table); |
---|
| 935 | + |
---|
| 936 | +int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info, |
---|
| 937 | + int ocv, int temp) |
---|
| 938 | +{ |
---|
| 939 | + struct power_supply_battery_ocv_table *table; |
---|
| 940 | + int table_len; |
---|
| 941 | + |
---|
| 942 | + table = power_supply_find_ocv2cap_table(info, temp, &table_len); |
---|
| 943 | + if (!table) |
---|
| 944 | + return -EINVAL; |
---|
| 945 | + |
---|
| 946 | + return power_supply_ocv2cap_simple(table, table_len, ocv); |
---|
| 947 | +} |
---|
| 948 | +EXPORT_SYMBOL_GPL(power_supply_batinfo_ocv2cap); |
---|
623 | 949 | |
---|
624 | 950 | int power_supply_get_property(struct power_supply *psy, |
---|
625 | 951 | enum power_supply_property psp, |
---|
.. | .. |
---|
718 | 1044 | |
---|
719 | 1045 | static int psy_register_thermal(struct power_supply *psy) |
---|
720 | 1046 | { |
---|
721 | | - int i; |
---|
| 1047 | + int i, ret; |
---|
722 | 1048 | |
---|
723 | 1049 | if (psy->desc->no_thermal) |
---|
724 | 1050 | return 0; |
---|
.. | .. |
---|
728 | 1054 | if (psy->desc->properties[i] == POWER_SUPPLY_PROP_TEMP) { |
---|
729 | 1055 | psy->tzd = thermal_zone_device_register(psy->desc->name, |
---|
730 | 1056 | 0, 0, psy, &psy_tzd_ops, NULL, 0, 0); |
---|
731 | | - return PTR_ERR_OR_ZERO(psy->tzd); |
---|
| 1057 | + if (IS_ERR(psy->tzd)) |
---|
| 1058 | + return PTR_ERR(psy->tzd); |
---|
| 1059 | + ret = thermal_zone_device_enable(psy->tzd); |
---|
| 1060 | + if (ret) |
---|
| 1061 | + thermal_zone_device_unregister(psy->tzd); |
---|
| 1062 | + return ret; |
---|
732 | 1063 | } |
---|
733 | 1064 | } |
---|
734 | 1065 | return 0; |
---|
.. | .. |
---|
760 | 1091 | return ret; |
---|
761 | 1092 | } |
---|
762 | 1093 | |
---|
763 | | -static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd, |
---|
| 1094 | +static int ps_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd, |
---|
764 | 1095 | unsigned long *state) |
---|
765 | 1096 | { |
---|
766 | 1097 | struct power_supply *psy; |
---|
.. | .. |
---|
795 | 1126 | |
---|
796 | 1127 | static const struct thermal_cooling_device_ops psy_tcd_ops = { |
---|
797 | 1128 | .get_max_state = ps_get_max_charge_cntl_limit, |
---|
798 | | - .get_cur_state = ps_get_cur_chrage_cntl_limit, |
---|
| 1129 | + .get_cur_state = ps_get_cur_charge_cntl_limit, |
---|
799 | 1130 | .set_cur_state = ps_set_cur_charge_cntl_limit, |
---|
800 | 1131 | }; |
---|
801 | 1132 | |
---|
.. | .. |
---|
807 | 1138 | for (i = 0; i < psy->desc->num_properties; i++) { |
---|
808 | 1139 | if (psy->desc->properties[i] == |
---|
809 | 1140 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) { |
---|
810 | | - psy->tcd = thermal_cooling_device_register( |
---|
811 | | - (char *)psy->desc->name, |
---|
812 | | - psy, &psy_tcd_ops); |
---|
| 1141 | + if (psy->dev.parent) |
---|
| 1142 | + psy->tcd = thermal_of_cooling_device_register( |
---|
| 1143 | + dev_of_node(psy->dev.parent), |
---|
| 1144 | + (char *)psy->desc->name, |
---|
| 1145 | + psy, &psy_tcd_ops); |
---|
| 1146 | + else |
---|
| 1147 | + psy->tcd = thermal_cooling_device_register( |
---|
| 1148 | + (char *)psy->desc->name, |
---|
| 1149 | + psy, &psy_tcd_ops); |
---|
813 | 1150 | return PTR_ERR_OR_ZERO(psy->tcd); |
---|
814 | 1151 | } |
---|
815 | 1152 | } |
---|
.. | .. |
---|
880 | 1217 | dev_set_drvdata(dev, psy); |
---|
881 | 1218 | psy->desc = desc; |
---|
882 | 1219 | if (cfg) { |
---|
| 1220 | + dev->groups = cfg->attr_grp; |
---|
883 | 1221 | psy->drv_data = cfg->drv_data; |
---|
884 | 1222 | psy->of_node = |
---|
885 | 1223 | cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node; |
---|
.. | .. |
---|
914 | 1252 | if (rc) |
---|
915 | 1253 | goto register_thermal_failed; |
---|
916 | 1254 | |
---|
917 | | - rc = psy_register_cooler(psy); |
---|
918 | | - if (rc) |
---|
919 | | - goto register_cooler_failed; |
---|
920 | | - |
---|
921 | 1255 | rc = power_supply_create_triggers(psy); |
---|
922 | 1256 | if (rc) |
---|
923 | 1257 | goto create_triggers_failed; |
---|
| 1258 | + |
---|
| 1259 | + rc = power_supply_add_hwmon_sysfs(psy); |
---|
| 1260 | + if (rc) |
---|
| 1261 | + goto add_hwmon_sysfs_failed; |
---|
924 | 1262 | |
---|
925 | 1263 | /* |
---|
926 | 1264 | * Update use_cnt after any uevents (most notably from device_add()). |
---|
.. | .. |
---|
940 | 1278 | |
---|
941 | 1279 | return psy; |
---|
942 | 1280 | |
---|
| 1281 | +add_hwmon_sysfs_failed: |
---|
| 1282 | + power_supply_remove_triggers(psy); |
---|
943 | 1283 | create_triggers_failed: |
---|
944 | | - psy_unregister_cooler(psy); |
---|
945 | | -register_cooler_failed: |
---|
946 | 1284 | psy_unregister_thermal(psy); |
---|
947 | 1285 | register_thermal_failed: |
---|
948 | 1286 | device_del(dev); |
---|
.. | .. |
---|
1092 | 1430 | cancel_work_sync(&psy->changed_work); |
---|
1093 | 1431 | cancel_delayed_work_sync(&psy->deferred_register_work); |
---|
1094 | 1432 | sysfs_remove_link(&psy->dev.kobj, "powers"); |
---|
| 1433 | + power_supply_remove_hwmon_sysfs(psy); |
---|
1095 | 1434 | power_supply_remove_triggers(psy); |
---|
1096 | 1435 | psy_unregister_cooler(psy); |
---|
1097 | 1436 | psy_unregister_thermal(psy); |
---|