From patchwork Wed Dec 18 02:14:13 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonghwa Lee X-Patchwork-Id: 3367191 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 53FD4C0D4A for ; Wed, 18 Dec 2013 02:14:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3DD6B203AE for ; Wed, 18 Dec 2013 02:14:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5130A203B0 for ; Wed, 18 Dec 2013 02:14:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751128Ab3LRCO0 (ORCPT ); Tue, 17 Dec 2013 21:14:26 -0500 Received: from mailout2.samsung.com ([203.254.224.25]:63372 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751231Ab3LRCOZ (ORCPT ); Tue, 17 Dec 2013 21:14:25 -0500 Received: from epcpsbgr5.samsung.com (u145.gpu120.samsung.co.kr [203.254.230.145]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MXZ00BQ2CW0RWB0@mailout2.samsung.com> for linux-pm@vger.kernel.org; Wed, 18 Dec 2013 11:14:24 +0900 (KST) Received: from epcpsbgm1.samsung.com ( [172.20.52.113]) by epcpsbgr5.samsung.com (EPCPMTA) with SMTP id 3A.8E.06316.00501B25; Wed, 18 Dec 2013 11:14:24 +0900 (KST) X-AuditID: cbfee691-b7fe66d0000018ac-d3-52b105000390 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 66.11.22838.00501B25; Wed, 18 Dec 2013 11:14:24 +0900 (KST) Received: from localhost.localdomain ([10.252.82.199]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MXZ001C1CVS8O70@mmp1.samsung.com>; Wed, 18 Dec 2013 11:14:24 +0900 (KST) From: Jonghwa Lee To: linux-pm@vger.kernel.org Cc: anton@enomsg.org, dwmw2@infradead.org, myungjoo.ham@samsung.com, cw00.choi@samsung.com, Jonghwa Lee Subject: [PATCH 2/2] charger-manager : Support deivce tree in charger manager driver Date: Wed, 18 Dec 2013 11:14:13 +0900 Message-id: <1387332853-5923-3-git-send-email-jonghwa3.lee@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1387332853-5923-1-git-send-email-jonghwa3.lee@samsung.com> References: <1387332853-5923-1-git-send-email-jonghwa3.lee@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrFLMWRmVeSWpSXmKPExsWyRsSkUJeBdWOQwdm9ohYHt2paXP/ynNVi 4srJzBadZ58wW3zuPcJocbtxBZsDm8eE/k+MHptXaHn0bVnF6PF5k1wASxSXTUpqTmZZapG+ XQJXxpSOtSwFqwMrDq27xtbA+N6pi5GTQ0LAROLNtIPMELaYxIV769m6GLk4hASWMkr8nPCd GaboxKHbrBCJRYwSR7raWEESQgJtTBLHF2eB2GwCOhL/991kB7FFBGQkpl7ZD9bALNDCKPHm wB9GkISwQJhEy7ejLCA2i4CqxLmXjWAbeAXcJR4v+QwU5wDapiAxZ5INSJhTwEPi67uD7BC7 3CXaVzaygMyUEOhnl1h3YwMTxBwBiW+TD0H1ykpsOgB1tKTEwRU3WCYwCi9gZFjFKJpakFxQ nJReZKpXnJhbXJqXrpecn7uJERjOp/89m7iD8f4B60OMyUDjJjJLiSbnA+MhryTe0NjMyMLU xNTYyNzSjDRhJXHe9EdJQUIC6YklqdmpqQWpRfFFpTmpxYcYmTg4pRoYe15kKN/kKfqxv9Bz csLiSs+492v/2J3je6RtYfqluvNrU5F+z603ivosa77e704xP/Z7SkbENO0fHrHV9S/3c7tY 8xZxFmXdCD634ILLqz3yPjpVEvUGU+K7u2umM/B+if4f4mf42zBxtrnDRbG0lWfizJ7t27PX sOhH0gQBz49HN/o6ekYrsRRnJBpqMRcVJwIAuj7Q0X0CAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrOIsWRmVeSWpSXmKPExsVy+t9jAV0G1o1BBmt38Vgc3Kppcf3Lc1aL iSsnM1t0nn3CbPG59wijxe3GFWwObB4T+j8xemxeoeXRt2UVo8fnTXIBLFENjDYZqYkpqUUK qXnJ+SmZeem2St7B8c7xpmYGhrqGlhbmSgp5ibmptkouPgG6bpk5QLuVFMoSc0qBQgGJxcVK +naYJoSGuOlawDRG6PqGBMH1GBmggYQ1jBlTOtayFKwOrDi07hpbA+N7py5GTg4JAROJE4du s0LYYhIX7q1n62Lk4hASWMQocaSrDSwhJNDGJHF8cRaIzSagI/F/3012EFtEQEZi6pX9rCAN zAItjBJvDvxhBEkIC4RJtHw7ygJiswioSpx72cgMYvMKuEs8XvIZKM4BtE1BYs4kG5Awp4CH xNd3B9khdrlLtK9sZJnAyLuAkWEVo2hqQXJBcVJ6rqFecWJucWleul5yfu4mRnC0PJPawbiy weIQowAHoxIPL8fs9UFCrIllxZW5hxglOJiVRHjX/d8QJMSbklhZlVqUH19UmpNafIgxGeio icxSosn5wEjOK4k3NDYxM7I0Mje0MDI2J01YSZz3QKt1oJBAemJJanZqakFqEcwWJg5OqQbG nKlS71pyn4akzneo2DK5OtXq7Z38r0oBE2oEWOfZt2VvVUvRmaAzNUZvsrF5866Z6q1zcxjF 52zf2n5BdI+sR/HSB7MbVso/jTj8oHjy32991//t1JeYMtf4U52ke7JYn9YcnaSnaRa11e4f Jp2slC1e6Lwu6mDkqmuNnusTpwp/deL6+naTEktxRqKhFnNRcSIA2ycctNoCAAA= DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Charger-manager can parse charger_desc data from devicetree which is used to register charger manager. Signed-off-by: Jonghwa Lee Signed-off-by: Myungjoo Ham --- .../bindings/power_supply/charger-manager.txt | 81 +++++++++++ drivers/power/charger-manager.c | 144 +++++++++++++++++++- include/linux/power/charger-manager.h | 12 +- 3 files changed, 228 insertions(+), 9 deletions(-) create mode 100644 Documentation/devicetree/bindings/power_supply/charger-manager.txt diff --git a/Documentation/devicetree/bindings/power_supply/charger-manager.txt b/Documentation/devicetree/bindings/power_supply/charger-manager.txt new file mode 100644 index 0000000..2b33750 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/charger-manager.txt @@ -0,0 +1,81 @@ +charger-manager bindings +~~~~~~~~~~~~~~~~~~~~~~~~ + +Required properties : + - compatible : "charger-manager" + - <>-supply : for regulator consumer + - cm-num-chargers : number of chargers + - cm-chargers : name of chargers + - cm-fuel-gauge : name of battery fuel gauge + - subnode : + - cm-regulator-name : name of charger regulator + - subnode : + - cm-cable-name : name of charger cable + - cm-cable-extcon : name of extcon dev +(optional) - cm-cable-min : minimum current of cable +(optional) - cm-cable-max : maximum current of cable + +Optional properties : + - cm-name : charger manager's name (default : "battery") + - cm-poll-mode : polling mode (enum polling_modes) + - cm-poll-interval : polling interval + - cm-battery-stat : battery status (enum data_source) + - cm-fullbatt-* : data for full battery checking + - cm-thermal-zone : name of external thermometer's thermal zone + - cm-battery-* : threshold battery temperature for charging + -cold : critical cold temperature of battery for charging + -cold-in-minus : flag that cold temerature is in minus degree + -hot : critical hot temperature of battery for charging + -temp-diff : temperature difference to allow recharging + - cm-dis/charging-max = limits of charging duration + +Example : + charger-manager@0 { + compatible = "charger-manager"; + chg-reg-supply = <&charger_regulator>; + + cm-name = "battery"; + /* Always polling ON : 30s */ + cm-poll-mode = <1>; + cm-poll-interval = <30000>; + + cm-fullbatt-vchkdrop-ms = <30000>; + cm-fullbatt-vchkdrop-volt = <150000>; + cm-fullbatt-soc = <100>; + + cm-battery-stat = <3>; + + cm-num-chargers = <3>; + cm-chargers = "charger0", "charger1", "charger2"; + + cm-fuel-gauge = "fuelgauge0"; + + cm-thermal-zone = "thermal_zone.1" + /* in deci centigrade */ + cm-battery-cold = <50>; + cm-battery-cold-in-minus; + cm-battery-hot = <800>; + cm-battery-temp-diff = <100>; + + /* Allow charging for 5hr */ + cm-charging-max = <18000000>; + /* Allow discharging for 2hr */ + cm-discharging-max = <7200000>; + + regulator@0 { + cm-regulator-name = "chg-reg"; + cable@0 { + cm-cable-name = "USB"; + cm-cable-extcon = "extcon-dev.0"; + cm-cable-min = <475000>; + cm-cable-max = <500000>; + }; + cable@1 { + cm-cable-name = "TA"; + cm-cable-extcon = "extcon-dev.0"; + cm-cable-min = <650000>; + cm-cable-max = <675000>; + }; + }; + + }; diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 6b68d15..d92e946 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* @@ -528,7 +529,7 @@ static int check_charging_duration(struct charger_manager *cm) duration = curr - cm->charging_start_time; if (duration > desc->charging_max_duration_ms) { - dev_info(cm->dev, "Charging duration exceed %lldms\n", + dev_info(cm->dev, "Charging duration exceed %ums\n", desc->charging_max_duration_ms); uevent_notify(cm, "Discharging"); try_charger_enable(cm, false); @@ -539,7 +540,7 @@ static int check_charging_duration(struct charger_manager *cm) if (duration > desc->charging_max_duration_ms && is_ext_pwr_online(cm)) { - dev_info(cm->dev, "Discharging duration exceed %lldms\n", + dev_info(cm->dev, "Discharging duration exceed %ums\n", desc->discharging_max_duration_ms); uevent_notify(cm, "Recharging"); try_charger_enable(cm, true); @@ -1528,9 +1529,145 @@ static int cm_init_thermal_data(struct charger_manager *cm) return ret; } +#ifdef CONFIG_OF +static struct of_device_id charger_manager_match[] = { + { + .compatible = "charger-manager", + }, + {}, +}; + +struct charger_desc *of_cm_parse_desc(struct device *dev) +{ + struct charger_desc *desc; + struct device_node *np = dev->of_node; + u32 poll_mode = CM_POLL_DISABLE; + u32 battery_stat = CM_NO_BATTERY; + int num_chgs; + + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return ERR_PTR(-ENOMEM); + + of_property_read_string(np, "cm-name", &desc->psy_name); + + of_property_read_u32(np, "cm-poll-mode", &poll_mode); + desc->polling_mode = poll_mode; + + of_property_read_u32(np, "cm-poll-interval", + &desc->polling_interval_ms); + + of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms", + &desc->fullbatt_vchkdrop_ms); + of_property_read_u32(np, "cm-fullbatt-vchkdrop-volt", + &desc->fullbatt_vchkdrop_uV); + of_property_read_u32(np, "cm-fullbatt-voltage", &desc->fullbatt_uV); + of_property_read_u32(np, "cm-fullbatt-soc", &desc->fullbatt_soc); + of_property_read_u32(np, "cm-fullbatt-capacity", + &desc->fullbatt_full_capacity); + + of_property_read_u32(np, "cm-battery-stat", &battery_stat); + desc->battery_present = battery_stat; + + /* chargers */ + of_property_read_u32(np, "cm-num-chargers", &num_chgs); + if (num_chgs) { + /* Allocate empty bin at the tail of array */ + desc->psy_charger_stat = devm_kzalloc(dev, sizeof(char *) + * (num_chgs + 1), GFP_KERNEL); + if (desc->psy_charger_stat) { + int i; + for (i = 0; i < num_chgs; i++) + of_property_read_string_index(np, "cm-chargers", + i, &desc->psy_charger_stat[i]); + } else { + return ERR_PTR(-ENOMEM); + } + } + + of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge); + + of_property_read_string(np, "cm-thermal-zone", &desc->thermal_zone); + + of_property_read_u32(np, "cm-battery-cold", &desc->temp_min); + if (of_get_property(np, "cm-battery-cold-in-minus", NULL)) + desc->temp_min *= -1; + of_property_read_u32(np, "cm-battery-hot", &desc->temp_max); + of_property_read_u32(np, "cm-battery-temp-diff", &desc->temp_diff); + + of_property_read_u32(np, "cm-charging-max", + &desc->charging_max_duration_ms); + of_property_read_u32(np, "cm-discharging-max", + &desc->discharging_max_duration_ms); + + /* battery charger regualtors */ + desc->num_charger_regulators = of_get_child_count(np); + if (desc->num_charger_regulators) { + struct charger_regulator *chg_regs; + struct device_node *child; + + chg_regs = devm_kzalloc(dev, sizeof(*chg_regs) + * desc->num_charger_regulators, + GFP_KERNEL); + if (!chg_regs) + return ERR_PTR(-ENOMEM); + + desc->charger_regulators = chg_regs; + + for_each_child_of_node(np, child) { + struct charger_cable *cables; + struct device_node *_child; + + of_property_read_string(child, "cm-regulator-name", + &chg_regs->regulator_name); + + /* charger cables */ + chg_regs->num_cables = of_get_child_count(child); + if (chg_regs->num_cables) { + cables = devm_kzalloc(dev, sizeof(*cables) + * chg_regs->num_cables, + GFP_KERNEL); + if (!cables) + return ERR_PTR(-ENOMEM); + + chg_regs->cables = cables; + + for_each_child_of_node(child, _child) { + of_property_read_string(_child, + "cm-cable-name", &cables->name); + of_property_read_string(_child, + "cm-cable-extcon", + &cables->extcon_name); + of_property_read_u32(_child, + "cm-cable-min", + &cables->min_uA); + of_property_read_u32(_child, + "cm-cable-max", + &cables->max_uA); + cables++; + } + } + chg_regs++; + } + } + return desc; +} +#else +#define charger_manager_match NULL +#endif + +static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev) +{ +#ifdef CONFIG_OF + if (pdev->dev.of_node) + return of_cm_parse_desc(&pdev->dev); +#endif + return (struct charger_desc *)dev_get_platdata(&pdev->dev); +} + static int charger_manager_probe(struct platform_device *pdev) { - struct charger_desc *desc = dev_get_platdata(&pdev->dev); + struct charger_desc *desc = cm_get_drv_data(pdev); struct charger_manager *cm; int ret = 0, i = 0; int j = 0; @@ -1887,6 +2024,7 @@ static struct platform_driver charger_manager_driver = { .name = "charger-manager", .owner = THIS_MODULE, .pm = &charger_manager_pm, + .of_match_table = charger_manager_match, }, .probe = charger_manager_probe, .remove = charger_manager_remove, diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index 9aec029..07e7945 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h @@ -191,7 +191,7 @@ struct charger_regulator { * max_duration_ms', cm start charging. */ struct charger_desc { - char *psy_name; + const char *psy_name; enum polling_modes polling_mode; unsigned int polling_interval_ms; @@ -204,14 +204,14 @@ struct charger_desc { enum data_source battery_present; - char **psy_charger_stat; + const char **psy_charger_stat; int num_charger_regulators; struct charger_regulator *charger_regulators; - char *psy_fuel_gauge; + const char *psy_fuel_gauge; - char *thermal_zone; + const char *thermal_zone; int temp_min; int temp_max; @@ -219,8 +219,8 @@ struct charger_desc { bool measure_battery_temp; - u64 charging_max_duration_ms; - u64 discharging_max_duration_ms; + u32 charging_max_duration_ms; + u32 discharging_max_duration_ms; }; #define PSY_NAME_MAX 30