From patchwork Wed Dec 18 06:42:34 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonghwa Lee X-Patchwork-Id: 3367881 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 068249F314 for ; Wed, 18 Dec 2013 06:42:49 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8BA1E203DB for ; Wed, 18 Dec 2013 06:42:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D5361203AE for ; Wed, 18 Dec 2013 06:42:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751277Ab3LRGmn (ORCPT ); Wed, 18 Dec 2013 01:42:43 -0500 Received: from mailout3.samsung.com ([203.254.224.33]:31807 "EHLO mailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750933Ab3LRGmm (ORCPT ); Wed, 18 Dec 2013 01:42:42 -0500 Received: from epcpsbgr5.samsung.com (u145.gpu120.samsung.co.kr [203.254.230.145]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MXZ00179PB4AC50@mailout3.samsung.com> for linux-pm@vger.kernel.org; Wed, 18 Dec 2013 15:42:40 +0900 (KST) Received: from epcpsbgm1.samsung.com ( [172.20.52.116]) by epcpsbgr5.samsung.com (EPCPMTA) with SMTP id 9B.BE.06316.0E341B25; Wed, 18 Dec 2013 15:42:40 +0900 (KST) X-AuditID: cbfee691-b7fe66d0000018ac-5a-52b143e068ea Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 22.D6.22838.0E341B25; Wed, 18 Dec 2013 15:42:40 +0900 (KST) Received: from localhost.localdomain ([10.252.82.199]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MXZ006ONPB13O70@mmp2.samsung.com>; Wed, 18 Dec 2013 15:42:40 +0900 (KST) From: Jonghwa Lee To: linux-pm@vger.kernel.org Cc: anton@enomsg.org, dwmw2@infradead.org, Jonghwa Lee , Myungjoo Ham Subject: [PATCH v3 RESEND 1/2] charger-manager : Modify the way of checking battery's temperature. Date: Wed, 18 Dec 2013 15:42:34 +0900 Message-id: <1387348955-23174-2-git-send-email-jonghwa3.lee@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1387348955-23174-1-git-send-email-jonghwa3.lee@samsung.com> References: <1387348955-23174-1-git-send-email-jonghwa3.lee@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrCLMWRmVeSWpSXmKPExsWyRsSkRPeB88Ygg+27pSwObtW0mLhyMrNF 59knzBafe48wWtxuXMHmwOoxof8To8fmFVoefVtWMXp83iQXwBLFZZOSmpNZllqkb5fAlfGs 8wxzwY2wik3ffrE0MO5372Lk5JAQMJF4dOImO4QtJnHh3nq2LkYuDiGBpYwSRzfPZIEpWnpp MiNEYjqjxOOJd1kgnDYmiYVTW1hBqtgEdCT+74MYJSIgIzH1yn6gOAcHs0CNxJcjQSBhYYEU oPLTzCA2i4CqxNwH98DKeQU8JA7tOcsCUi4hoCAxZ5INSJhTwFPi97a1jCC2EFDJx93XmEDW Sgg0s0sc3LaNEWKOgMS3yYegemUlNh1ghrhZUuLgihssExiFFzAyrGIUTS1ILihOSi8y1StO zC0uzUvXS87P3cQIDOHT/55N3MF4/4D1IcZkoHETmaVEk/OBMZBXEm9obGZkYWpiamxkbmlG mrCSOG/6o6QgIYH0xJLU7NTUgtSi+KLSnNTiQ4xMHJxSDYwL/n163b80tEmsJZbZ+Kmfa8ff /CfTHQVb2q74Xo78pr3hkkr0jC81UStW5dzPnFa5I/ZGTKDYmkDvSWu7e/a8fccVv23/wtQt X+3v3nh85sCv9ZJZvw6YKr74d3hui9CbMI3rzMUpSwI8mj8ZPJk6966j3Hfm3mMz+k65veW6 c3Snhf3Lj8sPK7EUZyQaajEXFScCANFrM+p3AgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrIIsWRmVeSWpSXmKPExsVy+t9jQd0HzhuDDBZtFLA4uFXTYuLKycwW nWefMFt87j3CaHG7cQWbA6vHhP5PjB6bV2h59G1ZxejxeZNcAEtUA6NNRmpiSmqRQmpecn5K Zl66rZJ3cLxzvKmZgaGuoaWFuZJCXmJuqq2Si0+ArltmDtBaJYWyxJxSoFBAYnGxkr4dpgmh IW66FjCNEbq+IUFwPUYGaCBhDWPGs84zzAU3wio2ffvF0sC4372LkZNDQsBEYumlyYwQtpjE hXvr2boYuTiEBKYzSjyeeJcFwmljklg4tYUVpIpNQEfi/76b7CC2iICMxNQr+4HiHBzMAjUS X44EgYSFBVKAyk8zg9gsAqoScx/cAyvnFfCQOLTnLAtIuYSAgsScSTYgYU4BT4nf29aC3SAE VPJx9zWmCYy8CxgZVjGKphYkFxQnpeca6hUn5haX5qXrJefnbmIER8gzqR2MKxssDjEKcDAq 8fByzF4fJMSaWFZcmXuIUYKDWUmEd93/DUFCvCmJlVWpRfnxRaU5qcWHGJOBjprILCWanA+M 3rySeENjEzMjSyNzQwsjY3PShJXEeQ+0WgcKCaQnlqRmp6YWpBbBbGHi4JRqYHQVFApel8b5 8YF0pFPA3FOXC24b3XbaztRVY/zyrV6i+q9jk9fM8JKZ3MllJzFlyiqJ7olK5e2dazfkK136 +r5M6VJAcYqe/bn533Yb8XLub2ZSdNlfEhHdP3GO+YQ60SlpW29ddIl+ELKJyd0v4nrkIQn5 aO7Fb5LPxy9LqLpsFHqG2UKoWYmlOCPRUIu5qDgRAHHEJZ3UAgAA 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 driver used to check battery temperature through the callback function passed by platform data. Unfortunatley, without that pre-defined callback function, charger-manager can't get battery's temperature at all. Also passing callback function through platform data ruins DT support for charger-manager. This patch mondifies charger-manager driver to get temperature of battery without pre-defined callback function. Now, charger-manager can use either of battery thermometer in fuel-gauge and ouside of battery. It uses thermal framework interface for outer thermometer if thermal fw is enabled. Otherwise, it tries to use fuel-gauge's through the power supply interface. Signed-off-by: Jonghwa Lee Signed-off-by: Myungjoo Ham --- drivers/power/charger-manager.c | 161 ++++++++++++++++++++++++--------- include/linux/power/charger-manager.h | 24 +++-- 2 files changed, 136 insertions(+), 49 deletions(-) diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 7287c0e..6b68d15 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -25,12 +25,22 @@ #include #include #include +#include + +/* + * Default termperature threshold for charging. + * Every temperature units are in tenth of centigrade. + */ +#define CM_DEFAULT_RECHARGE_TEMP_DIFF 50 +#define CM_DEFAULT_CHARGE_TEMP_MAX 500 static const char * const default_event_names[] = { [CM_EVENT_UNKNOWN] = "Unknown", [CM_EVENT_BATT_FULL] = "Battery Full", [CM_EVENT_BATT_IN] = "Battery Inserted", [CM_EVENT_BATT_OUT] = "Battery Pulled Out", + [CM_EVENT_BATT_OVERHEAT] = "Battery Overheat", + [CM_EVENT_BATT_COLD] = "Battery Cold", [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", [CM_EVENT_OTHERS] = "Other battery events" @@ -540,6 +550,60 @@ static int check_charging_duration(struct charger_manager *cm) return ret; } +static int cm_get_battery_temperature(struct charger_manager *cm, + int *temp) +{ + int ret; + + if (!cm->desc->measure_battery_temp) + return -ENODEV; + +#ifdef CONFIG_THERMAL + ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); + if (!ret) + /* Calibrate temperature unit */ + *temp /= 100; +#else + ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + POWER_SUPPLY_PROP_TEMP, + (union power_supply_propval *)temp); +#endif + return ret; +} + +static int cm_check_thermal_status(struct charger_manager *cm) +{ + struct charger_desc *desc = cm->desc; + int temp, upper_limit, lower_limit; + int ret = 0; + + ret = cm_get_battery_temperature(cm, &temp); + if (ret) { + /* FIXME: + * No information of battery temperature might + * occur hazadous result. We have to handle it + * depending on battery type. + */ + dev_err(cm->dev, "Failed to get battery temperature\n"); + return 0; + } + + upper_limit = desc->temp_max; + lower_limit = desc->temp_min; + + if (cm->emergency_stop) { + upper_limit -= desc->temp_diff; + lower_limit += desc->temp_diff; + } + + if (temp > upper_limit) + ret = CM_EVENT_BATT_OVERHEAT; + else if (temp < lower_limit) + ret = CM_EVENT_BATT_COLD; + + return ret; +} + /** * _cm_monitor - Monitor the temperature and return true for exceptions. * @cm: the Charger Manager representing the battery. @@ -549,28 +613,22 @@ static int check_charging_duration(struct charger_manager *cm) */ static bool _cm_monitor(struct charger_manager *cm) { - struct charger_desc *desc = cm->desc; - int temp = desc->temperature_out_of_range(&cm->last_temp_mC); + int temp_alrt; - dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", - cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); + temp_alrt = cm_check_thermal_status(cm); /* It has been stopped already */ - if (temp && cm->emergency_stop) + if (temp_alrt && cm->emergency_stop) return false; /* * Check temperature whether overheat or cold. * If temperature is out of range normal state, stop charging. */ - if (temp) { - cm->emergency_stop = temp; - if (!try_charger_enable(cm, false)) { - if (temp > 0) - uevent_notify(cm, "OVERHEAT"); - else - uevent_notify(cm, "COLD"); - } + if (temp_alrt) { + cm->emergency_stop = temp_alrt; + if (!try_charger_enable(cm, false)) + uevent_notify(cm, default_event_names[temp_alrt]); /* * Check whole charging duration and discharing duration @@ -802,21 +860,8 @@ static int charger_get_property(struct power_supply *psy, POWER_SUPPLY_PROP_CURRENT_NOW, val); break; case POWER_SUPPLY_PROP_TEMP: - /* in thenth of centigrade */ - if (cm->last_temp_mC == INT_MIN) - desc->temperature_out_of_range(&cm->last_temp_mC); - val->intval = cm->last_temp_mC / 100; - if (!desc->measure_battery_temp) - ret = -ENODEV; - break; case POWER_SUPPLY_PROP_TEMP_AMBIENT: - /* in thenth of centigrade */ - if (cm->last_temp_mC == INT_MIN) - desc->temperature_out_of_range(&cm->last_temp_mC); - val->intval = cm->last_temp_mC / 100; - if (desc->measure_battery_temp) - ret = -ENODEV; - break; + return cm_get_battery_temperature(cm, &val->intval); case POWER_SUPPLY_PROP_CAPACITY: if (!cm->fuel_gauge) { ret = -ENODEV; @@ -1439,6 +1484,50 @@ err: return ret; } +static int cm_init_thermal_data(struct charger_manager *cm) +{ + struct charger_desc *desc = cm->desc; + union power_supply_propval val; + int ret; + + /* Verify whether fuel gauge provides battery temperature */ + ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + POWER_SUPPLY_PROP_TEMP, &val); + + if (!ret) { + cm->charger_psy.properties[cm->charger_psy.num_properties] = + POWER_SUPPLY_PROP_TEMP; + cm->charger_psy.num_properties++; + cm->desc->measure_battery_temp = true; + } +#ifdef CONFIG_THERMAL + cm->tzd_batt = cm->fuel_gauge->tzd; + + if (ret && desc->thermal_zone) { + cm->tzd_batt = + thermal_zone_get_zone_by_name(desc->thermal_zone); + if (IS_ERR(cm->tzd_batt)) + return PTR_ERR(cm->tzd_batt); + + /* Use external thermometer */ + cm->charger_psy.properties[cm->charger_psy.num_properties] = + POWER_SUPPLY_PROP_TEMP_AMBIENT; + cm->charger_psy.num_properties++; + cm->desc->measure_battery_temp = true; + ret = 0; + } +#endif + if (cm->desc->measure_battery_temp) { + /* NOTICE : Default allowable minimum charge temperature is 0 */ + if (!desc->temp_max) + desc->temp_max = CM_DEFAULT_CHARGE_TEMP_MAX; + if (!desc->temp_diff) + desc->temp_diff = CM_DEFAULT_RECHARGE_TEMP_DIFF; + } + + return ret; +} + static int charger_manager_probe(struct platform_device *pdev) { struct charger_desc *desc = dev_get_platdata(&pdev->dev); @@ -1470,7 +1559,6 @@ static int charger_manager_probe(struct platform_device *pdev) /* Basic Values. Unspecified are Null or 0 */ cm->dev = &pdev->dev; cm->desc = desc; - cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ /* * The following two do not need to be errors. @@ -1533,11 +1621,6 @@ static int charger_manager_probe(struct platform_device *pdev) return -EINVAL; } - if (!desc->temperature_out_of_range) { - dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); - return -EINVAL; - } - if (!desc->charging_max_duration_ms || !desc->discharging_max_duration_ms) { dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); @@ -1583,14 +1666,10 @@ static int charger_manager_probe(struct platform_device *pdev) cm->charger_psy.num_properties++; } - if (desc->measure_battery_temp) { - cm->charger_psy.properties[cm->charger_psy.num_properties] = - POWER_SUPPLY_PROP_TEMP; - cm->charger_psy.num_properties++; - } else { - cm->charger_psy.properties[cm->charger_psy.num_properties] = - POWER_SUPPLY_PROP_TEMP_AMBIENT; - cm->charger_psy.num_properties++; + ret = cm_init_thermal_data(cm); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize thermal data\n"); + cm->desc->measure_battery_temp = false; } INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index 0e86840..9aec029 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h @@ -37,6 +37,8 @@ enum cm_event_types { CM_EVENT_BATT_FULL, CM_EVENT_BATT_IN, CM_EVENT_BATT_OUT, + CM_EVENT_BATT_OVERHEAT, + CM_EVENT_BATT_COLD, CM_EVENT_EXT_PWR_IN_OUT, CM_EVENT_CHG_START_STOP, CM_EVENT_OTHERS, @@ -173,11 +175,10 @@ struct charger_regulator { * @num_charger_regulator: the number of entries in charger_regulators * @charger_regulators: array of charger regulators * @psy_fuel_gauge: the name of power-supply for fuel gauge - * @temperature_out_of_range: - * Determine whether the status is overheat or cold or normal. - * return_value > 0: overheat - * return_value == 0: normal - * return_value < 0: cold + * @thermal_zone : the name of thermal zone for battery + * @temp_min : Minimum battery temperature for charging. + * @temp_max : Maximum battery temperature for charging. + * @temp_diff : Temperature diffential to restart charging. * @measure_battery_temp: * true: measure battery temperature * false: measure ambient temperature @@ -210,7 +211,12 @@ struct charger_desc { char *psy_fuel_gauge; - int (*temperature_out_of_range)(int *mC); + char *thermal_zone; + + int temp_min; + int temp_max; + int temp_diff; + bool measure_battery_temp; u64 charging_max_duration_ms; @@ -226,13 +232,13 @@ struct charger_desc { * @desc: instance of charger_desc * @fuel_gauge: power_supply for fuel gauge * @charger_stat: array of power_supply for chargers + * @tzd_batt : thermal zone device for battery * @charger_enabled: the state of charger * @fullbatt_vchk_jiffies_at: * jiffies at the time full battery check will occur. * @fullbatt_vchk_work: work queue for full battery check * @emergency_stop: * When setting true, stop charging - * @last_temp_mC: the measured temperature in milli-Celsius * @psy_name_buf: the name of power-supply-class for charger manager * @charger_psy: power_supply for charger manager * @status_save_ext_pwr_inserted: @@ -250,13 +256,15 @@ struct charger_manager { struct power_supply *fuel_gauge; struct power_supply **charger_stat; +#ifdef CONFIG_THERMAL + struct thermal_zone_device *tzd_batt; +#endif bool charger_enabled; unsigned long fullbatt_vchk_jiffies_at; struct delayed_work fullbatt_vchk_work; int emergency_stop; - int last_temp_mC; char psy_name_buf[PSY_NAME_MAX + 1]; struct power_supply charger_psy;