Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec7de656 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-v3.18-rc' of git://git.infradead.org/battery-2.6

Pull power supply updates from Sebastian Reichel:
 "Power supply and reset changes for the v3.18-rc:

   - misc. charger-manager fixes
   - year 2038 fix in ab8500_fg
   - fix error handling of bq2415x_charger"

* tag 'for-v3.18-rc' of git://git.infradead.org/battery-2.6:
  power: charger-manager: Fix accessing invalidated power supply after charger unbind
  power: charger-manager: Fix accessing invalidated power supply after fuel gauge unbind
  power: charger-manager: Avoid recursive thermal get_temp call
  power_supply: Add no_thermal property to prevent recursive get_temp calls
  power: bq2415x_charger: Fix memory leak on DTS parsing error
  power: bq2415x_charger: Properly handle ENODEV from power_supply_get_by_phandle
  power: ab8500_fg.c: use 64-bit time types
parents e0611671 cdaf3e15
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/time64.h>
#include <linux/of.h>
#include <linux/completion.h>
#include <linux/mfd/core.h>
@@ -108,7 +109,7 @@ enum ab8500_fg_calibration_state {
struct ab8500_fg_avg_cap {
	int avg;
	int samples[NBR_AVG_SAMPLES];
	__kernel_time_t time_stamps[NBR_AVG_SAMPLES];
	time64_t time_stamps[NBR_AVG_SAMPLES];
	int pos;
	int nbr_samples;
	int sum;
@@ -386,15 +387,15 @@ static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr)
 */
static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample)
{
	struct timespec ts;
	struct timespec64 ts64;
	struct ab8500_fg_avg_cap *avg = &di->avg_cap;

	getnstimeofday(&ts);
	getnstimeofday64(&ts64);

	do {
		avg->sum += sample - avg->samples[avg->pos];
		avg->samples[avg->pos] = sample;
		avg->time_stamps[avg->pos] = ts.tv_sec;
		avg->time_stamps[avg->pos] = ts64.tv_sec;
		avg->pos++;

		if (avg->pos == NBR_AVG_SAMPLES)
@@ -407,7 +408,7 @@ static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample)
		 * Check the time stamp for each sample. If too old,
		 * replace with latest sample
		 */
	} while (ts.tv_sec - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]);
	} while (ts64.tv_sec - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]);

	avg->avg = avg->sum / avg->nbr_samples;

