diff options
author | Jonghwa Lee <jonghwa3.lee@samsung.com> | 2014-10-22 18:07:35 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 12:01:03 +0900 |
commit | 5fb7e974cd956087be5b7a5a8cf477c8754addff (patch) | |
tree | adae778e3d5653f455ba0d8400bbad8719bfda34 | |
parent | 502a2ce42f035112cb455446b823444eeb2b7421 (diff) | |
download | linux-3.10-5fb7e974cd956087be5b7a5a8cf477c8754addff.tar.gz linux-3.10-5fb7e974cd956087be5b7a5a8cf477c8754addff.tar.bz2 linux-3.10-5fb7e974cd956087be5b7a5a8cf477c8754addff.zip |
power: charger-manager: Update essential battery information at once.
In current code, charger-manager may attemps to read battery state more
than once in a same period. And it already did such when user accesses
uevent, it reads battery voltage several times.
This patch makes charger-manager to read current battery state including
SoC, voltage and temperature at the start of monitoring and re-use it
during whole period.
Change-Id: Ic69ddb465a75237ded0488cb3eb41f47bb909311
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
-rw-r--r-- | drivers/power/charger-manager.c | 296 | ||||
-rw-r--r-- | include/linux/power/charger-manager.h | 32 |
2 files changed, 139 insertions, 189 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index b2a4fedb6e0..c739a89fc64 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -75,6 +75,7 @@ static struct delayed_work cm_monitor_work; /* init at driver add */ static bool is_batt_present(struct charger_manager *cm) { union power_supply_propval val; + struct power_supply *fuelgauge = cm->battery.fuelgauge; bool present = false; int i, ret; @@ -85,7 +86,7 @@ static bool is_batt_present(struct charger_manager *cm) case CM_NO_BATTERY: break; case CM_FUEL_GAUGE: - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + ret = fuelgauge->get_property(fuelgauge, POWER_SUPPLY_PROP_PRESENT, &val); if (ret == 0 && val.intval) present = true; @@ -134,87 +135,18 @@ static bool is_ext_pwr_online(struct charger_manager *cm) } /** - * get_batt_uV - Get the voltage level of the battery - * @cm: the Charger Manager representing the battery. - * @uV: the voltage level returned. - * - * Returns 0 if there is no error. - * Returns a negative value on error. - */ -static int get_batt_uV(struct charger_manager *cm, int *uV) -{ - union power_supply_propval val; - int ret; - - if (!cm->fuel_gauge) - return -ENODEV; - - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); - if (ret) - return ret; - - *uV = val.intval; - return 0; -} - -/** * is_charging - Returns true if the battery is being charged. * @cm: the Charger Manager representing the battery. */ static bool is_charging(struct charger_manager *cm) { - int i, ret; - bool charging = false; - union power_supply_propval val; + struct battery_entity *battery = &cm->battery; /* If there is no battery, it cannot be charged */ if (!is_batt_present(cm)) return false; - /* If at least one of the charger is charging, return yes */ - for (i = 0; i < cm->desc->num_chargers; i++) { - /* 1. The charger sholuld not be DISABLED */ - if (cm->emergency_stop) - continue; - if (!cm->charger_enabled) - continue; - - /* 2. The charger should be online (ext-power) */ - ret = cm->charger_stat[i]->get_property( - 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]); - continue; - } - if (val.intval == 0) - continue; - - /* - * 3. The charger should not be FULL, DISCHARGING, - * or NOT_CHARGING. - */ - ret = cm->charger_stat[i]->get_property( - 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]); - continue; - } - if (val.intval == POWER_SUPPLY_STATUS_FULL || - val.intval == POWER_SUPPLY_STATUS_DISCHARGING || - val.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) - continue; - - /* Then, this is charging. */ - charging = true; - break; - } - - return charging; + return battery->status == POWER_SUPPLY_STATUS_CHARGING; } /** @@ -224,6 +156,8 @@ static bool is_charging(struct charger_manager *cm) static bool is_full_charged(struct charger_manager *cm) { struct charger_desc *desc = cm->desc; + struct battery_entity *battery = &cm->battery; + struct power_supply *fuelgauge = battery->fuelgauge; union power_supply_propval val; int ret = 0; int uV = 0; @@ -234,34 +168,28 @@ static bool is_full_charged(struct charger_manager *cm) /* Full, if it's over the fullbatt voltage */ if (desc->fullbatt_uV > 0) { - ret = get_batt_uV(cm, &uV); - if (!ret) { - /* Battery is already full, checks voltage drop. */ - if (cm->battery_status == POWER_SUPPLY_STATUS_FULL - && desc->fullbatt_vchkdrop_uV) - uV += desc->fullbatt_vchkdrop_uV; - if (uV >= desc->fullbatt_uV) - return true; - } + uV = battery->voltage; + /* Battery is already full, checks voltage drop. */ + if (battery->status == POWER_SUPPLY_STATUS_FULL + && desc->fullbatt_vchkdrop_uV) + uV += desc->fullbatt_vchkdrop_uV; + if (uV >= desc->fullbatt_uV) + return true; } - if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) { + if (desc->fullbatt_full_capacity > 0) { val.intval = 0; /* Not full if capacity of fuel gauge isn't full */ - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + ret = fuelgauge->get_property(fuelgauge, POWER_SUPPLY_PROP_CHARGE_FULL, &val); if (!ret && val.intval > desc->fullbatt_full_capacity) return true; } /* Full, if the capacity is more than fullbatt_soc */ - if (cm->fuel_gauge && desc->fullbatt_soc > 0) { - val.intval = 0; - - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_CAPACITY, &val); - if (!ret && val.intval >= desc->fullbatt_soc) + if (desc->fullbatt_soc > 0) { + if (battery->soc >= desc->fullbatt_soc) return true; } @@ -311,9 +239,6 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) return 0; if (enable) { - if (cm->emergency_stop) - return -EAGAIN; - /* * Save start time of charging to limit * maximum possible charging time. @@ -384,6 +309,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) static int check_charging_duration(struct charger_manager *cm) { struct charger_desc *desc = cm->desc; + struct battery_entity *battery = &cm->battery; u64 curr = ktime_to_ms(ktime_get()); u64 duration; int ret = false; @@ -400,7 +326,7 @@ static int check_charging_duration(struct charger_manager *cm) desc->charging_max_duration_ms); ret = true; } - } else if (cm->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { + } else if (battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING) { duration = curr - cm->charging_end_time; if (duration > desc->charging_max_duration_ms) { @@ -413,52 +339,31 @@ 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; - - ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); - if (!ret) - /* Calibrate temperature unit */ - *temp /= 100; - - return ret; -} - -static int cm_check_thermal_status(struct charger_manager *cm) +static void 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; - } + struct battery_entity *battery = &cm->battery; + int upper_limit, lower_limit; upper_limit = desc->temp_max; lower_limit = desc->temp_min; - if (cm->emergency_stop) { + if (battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING) { 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; + if (battery->temperature > upper_limit) { + battery->health = POWER_SUPPLY_HEALTH_OVERHEAT; + return; + } - cm->emergency_stop = ret; + if (battery->temperature < lower_limit) { + battery->health = POWER_SUPPLY_HEALTH_COLD; + return; + } - return ret; + battery->health = POWER_SUPPLY_HEALTH_GOOD; } /** @@ -467,17 +372,19 @@ static int cm_check_thermal_status(struct charger_manager *cm) */ static int cm_get_target_status(struct charger_manager *cm) { + struct battery_entity *battery = &cm->battery; + if (!is_ext_pwr_online(cm)) return POWER_SUPPLY_STATUS_DISCHARGING; - if (cm_check_thermal_status(cm)) { + if (battery->health != POWER_SUPPLY_HEALTH_GOOD) { /* Check if discharging duration exeeds limit. */ if (check_charging_duration(cm)) goto charging_ok; return POWER_SUPPLY_STATUS_NOT_CHARGING; } - switch (cm->battery_status) { + switch (battery->status) { case POWER_SUPPLY_STATUS_CHARGING: /* Check if charging duration exeeds limit. */ if (check_charging_duration(cm)) @@ -495,26 +402,76 @@ charging_ok: } /** + * update_battery_state - Update current battery state. + * @battery: battery_entity instance + * + * Return true if battery state is varied from last checking. + */ +static bool update_battery_state(struct battery_entity *battery) +{ + struct power_supply *fuelgauge = battery->fuelgauge; + union power_supply_propval val; + bool updated = false; + unsigned long temp; + int ret; + + ret = fuelgauge->get_property(fuelgauge, + POWER_SUPPLY_PROP_CAPACITY, &val); + if (!ret && battery->soc != val.intval) { + battery->soc = val.intval; + updated = true; + } + + ret = fuelgauge->get_property(fuelgauge, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + if (!ret && battery->voltage != val.intval) { + battery->voltage = val.intval; + updated = true; + } + + ret = thermal_zone_get_temp(battery->tzd, &temp); + if (!ret) { + /* Change unit to decidegree Celcius */ + temp /= 100; + if (battery->temperature != temp) { + battery->temperature = temp; + updated = true; + } + } + + return updated; +} + +/** * _cm_monitor - Monitor the temperature and return true for exceptions. * @cm: the Charger Manager representing the battery. * * Returns true if there is an event to notify for the battery. - * (True if the status of "emergency_stop" changes) + * (True if the battery status changes) */ static bool _cm_monitor(struct charger_manager *cm) { + struct battery_entity *battery = &cm->battery; int target; + bool updated = false; + + updated = update_battery_state(battery); + + cm_check_thermal_status(cm); target = cm_get_target_status(cm); try_charger_enable(cm, (target == POWER_SUPPLY_STATUS_CHARGING)); - if (cm->battery_status != target) { - cm->battery_status = target; - power_supply_changed(&cm->charger_psy); + if (battery->status != target) { + battery->status = target; + updated = true; } - return (cm->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING); + if (updated) + power_supply_changed(&cm->charger_psy); + + return updated; } /** @@ -614,20 +571,18 @@ static int charger_get_property(struct power_supply *psy, struct charger_manager *cm = container_of(psy, struct charger_manager, charger_psy); struct charger_desc *desc = cm->desc; + struct battery_entity *battery = &cm->battery; + struct power_supply *fuelgauge = battery->fuelgauge; int ret = 0; - int uV; + + update_battery_state(battery); switch (psp) { case POWER_SUPPLY_PROP_STATUS: - val->intval = cm->battery_status; + val->intval = battery->status; break; case POWER_SUPPLY_PROP_HEALTH: - if (cm->emergency_stop > 0) - val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; - else if (cm->emergency_stop < 0) - val->intval = POWER_SUPPLY_HEALTH_COLD; - else - val->intval = POWER_SUPPLY_HEALTH_GOOD; + val->intval = battery->health; break; case POWER_SUPPLY_PROP_PRESENT: if (is_batt_present(cm)) @@ -636,56 +591,35 @@ static int charger_get_property(struct power_supply *psy, val->intval = 0; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = get_batt_uV(cm, &val->intval); + val->intval = battery->voltage; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + ret = fuelgauge->get_property(fuelgauge, POWER_SUPPLY_PROP_CURRENT_NOW, val); break; case POWER_SUPPLY_PROP_TEMP: - case POWER_SUPPLY_PROP_TEMP_AMBIENT: - return cm_get_battery_temperature(cm, &val->intval); + val->intval = battery->temperature; + break; case POWER_SUPPLY_PROP_CAPACITY: - if (!cm->fuel_gauge) { - ret = -ENODEV; - break; - } - if (!is_batt_present(cm)) { /* There is no battery. Assume 100% */ val->intval = 100; break; } - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, - POWER_SUPPLY_PROP_CAPACITY, val); - if (ret) - break; + val->intval = battery->soc; if (val->intval > 100) { val->intval = 100; break; } - if (val->intval < 0) - val->intval = 0; /* Do not adjust SOC when charging: voltage is overrated */ if (is_charging(cm)) break; - /* - * If the capacity value is inconsistent, calibrate it base on - * the battery voltage values and the thresholds given as desc - */ - ret = get_batt_uV(cm, &uV); - if (ret) { - /* Voltage information not available. No calibration */ - ret = 0; - break; - } - - if (desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && - !is_charging(cm)) { + if (desc->fullbatt_uV > 0 + && battery->voltage >= desc->fullbatt_uV) { val->intval = 100; break; } @@ -698,11 +632,11 @@ static int charger_get_property(struct power_supply *psy, val->intval = 0; break; case POWER_SUPPLY_PROP_CHARGE_FULL: - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + ret = fuelgauge->get_property(fuelgauge, POWER_SUPPLY_PROP_CHARGE_FULL, val); break; case POWER_SUPPLY_PROP_CHARGE_NOW: - ret = cm->fuel_gauge->get_property(cm->fuel_gauge, + ret = fuelgauge->get_property(fuelgauge, POWER_SUPPLY_PROP_CHARGE_NOW, val); break; default: @@ -760,7 +694,7 @@ static bool cm_setup_timer(void) mutex_lock(&cm_list_mtx); list_for_each_entry(cm, &cm_list, entry) { /* Skip if polling is not required for this CM */ - if (!is_polling_required(cm) && !cm->emergency_stop) + if (!is_polling_required(cm)) continue; timer_req++; if (cm->desc->polling_interval_ms == 0) @@ -1245,8 +1179,9 @@ static void cm_add_optional_property(struct charger_manager *cm, enum power_supply_property psp) { union power_supply_propval val; + struct power_supply *fuelgauge = cm->battery.fuelgauge; - if (cm->fuel_gauge->get_property(cm->fuel_gauge, psp, &val)) + if (fuelgauge->get_property(fuelgauge, psp, &val)) return; cm->charger_psy.properties[cm->charger_psy.num_properties] = psp; @@ -1330,8 +1265,8 @@ 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) { + cm->battery.fuelgauge = power_supply_get_by_name(desc->psy_fuel_gauge); + if (!cm->battery.fuelgauge) { dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", desc->psy_fuel_gauge); return -ENODEV; @@ -1376,12 +1311,12 @@ static int charger_manager_probe(struct platform_device *pdev) cm_add_optional_property(cm, cm_optional_props[i]); if (desc->thermal_zone) - cm->tzd_batt = + cm->battery.tzd = thermal_zone_get_zone_by_name(desc->thermal_zone); else - cm->tzd_batt = cm->fuel_gauge->tzd; + cm->battery.tzd = cm->battery.fuelgauge->tzd; - if (!cm->tzd_batt) { + if (!cm->battery.tzd) { pr_err("No way to monitor battery temperature.\n"); return -ENODEV; } @@ -1420,6 +1355,9 @@ static int charger_manager_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, true); device_set_wakeup_capable(&pdev->dev, false); + /* Update initial battery state */ + _cm_monitor(cm); + schedule_work(&setup_polling); return 0; diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index b7a58e788ce..d380ba343ef 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h @@ -203,17 +203,34 @@ struct charger_desc { #define PSY_NAME_MAX 30 +/* struct battery_entity + * @fuelgauge: power_supply for fuel gauge + * @tzd : thermal zone device for battery + * @status: Current battery status + * @health: Current battery health + * @soc: Current battery soc + * @voltage: Current battery voltage + * @temperature: Current battery temperature + */ +struct battery_entity { + struct power_supply *fuelgauge; + struct thermal_zone_device *tzd; + + int status; + int health; + + int soc; + int voltage; + int temperature; +}; + /** * struct charger_manager * @entry: entry for list * @dev: device pointer * @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 - * @emergency_stop: - * When setting true, stop charging * @psy_name_buf: the name of power-supply-class for charger manager * @charger_psy: power_supply for charger manager * @status_save_ext_pwr_inserted: @@ -228,17 +245,12 @@ struct charger_manager { struct device *dev; struct charger_desc *desc; - int battery_status; + struct battery_entity battery; - struct power_supply *fuel_gauge; struct power_supply **charger_stat; - struct thermal_zone_device *tzd_batt; - bool charger_enabled; - int emergency_stop; - char psy_name_buf[PSY_NAME_MAX + 1]; struct power_supply charger_psy; |