static int sbs_get_property()

in supply/sbs-battery.c [905:1035]


static int sbs_get_property(struct power_supply *psy,
	enum power_supply_property psp,
	union power_supply_propval *val)
{
	int ret = 0;
	struct sbs_info *chip = power_supply_get_drvdata(psy);
	struct i2c_client *client = chip->client;
	const char *str;

	if (chip->gpio_detect) {
		ret = gpiod_get_value_cansleep(chip->gpio_detect);
		if (ret < 0)
			return ret;
		if (psp == POWER_SUPPLY_PROP_PRESENT) {
			val->intval = ret;
			sbs_update_presence(chip, ret);
			return 0;
		}
		if (ret == 0)
			return -ENODATA;
	}

	switch (psp) {
	case POWER_SUPPLY_PROP_PRESENT:
	case POWER_SUPPLY_PROP_HEALTH:
		ret = sbs_get_battery_presence_and_health(client, psp, val);

		/* this can only be true if no gpio is used */
		if (psp == POWER_SUPPLY_PROP_PRESENT)
			return 0;
		break;

	case POWER_SUPPLY_PROP_TECHNOLOGY:
		ret = sbs_get_chemistry(chip, val);
		if (ret < 0)
			break;

		goto done; /* don't trigger power_supply_changed()! */

	case POWER_SUPPLY_PROP_ENERGY_NOW:
	case POWER_SUPPLY_PROP_ENERGY_FULL:
	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
	case POWER_SUPPLY_PROP_CHARGE_NOW:
	case POWER_SUPPLY_PROP_CHARGE_FULL:
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		ret = sbs_get_property_index(client, psp);
		if (ret < 0)
			break;

		/* sbs_get_battery_capacity() will change the battery mode
		 * temporarily to read the requested attribute. Ensure we stay
		 * in the desired mode for the duration of the attribute read.
		 */
		mutex_lock(&chip->mode_lock);
		ret = sbs_get_battery_capacity(client, ret, psp, val);
		mutex_unlock(&chip->mode_lock);
		break;

	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
		ret = sbs_get_battery_serial_number(client, val);
		break;

	case POWER_SUPPLY_PROP_STATUS:
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
	case POWER_SUPPLY_PROP_CYCLE_COUNT:
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
	case POWER_SUPPLY_PROP_CURRENT_NOW:
	case POWER_SUPPLY_PROP_CURRENT_AVG:
	case POWER_SUPPLY_PROP_TEMP:
	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
	case POWER_SUPPLY_PROP_CAPACITY:
	case POWER_SUPPLY_PROP_CAPACITY_ERROR_MARGIN:
		ret = sbs_get_property_index(client, psp);
		if (ret < 0)
			break;

		ret = sbs_get_battery_property(client, ret, psp, val);
		break;

	case POWER_SUPPLY_PROP_MODEL_NAME:
	case POWER_SUPPLY_PROP_MANUFACTURER:
		str = sbs_get_constant_string(chip, psp);
		if (IS_ERR(str))
			ret = PTR_ERR(str);
		else
			val->strval = str;
		break;

	case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
	case POWER_SUPPLY_PROP_MANUFACTURE_MONTH:
	case POWER_SUPPLY_PROP_MANUFACTURE_DAY:
		ret = sbs_get_battery_manufacture_date(client, psp, val);
		break;

	default:
		dev_err(&client->dev,
			"%s: INVALID property\n", __func__);
		return -EINVAL;
	}

	if (!chip->gpio_detect && chip->is_present != (ret >= 0)) {
		bool old_present = chip->is_present;
		union power_supply_propval val;
		int err = sbs_get_battery_presence_and_health(
				client, POWER_SUPPLY_PROP_PRESENT, &val);

		sbs_update_presence(chip, !err && val.intval);

		if (old_present != chip->is_present)
			power_supply_changed(chip->power_supply);
	}

done:
	if (!ret) {
		/* Convert units to match requirements for power supply class */
		sbs_unit_adjustment(client, psp, val);
		dev_dbg(&client->dev,
			"%s: property = %d, value = %x\n", __func__,
			psp, val->intval);
	} else if (!chip->is_present)  {
		/* battery not present, so return NODATA for properties */
		ret = -ENODATA;
	}
	return ret;
}