diff options
author | Jonghwa Lee <jonghwa3.lee@samsung.com> | 2014-10-01 15:05:11 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 12:00:55 +0900 |
commit | c8a1f8253c5e4293baf077eafae28ac503248df5 (patch) | |
tree | a43f301d339c26989aff06517e1a89b04638160a | |
parent | 29e9cfb73c65efdcba444fa2f8eef3b6a772dc1b (diff) | |
download | linux-3.10-c8a1f8253c5e4293baf077eafae28ac503248df5.tar.gz linux-3.10-c8a1f8253c5e4293baf077eafae28ac503248df5.tar.bz2 linux-3.10-c8a1f8253c5e4293baf077eafae28ac503248df5.zip |
power: charger-manager: Rebase charger-manager up-to-date.
Drop all local commits and adjust it to up-to-date version of mainline
to make it easy to maintain.
Change-Id: Id5dc3314afd6498e704bcc1bdebe2c226b8fa07c
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
-rw-r--r-- | Documentation/devicetree/bindings/power_supply/charger-manager.txt | 81 | ||||
-rw-r--r-- | drivers/power/charger-manager.c | 440 | ||||
-rw-r--r-- | include/linux/power/charger-manager.h | 38 |
3 files changed, 295 insertions, 264 deletions
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 00000000000..2b33750e3db --- /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 <regulator> : + - cm-regulator-name : name of charger regulator + - subnode <cable> : + - 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 5a1baf13317..9e4dab46eef 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -12,6 +12,8 @@ * published by the Free Software Foundation. **/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/io.h> #include <linux/module.h> #include <linux/irq.h> @@ -24,12 +26,22 @@ #include <linux/regulator/consumer.h> #include <linux/sysfs.h> #include <linux/of.h> +#include <linux/thermal.h> + +/* + * 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" @@ -196,8 +208,8 @@ static bool is_charging(struct charger_manager *cm) cm->charger_stat[i], POWER_SUPPLY_PROP_ONLINE, &val); if (ret) { - dev_warn(cm->dev, "Cannot read ONLINE value from %s.\n", - cm->desc->psy_charger_stat[i]); + dev_warn(cm->dev, "Cannot read ONLINE value from %s\n", + cm->desc->psy_charger_stat[i]); continue; } if (val.intval == 0) @@ -211,8 +223,8 @@ static bool is_charging(struct charger_manager *cm) cm->charger_stat[i], POWER_SUPPLY_PROP_STATUS, &val); if (ret) { - dev_warn(cm->dev, "Cannot read STATUS value from %s.\n", - cm->desc->psy_charger_stat[i]); + dev_warn(cm->dev, "Cannot read STATUS value from %s\n", + cm->desc->psy_charger_stat[i]); continue; } if (val.intval == POWER_SUPPLY_STATUS_FULL || @@ -290,7 +302,7 @@ static bool is_polling_required(struct charger_manager *cm) return is_charging(cm); default: dev_warn(cm->dev, "Incorrect polling_mode (%d)\n", - cm->desc->polling_mode); + cm->desc->polling_mode); } return false; @@ -332,9 +344,8 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) err = regulator_enable(desc->charger_regulators[i].consumer); if (err < 0) { - dev_warn(cm->dev, - "Cannot enable %s regulator\n", - desc->charger_regulators[i].regulator_name); + dev_warn(cm->dev, "Cannot enable %s regulator\n", + desc->charger_regulators[i].regulator_name); } } } else { @@ -351,9 +362,8 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) err = regulator_disable(desc->charger_regulators[i].consumer); if (err < 0) { - dev_warn(cm->dev, - "Cannot disable %s regulator\n", - desc->charger_regulators[i].regulator_name); + dev_warn(cm->dev, "Cannot disable %s regulator\n", + desc->charger_regulators[i].regulator_name); } } @@ -366,9 +376,8 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) desc->charger_regulators[i].consumer)) { regulator_force_disable( desc->charger_regulators[i].consumer); - dev_warn(cm->dev, - "Disable regulator(%s) forcibly.\n", - desc->charger_regulators[i].regulator_name); + dev_warn(cm->dev, "Disable regulator(%s) forcibly\n", + desc->charger_regulators[i].regulator_name); } } } @@ -451,7 +460,7 @@ static void uevent_notify(struct charger_manager *cm, const char *event) strncpy(env_str, event, UEVENT_BUF_SIZE); kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); - dev_info(cm->dev, "%s", event); + dev_info(cm->dev, "%s\n", event); } /** @@ -479,7 +488,7 @@ static void fullbatt_vchk(struct work_struct *work) err = get_batt_uV(cm, &batt_uV); if (err) { - dev_err(cm->dev, "%s: get_batt_uV error(%d).\n", __func__, err); + dev_err(cm->dev, "%s: get_batt_uV error(%d)\n", __func__, err); return; } @@ -487,7 +496,7 @@ static void fullbatt_vchk(struct work_struct *work) if (diff < 0) return; - dev_info(cm->dev, "VBATT dropped %duV after full-batt.\n", diff); + dev_info(cm->dev, "VBATT dropped %duV after full-batt\n", diff); if (diff > desc->fullbatt_vchkdrop_uV) { try_charger_restart(cm); @@ -520,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 %ums", + dev_info(cm->dev, "Charging duration exceed %ums\n", desc->charging_max_duration_ms); uevent_notify(cm, "Discharging"); try_charger_enable(cm, false); @@ -531,9 +540,9 @@ 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 %ums", + dev_info(cm->dev, "Discharging duration exceed %ums\n", desc->discharging_max_duration_ms); - uevent_notify(cm, "Recharing"); + uevent_notify(cm, "Recharging"); try_charger_enable(cm, true); ret = true; } @@ -542,6 +551,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. @@ -551,41 +614,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); + int temp_alrt; - if (cm->desc->polling_battery_soc) { - union power_supply_propval val; - int ret; - ret = cm->charger_psy.get_property(&cm->charger_psy, - POWER_SUPPLY_PROP_CAPACITY, &val); - if (!ret && (cm->last_batt_soc != val.intval)) { - power_supply_changed(&cm->charger_psy); - cm->last_batt_soc = val.intval; - } - if (!is_polling_required(cm)) - return true; - } - - 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 @@ -593,7 +637,7 @@ static bool _cm_monitor(struct charger_manager *cm) */ } else if (!cm->emergency_stop && check_charging_duration(cm)) { dev_dbg(cm->dev, - "Charging/Discharging duration is out of range"); + "Charging/Discharging duration is out of range\n"); /* * Check dropped voltage of battery. If battery voltage is more * dropped than fullbatt_vchkdrop_uV after fully charged state, @@ -609,7 +653,7 @@ static bool _cm_monitor(struct charger_manager *cm) */ } else if (!cm->emergency_stop && is_full_charged(cm) && cm->charger_enabled) { - dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n"); + dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n"); uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); try_charger_enable(cm, false); @@ -663,16 +707,11 @@ static void _setup_polling(struct work_struct *work) mutex_lock(&cm_list_mtx); list_for_each_entry(cm, &cm_list, entry) { - if (!cm->desc->polling_interval_ms) - continue; - - if (is_polling_required(cm)) { + if (is_polling_required(cm) && cm->desc->polling_interval_ms) { keep_polling = true; + if (min > cm->desc->polling_interval_ms) min = cm->desc->polling_interval_ms; - } else if (cm->desc->polling_battery_soc) { - keep_polling = true; - min = cm->desc->polling_interval_ms; } } @@ -744,7 +783,7 @@ static void fullbatt_handler(struct charger_manager *cm) cm->fullbatt_vchk_jiffies_at = 1; out: - dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n"); + dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n"); uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); } @@ -822,22 +861,8 @@ static int charger_get_property(struct power_supply *psy, POWER_SUPPLY_PROP_CURRENT_NOW, val); break; case POWER_SUPPLY_PROP_TEMP: - /* in tenth of centigrade */ - if (cm->last_temp_mC == INT_MIN) - desc->temperature_out_of_range(cm); - - val->intval = cm->last_temp_mC; - if (!desc->measure_battery_temp) - ret = -ENODEV; - break; case POWER_SUPPLY_PROP_TEMP_AMBIENT: - /* in tenth of centigrade */ - if (cm->last_temp_mC == INT_MIN) - desc->temperature_out_of_range(cm); - val->intval = cm->last_temp_mC; - 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; @@ -930,24 +955,15 @@ static enum power_supply_property default_charger_props[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CHARGE_FULL, - - /* FIXME : 20131011 - * This property has been used in wrong way. - * It'll be fixed sooner to it's original purpose. - */ - POWER_SUPPLY_PROP_CHARGE_NOW, /* * Optional properties are: + * POWER_SUPPLY_PROP_CHARGE_NOW, * POWER_SUPPLY_PROP_CURRENT_NOW, * POWER_SUPPLY_PROP_TEMP, and * POWER_SUPPLY_PROP_TEMP_AMBIENT, */ }; -#define cm_chg_add_property(_property) \ -{ cm->charger_psy.properties[cm->charger_psy.num_properties] = _property;\ - cm->charger_psy.num_properties++; } - static struct power_supply psy_default = { .name = "battery", .type = POWER_SUPPLY_TYPE_BATTERY, @@ -1001,7 +1017,7 @@ static bool cm_setup_timer(void) mutex_unlock(&cm_list_mtx); if (wakeup_ms < UINT_MAX && wakeup_ms > 0) { - pr_info("Charger Manager wakeup timer: %u ms.\n", wakeup_ms); + pr_info("Charger Manager wakeup timer: %u ms\n", wakeup_ms); if (rtc_dev) { struct rtc_wkalrm tmp; unsigned long time, now; @@ -1034,8 +1050,7 @@ static bool cm_setup_timer(void) ret = false; } - pr_info("Waking up after %lu secs.\n", - time - now); + pr_info("Waking up after %lu secs\n", time - now); rtc_time_to_tm(time, &tmp.time); rtc_set_alarm(rtc_dev, &tmp); @@ -1130,7 +1145,7 @@ int setup_charger_manager(struct charger_global_desc *gd) g_desc = NULL; if (!gd->rtc_only_wakeup) { - pr_err("The callback rtc_only_wakeup is not given.\n"); + pr_err("The callback rtc_only_wakeup is not given\n"); return -EINVAL; } @@ -1141,7 +1156,7 @@ int setup_charger_manager(struct charger_global_desc *gd) /* Retry at probe. RTC may be not registered yet */ } } else { - pr_warn("No wakeup timer is given for charger manager." + pr_warn("No wakeup timer is given for charger manager. " "In-suspend monitoring won't work.\n"); } @@ -1167,18 +1182,16 @@ static void charger_extcon_work(struct work_struct *work) cable->min_uA, cable->max_uA); if (ret < 0) { pr_err("Cannot set current limit of %s (%s)\n", - cable->charger->regulator_name, cable->name); + cable->charger->regulator_name, cable->name); return; } pr_info("Set current limit of %s : %duA ~ %duA\n", - cable->charger->regulator_name, - cable->min_uA, cable->max_uA); + cable->charger->regulator_name, + cable->min_uA, cable->max_uA); } - if (!try_charger_enable(cable->cm, cable->attached)) - uevent_notify(cable->cm, - cable->attached ? "CHARGING" : "DISCHARGING"); + try_charger_enable(cable->cm, cable->attached); } /** @@ -1241,9 +1254,8 @@ static int charger_extcon_init(struct charger_manager *cm, ret = extcon_register_interest(&cable->extcon_dev, cable->extcon_name, cable->name, &cable->nb); if (ret < 0) { - pr_info("Cannot register extcon_dev for %s(cable: %s).\n", - cable->extcon_name, - cable->name); + pr_info("Cannot register extcon_dev for %s(cable: %s)\n", + cable->extcon_name, cable->name); ret = -EINVAL; } @@ -1274,8 +1286,8 @@ static int charger_manager_register_extcon(struct charger_manager *cm) charger->consumer = regulator_get(cm->dev, charger->regulator_name); if (IS_ERR(charger->consumer)) { - dev_err(cm->dev, "Cannot find charger(%s)n", - charger->regulator_name); + dev_err(cm->dev, "Cannot find charger(%s)\n", + charger->regulator_name); return PTR_ERR(charger->consumer); } charger->cm = cm; @@ -1285,8 +1297,8 @@ static int charger_manager_register_extcon(struct charger_manager *cm) ret = charger_extcon_init(cm, cable); if (ret < 0) { - dev_err(cm->dev, "Cannot initialize charger(%s)n", - charger->regulator_name); + dev_err(cm->dev, "Cannot initialize charger(%s)\n", + charger->regulator_name); goto err; } cable->charger = charger; @@ -1377,10 +1389,8 @@ static ssize_t charger_externally_control_store(struct device *dev, } } else { dev_warn(cm->dev, - "'%s' regulator should be controlled " - "in charger-manager because charger-manager " - "must need at least one charger for charging\n", - charger->regulator_name); + "'%s' regulator should be controlled in charger-manager because charger-manager must need at least one charger for charging\n", + charger->regulator_name); } return count; @@ -1417,8 +1427,6 @@ static int charger_manager_register_sysfs(struct charger_manager *cm) str = devm_kzalloc(cm->dev, sizeof(char) * (strlen(buf) + 1), GFP_KERNEL); if (!str) { - dev_err(cm->dev, "Cannot allocate memory: %s\n", - charger->regulator_name); ret = -ENOMEM; goto err; } @@ -1454,26 +1462,21 @@ static int charger_manager_register_sysfs(struct charger_manager *cm) !chargers_externally_control) chargers_externally_control = 0; - dev_info(cm->dev, "'%s' regulator's externally_control" - "is %d\n", charger->regulator_name, - charger->externally_control); + dev_info(cm->dev, "'%s' regulator's externally_control is %d\n", + charger->regulator_name, charger->externally_control); ret = sysfs_create_group(&cm->charger_psy.dev->kobj, &charger->attr_g); if (ret < 0) { - dev_err(cm->dev, "Cannot create sysfs entry" - "of %s regulator\n", - charger->regulator_name); + dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n", + charger->regulator_name); ret = -EINVAL; goto err; } } if (chargers_externally_control) { - dev_err(cm->dev, "Cannot register regulator because " - "charger-manager must need at least " - "one charger for charging battery\n"); - + dev_err(cm->dev, "Cannot register regulator because charger-manager must need at least one charger for charging battery\n"); ret = -EINVAL; goto err; } @@ -1482,71 +1485,50 @@ err: return ret; } -/* Every temperature units are in decii centigrade */ -#define CM_DEFAULT_TEMP_ALERT_DIFF 100 -#define CM_DEFAULT_TEMP_ALERT_MAX 1270 -#define CM_DEFAULT_TEMP_ALERT_MIN (-1270) - -static int cm_default_get_temp(struct charger_manager *cm) +static int cm_init_thermal_data(struct charger_manager *cm) { struct charger_desc *desc = cm->desc; union power_supply_propval val; - static int temp_alert_min = 0; - static int temp_alert_max = 0; - static int temp_alert_diff = 0; - static int last_temp_status = 0; int ret; - if (!temp_alert_min && !temp_alert_max) { - /* Initialize minimum temperature for alert */ - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_TEMP_ALERT_MIN, - &val); - temp_alert_min = ret ? desc->temp_alert_min : - min(desc->temp_alert_min, val.intval); - if (!temp_alert_min) - temp_alert_min = CM_DEFAULT_TEMP_ALERT_MIN; - - /* Initialize maximum temperature for alert */ - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_TEMP_ALERT_MAX, - &val); - temp_alert_max = ret ? desc->temp_alert_max : - min(desc->temp_alert_max, val.intval); - if (!temp_alert_max) - temp_alert_max = CM_DEFAULT_TEMP_ALERT_MAX; - - temp_alert_diff = desc->temp_alert_diff ? - : CM_DEFAULT_TEMP_ALERT_DIFF; - } - - /* Get battery temperature */ + /* Verify whether fuel gauge provides battery temperature */ ret = cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_TEMP, - &val); - if (ret) { - cm->last_temp_mC = INT_MIN; - return 0; + 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; } - - cm->last_temp_mC = val.intval; - - if (cm->last_temp_mC > temp_alert_max || (last_temp_status && - cm->last_temp_mC + temp_alert_diff > temp_alert_max)) { - /* OVERHEAT */ - last_temp_status = 1; - } else if (cm->last_temp_mC < temp_alert_min || (last_temp_status && - cm->last_temp_mC < temp_alert_min + temp_alert_diff)) { - /* Too COLD */ - last_temp_status = -1; - } else { - last_temp_status = 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 last_temp_status; + return ret; } -#ifdef CONFIG_OF static struct of_device_id charger_manager_match[] = { { .compatible = "charger-manager", @@ -1554,13 +1536,13 @@ static struct of_device_id charger_manager_match[] = { {}, }; -struct charger_desc *of_cm_parse_desc(struct device *dev) +static 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; + int num_chgs = 0; desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); if (!desc) @@ -1573,8 +1555,6 @@ struct charger_desc *of_cm_parse_desc(struct device *dev) of_property_read_u32(np, "cm-poll-interval", &desc->polling_interval_ms); - desc->polling_battery_soc = - of_property_read_bool(np, "cm-poll-batt-soc"); of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms", &desc->fullbatt_vchkdrop_ms); @@ -1588,13 +1568,6 @@ struct charger_desc *of_cm_parse_desc(struct device *dev) of_property_read_u32(np, "cm-battery-stat", &battery_stat); desc->battery_present = battery_stat; - of_property_read_u32(np, "cm-battery-cold", &desc->temp_alert_min); - if (of_get_property(np, "cm-battery-cold-in-minus", NULL)) - desc->temp_alert_min *= -1; - of_property_read_u32(np, "cm-battery-hot", &desc->temp_alert_max); - of_property_read_u32(np, "cm-battery-temp-diff", - &desc->temp_alert_diff); - /* chargers */ of_property_read_u32(np, "cm-num-chargers", &num_chgs); if (num_chgs) { @@ -1612,8 +1585,14 @@ struct charger_desc *of_cm_parse_desc(struct device *dev) } of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge); - if (of_get_property(np, "cm-battery-has-therm", NULL)) - desc->measure_battery_temp = true; + + 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); @@ -1672,23 +1651,17 @@ struct charger_desc *of_cm_parse_desc(struct device *dev) } return desc; } -#else -#define charger_manager_match NULL -#endif -static inline struct charger_desc *cm_get_drv_data( - struct platform_device *pdev) +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; + struct charger_desc *desc = cm_get_drv_data(pdev); struct charger_manager *cm; int ret = 0, i = 0; int j = 0; @@ -1698,61 +1671,52 @@ static int charger_manager_probe(struct platform_device *pdev) rtc_dev = rtc_class_open(g_desc->rtc_name); if (IS_ERR_OR_NULL(rtc_dev)) { rtc_dev = NULL; - dev_err(&pdev->dev, "Cannot get RTC %s.\n", + dev_err(&pdev->dev, "Cannot get RTC %s\n", g_desc->rtc_name); return -ENODEV; } } - desc = cm_get_drv_data(pdev); - if (!desc) { - dev_err(&pdev->dev, "No platform data (desc) found.\n"); + dev_err(&pdev->dev, "No platform data (desc) found\n"); return -ENODEV; } - cm = devm_kzalloc(&pdev->dev, sizeof(struct charger_manager), GFP_KERNEL); - if (!cm) { - dev_err(&pdev->dev, "Cannot allocate memory.\n"); + cm = devm_kzalloc(&pdev->dev, + sizeof(struct charger_manager), GFP_KERNEL); + if (!cm) return -ENOMEM; - } /* 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. * Users may intentionally ignore those two features. */ if (desc->fullbatt_uV == 0) { - dev_info(&pdev->dev, "Ignoring full-battery voltage threshold" - " as it is not supplied."); + dev_info(&pdev->dev, "Ignoring full-battery voltage threshold as it is not supplied\n"); } if (!desc->fullbatt_vchkdrop_ms || !desc->fullbatt_vchkdrop_uV) { - dev_info(&pdev->dev, "Disabling full-battery voltage drop " - "checking mechanism as it is not supplied."); + dev_info(&pdev->dev, "Disabling full-battery voltage drop checking mechanism as it is not supplied\n"); desc->fullbatt_vchkdrop_ms = 0; desc->fullbatt_vchkdrop_uV = 0; } if (desc->fullbatt_soc == 0) { - dev_info(&pdev->dev, "Ignoring full-battery soc(state of" - " charge) threshold as it is not" - " supplied."); + dev_info(&pdev->dev, "Ignoring full-battery soc(state of charge) threshold as it is not supplied\n"); } if (desc->fullbatt_full_capacity == 0) { - dev_info(&pdev->dev, "Ignoring full-battery full capacity" - " threshold as it is not supplied."); + dev_info(&pdev->dev, "Ignoring full-battery full capacity threshold as it is not supplied\n"); } if (!desc->charger_regulators || desc->num_charger_regulators < 1) { - dev_err(&pdev->dev, "charger_regulators undefined.\n"); + dev_err(&pdev->dev, "charger_regulators undefined\n"); return -EINVAL; } if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) { - dev_err(&pdev->dev, "No power supply defined.\n"); + dev_err(&pdev->dev, "No power supply defined\n"); return -EINVAL; } @@ -1761,18 +1725,16 @@ static int charger_manager_probe(struct platform_device *pdev) i++; cm->charger_stat = devm_kzalloc(&pdev->dev, - sizeof(struct power_supply *) * (i + 1), GFP_KERNEL); - if (!cm->charger_stat) { + sizeof(struct power_supply *) * i, GFP_KERNEL); + if (!cm->charger_stat) return -ENOMEM; - } for (i = 0; desc->psy_charger_stat[i]; i++) { cm->charger_stat[i] = power_supply_get_by_name( desc->psy_charger_stat[i]); if (!cm->charger_stat[i]) { - dev_err(&pdev->dev, "Cannot find power supply " - "\"%s\"\n", - desc->psy_charger_stat[i]); + dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", + desc->psy_charger_stat[i]); return -ENODEV; } } @@ -1780,7 +1742,7 @@ static int charger_manager_probe(struct platform_device *pdev) cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge); if (!cm->fuel_gauge) { dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", - desc->psy_fuel_gauge); + desc->psy_fuel_gauge); return -ENODEV; } @@ -1792,9 +1754,7 @@ static int charger_manager_probe(struct platform_device *pdev) 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"); + dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); desc->charging_max_duration_ms = 0; desc->discharging_max_duration_ms = 0; } @@ -1814,10 +1774,9 @@ static int charger_manager_probe(struct platform_device *pdev) sizeof(enum power_supply_property) * (ARRAY_SIZE(default_charger_props) + NUM_CHARGER_PSY_OPTIONAL), GFP_KERNEL); - if (!cm->charger_psy.properties) { - dev_err(&pdev->dev, "Cannot allocate for psy properties.\n"); + if (!cm->charger_psy.properties) return -ENOMEM; - } + memcpy(cm->charger_psy.properties, default_charger_props, sizeof(enum power_supply_property) * ARRAY_SIZE(default_charger_props)); @@ -1825,32 +1784,31 @@ static int charger_manager_probe(struct platform_device *pdev) /* Find which optional psy-properties are available */ if (!cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_CHARGE_NOW, &val)) - cm_chg_add_property(POWER_SUPPLY_PROP_CHARGE_NOW); + POWER_SUPPLY_PROP_CHARGE_NOW, &val)) { + cm->charger_psy.properties[cm->charger_psy.num_properties] = + POWER_SUPPLY_PROP_CHARGE_NOW; + cm->charger_psy.num_properties++; + } if (!cm->fuel_gauge->get_property(cm->fuel_gauge, POWER_SUPPLY_PROP_CURRENT_NOW, - &val)) - cm_chg_add_property(POWER_SUPPLY_PROP_CURRENT_NOW); + &val)) { + cm->charger_psy.properties[cm->charger_psy.num_properties] = + POWER_SUPPLY_PROP_CURRENT_NOW; + cm->charger_psy.num_properties++; + } - if (desc->measure_battery_temp) { - cm_chg_add_property(POWER_SUPPLY_PROP_TEMP); - desc->temperature_out_of_range = cm_default_get_temp; - } else { - if (!desc->temperature_out_of_range) { - dev_err(&pdev->dev, - "%s : No battery thermometer exists\n", - __func__); - return -EINVAL; - } - cm_chg_add_property(POWER_SUPPLY_PROP_TEMP_AMBIENT); + 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); ret = power_supply_register(NULL, &cm->charger_psy); if (ret) { - dev_err(&pdev->dev, "Cannot register charger-manager with" - " name \"%s\".\n", cm->charger_psy.name); + dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n", + cm->charger_psy.name); return ret; } @@ -2148,7 +2106,7 @@ void cm_notify_event(struct power_supply *psy, enum cm_event_types type, uevent_notify(cm, msg ? msg : default_event_names[type]); break; default: - dev_err(cm->dev, "%s type not specified.\n", __func__); + dev_err(cm->dev, "%s: type not specified\n", __func__); break; } } diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index f172e2fa95b..07e7945a1ff 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, @@ -148,8 +150,6 @@ struct charger_regulator { struct charger_manager *cm; }; -struct charger_manager; - /** * struct charger_desc * @psy_name: the name of power-supply-class for charger manager @@ -169,22 +169,16 @@ struct charger_manager; * it is assumed to be full. * @polling_interval_ms: interval in millisecond at which * charger manager will monitor battery health - * @polling_battery_soc: if TRUE, charger-manager reads battery soc and - * triggers uevent periodcally. * @battery_present: * Specify where information for existance of battery can be obtained * @psy_charger_stat: the names of power-supply for chargers * @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 - * @temp_alert_min : Minimum battery temperature to be allowed. - * @temp_alert_max : Maximum battery temperature to be allowed. - * @temp_alert_diff : Temperature diffential to restart charging. - * @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 @@ -201,8 +195,6 @@ struct charger_desc { enum polling_modes polling_mode; unsigned int polling_interval_ms; - /* For checking battery soc */ - bool polling_battery_soc; unsigned int fullbatt_vchkdrop_ms; unsigned int fullbatt_vchkdrop_uV; @@ -219,11 +211,12 @@ struct charger_desc { const char *psy_fuel_gauge; - int temp_alert_min; - int temp_alert_max; - int temp_alert_diff; + const char *thermal_zone; + + int temp_min; + int temp_max; + int temp_diff; - int (*temperature_out_of_range)(struct charger_manager *); bool measure_battery_temp; u32 charging_max_duration_ms; @@ -239,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: @@ -254,7 +247,6 @@ struct charger_desc { * saved status of battery before entering suspend-to-RAM * @charging_start_time: saved start time of enabling charging * @charging_end_time: saved end time of disabling charging - * @last_batt_soc: Last battery soc. */ struct charger_manager { struct list_head entry; @@ -264,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; @@ -280,8 +274,6 @@ struct charger_manager { u64 charging_start_time; u64 charging_end_time; - - unsigned int last_batt_soc; }; #ifdef CONFIG_CHARGER_MANAGER |