Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

charger-manager: Support deivce tree in charger manager driver

Charger-manager can parse charger_desc data from devicetree which is used
to register charger manager.

Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>

authored by

Jonghwa Lee and committed by
Anton Vorontsov
856ee611 5c49a625

+222 -9
+81
Documentation/devicetree/bindings/power_supply/charger-manager.txt
··· 1 + charger-manager bindings 2 + ~~~~~~~~~~~~~~~~~~~~~~~~ 3 + 4 + Required properties : 5 + - compatible : "charger-manager" 6 + - <>-supply : for regulator consumer 7 + - cm-num-chargers : number of chargers 8 + - cm-chargers : name of chargers 9 + - cm-fuel-gauge : name of battery fuel gauge 10 + - subnode <regulator> : 11 + - cm-regulator-name : name of charger regulator 12 + - subnode <cable> : 13 + - cm-cable-name : name of charger cable 14 + - cm-cable-extcon : name of extcon dev 15 + (optional) - cm-cable-min : minimum current of cable 16 + (optional) - cm-cable-max : maximum current of cable 17 + 18 + Optional properties : 19 + - cm-name : charger manager's name (default : "battery") 20 + - cm-poll-mode : polling mode (enum polling_modes) 21 + - cm-poll-interval : polling interval 22 + - cm-battery-stat : battery status (enum data_source) 23 + - cm-fullbatt-* : data for full battery checking 24 + - cm-thermal-zone : name of external thermometer's thermal zone 25 + - cm-battery-* : threshold battery temperature for charging 26 + -cold : critical cold temperature of battery for charging 27 + -cold-in-minus : flag that cold temerature is in minus degree 28 + -hot : critical hot temperature of battery for charging 29 + -temp-diff : temperature difference to allow recharging 30 + - cm-dis/charging-max = limits of charging duration 31 + 32 + Example : 33 + charger-manager@0 { 34 + compatible = "charger-manager"; 35 + chg-reg-supply = <&charger_regulator>; 36 + 37 + cm-name = "battery"; 38 + /* Always polling ON : 30s */ 39 + cm-poll-mode = <1>; 40 + cm-poll-interval = <30000>; 41 + 42 + cm-fullbatt-vchkdrop-ms = <30000>; 43 + cm-fullbatt-vchkdrop-volt = <150000>; 44 + cm-fullbatt-soc = <100>; 45 + 46 + cm-battery-stat = <3>; 47 + 48 + cm-num-chargers = <3>; 49 + cm-chargers = "charger0", "charger1", "charger2"; 50 + 51 + cm-fuel-gauge = "fuelgauge0"; 52 + 53 + cm-thermal-zone = "thermal_zone.1" 54 + /* in deci centigrade */ 55 + cm-battery-cold = <50>; 56 + cm-battery-cold-in-minus; 57 + cm-battery-hot = <800>; 58 + cm-battery-temp-diff = <100>; 59 + 60 + /* Allow charging for 5hr */ 61 + cm-charging-max = <18000000>; 62 + /* Allow discharging for 2hr */ 63 + cm-discharging-max = <7200000>; 64 + 65 + regulator@0 { 66 + cm-regulator-name = "chg-reg"; 67 + cable@0 { 68 + cm-cable-name = "USB"; 69 + cm-cable-extcon = "extcon-dev.0"; 70 + cm-cable-min = <475000>; 71 + cm-cable-max = <500000>; 72 + }; 73 + cable@1 { 74 + cm-cable-name = "TA"; 75 + cm-cable-extcon = "extcon-dev.0"; 76 + cm-cable-min = <650000>; 77 + cm-cable-max = <675000>; 78 + }; 79 + }; 80 + 81 + };
+135 -3
drivers/power/charger-manager.c
··· 25 25 #include <linux/power/charger-manager.h> 26 26 #include <linux/regulator/consumer.h> 27 27 #include <linux/sysfs.h> 28 + #include <linux/of.h> 28 29 #include <linux/thermal.h> 29 30 30 31 /* ··· 529 528 duration = curr - cm->charging_start_time; 530 529 531 530 if (duration > desc->charging_max_duration_ms) { 532 - dev_info(cm->dev, "Charging duration exceed %lldms\n", 531 + dev_info(cm->dev, "Charging duration exceed %ums\n", 533 532 desc->charging_max_duration_ms); 534 533 uevent_notify(cm, "Discharging"); 535 534 try_charger_enable(cm, false); ··· 540 539 541 540 if (duration > desc->charging_max_duration_ms && 542 541 is_ext_pwr_online(cm)) { 543 - dev_info(cm->dev, "Discharging duration exceed %lldms\n", 542 + dev_info(cm->dev, "Discharging duration exceed %ums\n", 544 543 desc->discharging_max_duration_ms); 545 544 uevent_notify(cm, "Recharging"); 546 545 try_charger_enable(cm, true); ··· 1529 1528 return ret; 1530 1529 } 1531 1530 1531 + static struct of_device_id charger_manager_match[] = { 1532 + { 1533 + .compatible = "charger-manager", 1534 + }, 1535 + {}, 1536 + }; 1537 + 1538 + struct charger_desc *of_cm_parse_desc(struct device *dev) 1539 + { 1540 + struct charger_desc *desc; 1541 + struct device_node *np = dev->of_node; 1542 + u32 poll_mode = CM_POLL_DISABLE; 1543 + u32 battery_stat = CM_NO_BATTERY; 1544 + int num_chgs = 0; 1545 + 1546 + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); 1547 + if (!desc) 1548 + return ERR_PTR(-ENOMEM); 1549 + 1550 + of_property_read_string(np, "cm-name", &desc->psy_name); 1551 + 1552 + of_property_read_u32(np, "cm-poll-mode", &poll_mode); 1553 + desc->polling_mode = poll_mode; 1554 + 1555 + of_property_read_u32(np, "cm-poll-interval", 1556 + &desc->polling_interval_ms); 1557 + 1558 + of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms", 1559 + &desc->fullbatt_vchkdrop_ms); 1560 + of_property_read_u32(np, "cm-fullbatt-vchkdrop-volt", 1561 + &desc->fullbatt_vchkdrop_uV); 1562 + of_property_read_u32(np, "cm-fullbatt-voltage", &desc->fullbatt_uV); 1563 + of_property_read_u32(np, "cm-fullbatt-soc", &desc->fullbatt_soc); 1564 + of_property_read_u32(np, "cm-fullbatt-capacity", 1565 + &desc->fullbatt_full_capacity); 1566 + 1567 + of_property_read_u32(np, "cm-battery-stat", &battery_stat); 1568 + desc->battery_present = battery_stat; 1569 + 1570 + /* chargers */ 1571 + of_property_read_u32(np, "cm-num-chargers", &num_chgs); 1572 + if (num_chgs) { 1573 + /* Allocate empty bin at the tail of array */ 1574 + desc->psy_charger_stat = devm_kzalloc(dev, sizeof(char *) 1575 + * (num_chgs + 1), GFP_KERNEL); 1576 + if (desc->psy_charger_stat) { 1577 + int i; 1578 + for (i = 0; i < num_chgs; i++) 1579 + of_property_read_string_index(np, "cm-chargers", 1580 + i, &desc->psy_charger_stat[i]); 1581 + } else { 1582 + return ERR_PTR(-ENOMEM); 1583 + } 1584 + } 1585 + 1586 + of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge); 1587 + 1588 + of_property_read_string(np, "cm-thermal-zone", &desc->thermal_zone); 1589 + 1590 + of_property_read_u32(np, "cm-battery-cold", &desc->temp_min); 1591 + if (of_get_property(np, "cm-battery-cold-in-minus", NULL)) 1592 + desc->temp_min *= -1; 1593 + of_property_read_u32(np, "cm-battery-hot", &desc->temp_max); 1594 + of_property_read_u32(np, "cm-battery-temp-diff", &desc->temp_diff); 1595 + 1596 + of_property_read_u32(np, "cm-charging-max", 1597 + &desc->charging_max_duration_ms); 1598 + of_property_read_u32(np, "cm-discharging-max", 1599 + &desc->discharging_max_duration_ms); 1600 + 1601 + /* battery charger regualtors */ 1602 + desc->num_charger_regulators = of_get_child_count(np); 1603 + if (desc->num_charger_regulators) { 1604 + struct charger_regulator *chg_regs; 1605 + struct device_node *child; 1606 + 1607 + chg_regs = devm_kzalloc(dev, sizeof(*chg_regs) 1608 + * desc->num_charger_regulators, 1609 + GFP_KERNEL); 1610 + if (!chg_regs) 1611 + return ERR_PTR(-ENOMEM); 1612 + 1613 + desc->charger_regulators = chg_regs; 1614 + 1615 + for_each_child_of_node(np, child) { 1616 + struct charger_cable *cables; 1617 + struct device_node *_child; 1618 + 1619 + of_property_read_string(child, "cm-regulator-name", 1620 + &chg_regs->regulator_name); 1621 + 1622 + /* charger cables */ 1623 + chg_regs->num_cables = of_get_child_count(child); 1624 + if (chg_regs->num_cables) { 1625 + cables = devm_kzalloc(dev, sizeof(*cables) 1626 + * chg_regs->num_cables, 1627 + GFP_KERNEL); 1628 + if (!cables) 1629 + return ERR_PTR(-ENOMEM); 1630 + 1631 + chg_regs->cables = cables; 1632 + 1633 + for_each_child_of_node(child, _child) { 1634 + of_property_read_string(_child, 1635 + "cm-cable-name", &cables->name); 1636 + of_property_read_string(_child, 1637 + "cm-cable-extcon", 1638 + &cables->extcon_name); 1639 + of_property_read_u32(_child, 1640 + "cm-cable-min", 1641 + &cables->min_uA); 1642 + of_property_read_u32(_child, 1643 + "cm-cable-max", 1644 + &cables->max_uA); 1645 + cables++; 1646 + } 1647 + } 1648 + chg_regs++; 1649 + } 1650 + } 1651 + return desc; 1652 + } 1653 + 1654 + static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev) 1655 + { 1656 + if (pdev->dev.of_node) 1657 + return of_cm_parse_desc(&pdev->dev); 1658 + return (struct charger_desc *)dev_get_platdata(&pdev->dev); 1659 + } 1660 + 1532 1661 static int charger_manager_probe(struct platform_device *pdev) 1533 1662 { 1534 - struct charger_desc *desc = dev_get_platdata(&pdev->dev); 1663 + struct charger_desc *desc = cm_get_drv_data(pdev); 1535 1664 struct charger_manager *cm; 1536 1665 int ret = 0, i = 0; 1537 1666 int j = 0; ··· 2018 1887 .name = "charger-manager", 2019 1888 .owner = THIS_MODULE, 2020 1889 .pm = &charger_manager_pm, 1890 + .of_match_table = charger_manager_match, 2021 1891 }, 2022 1892 .probe = charger_manager_probe, 2023 1893 .remove = charger_manager_remove,
+6 -6
include/linux/power/charger-manager.h
··· 191 191 * max_duration_ms', cm start charging. 192 192 */ 193 193 struct charger_desc { 194 - char *psy_name; 194 + const char *psy_name; 195 195 196 196 enum polling_modes polling_mode; 197 197 unsigned int polling_interval_ms; ··· 204 204 205 205 enum data_source battery_present; 206 206 207 - char **psy_charger_stat; 207 + const char **psy_charger_stat; 208 208 209 209 int num_charger_regulators; 210 210 struct charger_regulator *charger_regulators; 211 211 212 - char *psy_fuel_gauge; 212 + const char *psy_fuel_gauge; 213 213 214 - char *thermal_zone; 214 + const char *thermal_zone; 215 215 216 216 int temp_min; 217 217 int temp_max; ··· 219 219 220 220 bool measure_battery_temp; 221 221 222 - u64 charging_max_duration_ms; 223 - u64 discharging_max_duration_ms; 222 + u32 charging_max_duration_ms; 223 + u32 discharging_max_duration_ms; 224 224 }; 225 225 226 226 #define PSY_NAME_MAX 30