@@ -446,14 +447,14 @@ static void ab8500_fg_clear_cap_samples(struct ab8500_fg *di)
static void ab8500_fg_fill_cap_sample(struct ab8500_fg *di, int sample)
{
	int i;
	struct timespec ts;
	struct timespec64 ts64;
	struct ab8500_fg_avg_cap *avg = &di->avg_cap;

	getnstimeofday(&ts);
	getnstimeofday64(&ts64);

	for (i = 0; i < NBR_AVG_SAMPLES; i++) {
		avg->samples[i] = sample;
		avg->time_stamps[i] = ts.tv_sec;
		avg->time_stamps[i] = ts64.tv_sec;
	}

	avg->pos = 0;
+15 −8
Original line number Diff line number Diff line
@@ -1579,8 +1579,15 @@ static int bq2415x_probe(struct i2c_client *client,
	if (np) {
		bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection");

		if (!bq->notify_psy)
			return -EPROBE_DEFER;
		if (IS_ERR(bq->notify_psy)) {
			dev_info(&client->dev,
				"no 'ti,usb-charger-detection' property (err=%ld)\n",
				PTR_ERR(bq->notify_psy));
			bq->notify_psy = NULL;
		} else if (!bq->notify_psy) {
			ret = -EPROBE_DEFER;
			goto error_2;
		}
	}
	else if (pdata->notify_device)
		bq->notify_psy = power_supply_get_by_name(pdata->notify_device);
@@ -1602,27 +1609,27 @@ static int bq2415x_probe(struct i2c_client *client,
		ret = of_property_read_u32(np, "ti,current-limit",
				&bq->init_data.current_limit);
		if (ret)
			return ret;
			goto error_2;
		ret = of_property_read_u32(np, "ti,weak-battery-voltage",
				&bq->init_data.weak_battery_voltage);
		if (ret)
			return ret;
			goto error_2;
		ret = of_property_read_u32(np, "ti,battery-regulation-voltage",
				&bq->init_data.battery_regulation_voltage);
		if (ret)
			return ret;
			goto error_2;
		ret = of_property_read_u32(np, "ti,charge-current",
				&bq->init_data.charge_current);
		if (ret)
			return ret;
			goto error_2;
		ret = of_property_read_u32(np, "ti,termination-current",
				&bq->init_data.termination_current);
		if (ret)
			return ret;
			goto error_2;
		ret = of_property_read_u32(np, "ti,resistor-sense",
				&bq->init_data.resistor_sense);
		if (ret)
			return ret;
			goto error_2;
	} else {
		memcpy(&bq->init_data, pdata, sizeof(bq->init_data));
	}
+111 −53
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ static struct charger_global_desc *g_desc; /* init with setup_charger_manager */
static bool is_batt_present(struct charger_manager *cm)
{
	union power_supply_propval val;
	struct power_supply *psy;
	bool present = false;
	int i, ret;

@@ -107,16 +108,27 @@ 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,
		psy = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
		if (!psy)
			break;

		ret = psy->get_property(psy,
				POWER_SUPPLY_PROP_PRESENT, &val);
		if (ret == 0 && val.intval)
			present = true;
		break;
	case CM_CHARGER_STAT:
		for (i = 0; cm->charger_stat[i]; i++) {
			ret = cm->charger_stat[i]->get_property(
					cm->charger_stat[i],
					POWER_SUPPLY_PROP_PRESENT, &val);
		for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
			psy = power_supply_get_by_name(
					cm->desc->psy_charger_stat[i]);
			if (!psy) {
				dev_err(cm->dev, "Cannot find power supply \"%s\"\n",
					cm->desc->psy_charger_stat[i]);
				continue;
			}

			ret = psy->get_property(psy, POWER_SUPPLY_PROP_PRESENT,
					&val);
			if (ret == 0 && val.intval) {
				present = true;
				break;
@@ -139,14 +151,20 @@ static bool is_batt_present(struct charger_manager *cm)
static bool is_ext_pwr_online(struct charger_manager *cm)
{
	union power_supply_propval val;
	struct power_supply *psy;
	bool online = false;
	int i, ret;

	/* If at least one of them has one, it's yes. */
	for (i = 0; cm->charger_stat[i]; i++) {
		ret = cm->charger_stat[i]->get_property(
				cm->charger_stat[i],
				POWER_SUPPLY_PROP_ONLINE, &val);
	for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
		psy = power_supply_get_by_name(cm->desc->psy_charger_stat[i]);
		if (!psy) {
			dev_err(cm->dev, "Cannot find power supply \"%s\"\n",
					cm->desc->psy_charger_stat[i]);
			continue;
		}

		ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
		if (ret == 0 && val.intval) {
			online = true;
			break;
@@ -167,12 +185,14 @@ static bool is_ext_pwr_online(struct charger_manager *cm)
static int get_batt_uV(struct charger_manager *cm, int *uV)
{
	union power_supply_propval val;
	struct power_supply *fuel_gauge;
	int ret;

	if (!cm->fuel_gauge)
	fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
	if (!fuel_gauge)
		return -ENODEV;

	ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
	ret = fuel_gauge->get_property(fuel_gauge,
				POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
	if (ret)
		return ret;
@@ -189,6 +209,7 @@ static bool is_charging(struct charger_manager *cm)
{
	int i, ret;
	bool charging = false;
	struct power_supply *psy;
	union power_supply_propval val;

	/* If there is no battery, it cannot be charged */
@@ -196,17 +217,22 @@ static bool is_charging(struct charger_manager *cm)
		return false;

	/* If at least one of the charger is charging, return yes */
	for (i = 0; cm->charger_stat[i]; i++) {
	for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
		/* 1. The charger sholuld not be DISABLED */
		if (cm->emergency_stop)
			continue;
		if (!cm->charger_enabled)
			continue;

		psy = power_supply_get_by_name(cm->desc->psy_charger_stat[i]);
		if (!psy) {
			dev_err(cm->dev, "Cannot find power supply \"%s\"\n",
					cm->desc->psy_charger_stat[i]);
			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);
		ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
		if (ret) {
			dev_warn(cm->dev, "Cannot read ONLINE value from %s\n",
				 cm->desc->psy_charger_stat[i]);
@@ -219,9 +245,7 @@ static bool is_charging(struct charger_manager *cm)
		 * 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);
		ret = psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
		if (ret) {
			dev_warn(cm->dev, "Cannot read STATUS value from %s\n",
				 cm->desc->psy_charger_stat[i]);
@@ -248,6 +272,7 @@ static bool is_full_charged(struct charger_manager *cm)
{
	struct charger_desc *desc = cm->desc;
	union power_supply_propval val;
	struct power_supply *fuel_gauge;
	int ret = 0;
	int uV;

@@ -255,11 +280,15 @@ static bool is_full_charged(struct charger_manager *cm)
	if (!is_batt_present(cm))
		return false;

	if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) {
	fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
	if (!fuel_gauge)
		return false;

	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 = fuel_gauge->get_property(fuel_gauge,
				POWER_SUPPLY_PROP_CHARGE_FULL, &val);
		if (!ret && val.intval > desc->fullbatt_full_capacity)
			return true;
@@ -273,10 +302,10 @@ static bool is_full_charged(struct charger_manager *cm)
	}

	/* Full, if the capacity is more than fullbatt_soc */
	if (cm->fuel_gauge && desc->fullbatt_soc > 0) {
	if (desc->fullbatt_soc > 0) {
		val.intval = 0;

		ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
		ret = fuel_gauge->get_property(fuel_gauge,
				POWER_SUPPLY_PROP_CAPACITY, &val);
		if (!ret && val.intval >= desc->fullbatt_soc)
			return true;
@@ -551,6 +580,20 @@ static int check_charging_duration(struct charger_manager *cm)
	return ret;
}

static int cm_get_battery_temperature_by_psy(struct charger_manager *cm,
					int *temp)
{
	struct power_supply *fuel_gauge;

	fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
	if (!fuel_gauge)
		return -ENODEV;

	return fuel_gauge->get_property(fuel_gauge,
				POWER_SUPPLY_PROP_TEMP,
				(union power_supply_propval *)temp);
}

static int cm_get_battery_temperature(struct charger_manager *cm,
					int *temp)
{
@@ -560,15 +603,18 @@ static int cm_get_battery_temperature(struct charger_manager *cm,
		return -ENODEV;

#ifdef CONFIG_THERMAL
	if (cm->tzd_batt) {
		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);
	} else
#endif
	{
		/* if-else continued from CONFIG_THERMAL */
		ret = cm_get_battery_temperature_by_psy(cm, temp);
	}

	return ret;
}

@@ -827,6 +873,7 @@ 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 power_supply *fuel_gauge;
	int ret = 0;
	int uV;

@@ -857,14 +904,20 @@ static int charger_get_property(struct power_supply *psy,
		ret = get_batt_uV(cm, &val->intval);
		break;
	case POWER_SUPPLY_PROP_CURRENT_NOW:
		ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
		fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
		if (!fuel_gauge) {
			ret = -ENODEV;
			break;
		}
		ret = fuel_gauge->get_property(fuel_gauge,
				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);
	case POWER_SUPPLY_PROP_CAPACITY:
		if (!cm->fuel_gauge) {
		fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
		if (!fuel_gauge) {
			ret = -ENODEV;
			break;
		}
@@ -875,7 +928,7 @@ static int charger_get_property(struct power_supply *psy,
			break;
		}

		ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
		ret = fuel_gauge->get_property(fuel_gauge,
					POWER_SUPPLY_PROP_CAPACITY, val);
		if (ret)
			break;
@@ -924,7 +977,14 @@ static int charger_get_property(struct power_supply *psy,
		break;
	case POWER_SUPPLY_PROP_CHARGE_NOW:
		if (is_charging(cm)) {
			ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
			fuel_gauge = power_supply_get_by_name(
					cm->desc->psy_fuel_gauge);
			if (!fuel_gauge) {
				ret = -ENODEV;
				break;
			}

			ret = fuel_gauge->get_property(fuel_gauge,
						POWER_SUPPLY_PROP_CHARGE_NOW,
						val);
			if (ret) {
@@ -970,6 +1030,7 @@ static struct power_supply psy_default = {
	.properties = default_charger_props,
	.num_properties = ARRAY_SIZE(default_charger_props),
	.get_property = charger_get_property,
	.no_thermal = true,
};

/**
@@ -1485,14 +1546,15 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
	return ret;
}

static int cm_init_thermal_data(struct charger_manager *cm)
static int cm_init_thermal_data(struct charger_manager *cm,
		struct power_supply *fuel_gauge)
{
	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,
	ret = fuel_gauge->get_property(fuel_gauge,
					POWER_SUPPLY_PROP_TEMP, &val);

	if (!ret) {
@@ -1502,8 +1564,6 @@ static int cm_init_thermal_data(struct charger_manager *cm)
		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);
@@ -1666,6 +1726,7 @@ static int charger_manager_probe(struct platform_device *pdev)
	int ret = 0, i = 0;
	int j = 0;
	union power_supply_propval val;
	struct power_supply *fuel_gauge;

	if (g_desc && !rtc_dev && g_desc->rtc_name) {
		rtc_dev = rtc_class_open(g_desc->rtc_name);
@@ -1729,23 +1790,20 @@ static int charger_manager_probe(struct platform_device *pdev)
	while (desc->psy_charger_stat[i])
		i++;

	cm->charger_stat = devm_kzalloc(&pdev->dev,
				sizeof(struct power_supply *) * i, GFP_KERNEL);
	if (!cm->charger_stat)
		return -ENOMEM;

	/* Check if charger's supplies are present at probe */
	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]) {
		struct power_supply *psy;

		psy = power_supply_get_by_name(desc->psy_charger_stat[i]);
		if (!psy) {
			dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
				desc->psy_charger_stat[i]);
			return -ENODEV;
		}
	}

	cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge);
	if (!cm->fuel_gauge) {
	fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge);
	if (!fuel_gauge) {
		dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
			desc->psy_fuel_gauge);
		return -ENODEV;
@@ -1788,13 +1846,13 @@ static int charger_manager_probe(struct platform_device *pdev)
	cm->charger_psy.num_properties = psy_default.num_properties;

	/* Find which optional psy-properties are available */
	if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
	if (!fuel_gauge->get_property(fuel_gauge,
					  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,
	if (!fuel_gauge->get_property(fuel_gauge,
					  POWER_SUPPLY_PROP_CURRENT_NOW,
					  &val)) {
		cm->charger_psy.properties[cm->charger_psy.num_properties] =
@@ -1802,7 +1860,7 @@ static int charger_manager_probe(struct platform_device *pdev)
		cm->charger_psy.num_properties++;
	}

	ret = cm_init_thermal_data(cm);
	ret = cm_init_thermal_data(cm, fuel_gauge);
	if (ret) {
		dev_err(&pdev->dev, "Failed to initialize thermal data\n");
		cm->desc->measure_battery_temp = false;
@@ -2066,8 +2124,8 @@ static bool find_power_supply(struct charger_manager *cm,
	int i;
	bool found = false;

	for (i = 0; cm->charger_stat[i]; i++) {
		if (psy == cm->charger_stat[i]) {
	for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
		if (!strcmp(psy->name, cm->desc->psy_charger_stat[i])) {
			found = true;
			break;
		}
+3 −0
Original line number Diff line number Diff line
@@ -417,6 +417,9 @@ static int psy_register_thermal(struct power_supply *psy)
{
	int i;

	if (psy->no_thermal)
		return 0;

	/* Register battery zone device psy reports temperature */
	for (i = 0; i < psy->num_properties; i++) {
		if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
+0 −3
Original line number Diff line number Diff line
@@ -253,9 +253,6 @@ struct charger_manager {
	struct device *dev;
	struct charger_desc *desc;

	struct power_supply *fuel_gauge;
	struct power_supply **charger_stat;

#ifdef CONFIG_THERMAL
	struct thermal_zone_device *tzd_batt;
#endif
Loading