static int ec_get_battery_property(struct power_supply *psy,
					enum power_supply_property psp,
					union power_supply_propval *val)
{
	struct ec_battery_info *chip = container_of(psy,
				struct ec_battery_info, bat);
	int ret = 0, cur_sign = -1;
	int comp_cap = 0;
	u8 val8, cap;
	u16 val16;

	mutex_lock(&chip->lock);
	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		ret = byt_ec_read_byte(EC_BAT0_CUR_CAP_REG, &cap);
		if (ret < 0)
			goto ec_read_err;

		ret = byt_ec_read_byte(EC_BAT0_STAT_REG, &val8);
		if (ret < 0)
			goto ec_read_err;

		ret = byt_ec_read_word(EC_BAT0_BATTSBS_STATUS, &val16);
		if (ret < 0)
			goto ec_read_err;

		if (val8 & BAT0_STAT_DISCHARGING)
			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
		else if (val8 & BAT0_STAT_CHARGING)
			val->intval = POWER_SUPPLY_STATUS_CHARGING;
		else if (val8 & BAT0_STAT_LOW_BATT)
			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
		else if ((cap == 100) || (val16 & BAT0_BATTSBS_STATUS_FC))
			val->intval = POWER_SUPPLY_STATUS_FULL;
		else if (cap != 0)
			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
		else
			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		ret = byt_ec_read_byte(EC_BAT0_STAT_REG, &val8);
		if (ret < 0)
			goto ec_read_err;
		/* If battery is not connected
		 * return POWER_SUPPLY_HEALTH_UNKNOWN
		 */
		if (!(val8 & BAT0_STAT_BATT_PRESENT)) {
			val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
			break;
		}

		/* Battery operational temperature range is
		 * 0C to 40C while charging and -20 C to 60C
		 * while Discharging/Full/Not Charging.
		 */
		ret = byt_ec_read_word(EC_BAT0_TEMP_REG, &val16);
		if (ret < 0)
			goto ec_read_err;

		/* Android framwork don't differentiate b/w hot and cold.
		 *Both are treated as  overheat cases.
		 *So report overheat in both high and low temp cases.
		 */
		if ((val16 >= EC_BAT_CHRG_OVER_TEMP)
			| (val16 <= EC_BAT_CHRG_UNDER_TEMP)) {
			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
			break;
		}
		ret = byt_ec_read_word(EC_BAT0_VBATT_REG, &val16);
		if (ret < 0)
			goto ec_read_err;
		/* The battery is treated as DEAD if the battery voltage is
		 *bellow <= 6.55V in BYT-M
		 */
		if (val16 <= EC_BAT_DEAD_VOLTAGE) {
			val->intval = POWER_SUPPLY_HEALTH_DEAD;
			break;
		}

		val->intval = POWER_SUPPLY_HEALTH_GOOD;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		ret = byt_ec_read_word(EC_BAT0_VBATT_REG, &val16);
		if (ret < 0)
			goto ec_read_err;
		val->intval = val16 * 1000;
		break;
	case POWER_SUPPLY_PROP_CURRENT_NOW:
		ret = byt_ec_read_byte(EC_BAT0_STAT_REG, &val8);
		if (ret < 0)
			goto ec_read_err;

		if (val8 & BAT0_STAT_CHARGING) {
			ret = byt_ec_read_word(EC_BAT0_CIBATT_CUR_REG, &val16);
			cur_sign = 1;
		} else {
			ret = byt_ec_read_word(EC_BAT0_DIBATT_CUR_REG, &val16);
			cur_sign = -1;
		}
		if (ret < 0)
			goto ec_read_err;
		val->intval = cur_sign * ((int)val16 * 1000);
		break;
	case POWER_SUPPLY_PROP_CURRENT_AVG:
		ret = byt_ec_read_word(EC_BAT0_AVG_CUR_REG, &val16);
		if (ret < 0)
			goto ec_read_err;

		val->intval = (int)adjust_sign_value(val16) * 1000;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		ret = byt_ec_read_byte(EC_BAT0_CUR_CAP_REG, &cap);
		if (ret < 0)
			goto ec_read_err;

		ret = byt_ec_read_byte(EC_BAT0_STAT_REG, &val8);
		if (ret < 0)
			goto ec_read_err;

		if ((val8 & 0x7) || (cap != 0))
			val->intval = 1;
		else
			val->intval = 0;
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		ret = byt_ec_read_byte(EC_BAT0_CUR_CAP_REG, &val8);
		if (ret < 0)
			goto ec_read_err;
		/* 6% of battery capacity is minimun treshold for BYT-M
		 *So, the 6% is mapped to 0% in android.
		 * 6% to 100% is compensated with 0% to 100% to OS.
		 * Compensated capacity = cap - ((100 - cap)*6)/100 + 0.5
		 */
		comp_cap = val8;
		comp_cap = comp_cap*100 - ((100 - comp_cap)
				*EC_BAT_SAFE_MIN_CAPACITY) + 50;
		comp_cap /= 100;
		if (comp_cap < 0)
			comp_cap = 0;
		val->intval = comp_cap;
		break;
	case POWER_SUPPLY_PROP_TEMP:
		ret = byt_ec_read_word(EC_BAT0_TEMP_REG, &val16);
		if (ret < 0)
			goto ec_read_err;
		/*
		 * convert temperature from degree kelvin
		 * to degree celsius: T(C) = T(K) - 273.15
		 * also 1 LSB of Temp register = 0.1 Kelvin.
		 */
		val->intval = (((int)val16 * 10) -
			EC_BAT_TEMP_CONV_FACTOR) / 10;
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		ret = byt_ec_read_byte(EC_BAT0_STAT_REG, &val8);
		if (ret < 0)
			goto ec_read_err;
		/*If battery is not connected
		 *return POWER_SUPPLY_TECHNOLOGY_UNKNOWN
		 */
		if (val8 & BAT0_STAT_BATT_PRESENT)
			val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
		else
			val->intval =   POWER_SUPPLY_HEALTH_UNKNOWN;
		break;
	case POWER_SUPPLY_PROP_CHARGE_NOW:
		ret = byt_ec_read_word(EC_BAT0_REM_CAP_REG, &val16);
		if (ret < 0)
			goto ec_read_err;
		val->intval = ((int)val16) * 1000;
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL:
		ret = byt_ec_read_word(EC_BAT0_FULL_CHRG_CAP_REG, &val16);
		if (ret < 0)
			goto ec_read_err;
		val->intval = ((int)val16) * 1000;
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		ret = byt_ec_read_word(EC_BAT0_DESIGN_CAP_REG, &val16);
		if (ret < 0)
			goto ec_read_err;
		val->intval = ((int)val16) * 1000;
		break;
	default:
		mutex_unlock(&chip->lock);
		return -EINVAL;
	}

	mutex_unlock(&chip->lock);
	return 0;

ec_read_err:
	mutex_unlock(&chip->lock);
	return ret;
}
예제 #2
0
static int ulpmc_get_battery_property(struct power_supply *psy,
					enum power_supply_property psp,
					union power_supply_propval *val)
{
	int ret = 0;
	struct ulpmc_chip_info *chip = container_of(psy,
				struct ulpmc_chip_info, bat);
	mutex_lock(&chip->lock);
	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_FLAGS);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ulpmc_battery_status(chip, ret);
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		/*
		 * RVP doesn't support health detection yet.
		 * This feature will be supported on PR1.
		 */
		val->intval = POWER_SUPPLY_HEALTH_GOOD;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_VOLT);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ret * 1000;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
		val->intval = chip->pdata->volt_sh_min * 1000;
		break;
	case POWER_SUPPLY_PROP_CURRENT_AVG:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_AI);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ((int)adjust_sign_value(ret)) * 1000;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_FLAGS);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = (ret & FG_FLAG_BDET) ? 1 : 0;
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		if (chip->pdata->version == BYTULPMCFGV3)
			ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_SOC);
		else
			ret = ulpmc_read_reg16(chip->client,
							ULPMC_FG_REG_SOC_V4);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ret;
		break;
	case POWER_SUPPLY_PROP_TEMP:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_TEMP);
		if (ret < 0)
			goto i2c_read_err;
		dev_dbg(&chip->client->dev, "BQ FG Temp:%d\n", ret - 2731);
		/*
		 * RVP doesn't support temperature readings.
		 * This feature will be supported on PR1.
		 */
		val->intval = 350;
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
		break;
	case POWER_SUPPLY_PROP_CHARGE_NOW:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_RMC);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ret * 1000;
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_FCC);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ret * 1000;
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_FAC);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ret * 1000;
		break;
	case POWER_SUPPLY_PROP_CYCLE_COUNT:
		if (chip->pdata->version == BYTULPMCFGV3)
			ret = ulpmc_read_reg16(chip->client, ULPMC_FG_REG_CYCT);
		else
			ret = ulpmc_read_reg16(chip->client,
							ULPMC_FG_REG_CYCT_V4);
		if (ret < 0)
			goto i2c_read_err;
		val->intval = ret;
		break;
	case POWER_SUPPLY_PROP_MODEL_NAME:
		val->strval = chip->pdata->battid;
		break;
	default:
		mutex_unlock(&chip->lock);
		return -EINVAL;
	}

	mutex_unlock(&chip->lock);
	return 0;

i2c_read_err:
	mutex_unlock(&chip->lock);
	return ret;
}