/* soc should be 0.01% unit */
static int adc_get_soc(struct i2c_client *client)
{
	struct sec_fuelgauge_info *fuelgauge =
				i2c_get_clientdata(client);
	int soc;

	soc = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).ocv2soc_table,
		get_battery_data(fuelgauge).ocv2soc_table_size,
		fuelgauge->info.voltage_ocv);

	return soc;
}
Example #2
0
static int adc_get_vcell(struct i2c_client *client)
{
	struct sec_fuelgauge_info *fuelgauge =
				i2c_get_clientdata(client);
	int vcell;

	vcell = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).adc2vcell_table,
		get_battery_data(fuelgauge).adc2vcell_table_size,
		adc_get_adc_value(fuelgauge, SEC_BAT_ADC_CHANNEL_VOLTAGE_NOW));

	return vcell;
}
static int adc_get_current(struct i2c_client *client)
{
	union power_supply_propval value;
	struct sec_fuelgauge_info *fuelgauge =
				i2c_get_clientdata(client);
	int current_now;

	current_now = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).adc2current_table,
		get_battery_data(fuelgauge).adc2current_table_size,
		adc_get_adc_value(fuelgauge, SEC_BAT_ADC_CHANNEL_CURRENT_NOW));

	if (!current_now) {
		psy_do_property("sec-charger", get,
			POWER_SUPPLY_PROP_CURRENT_NOW, value);
		current_now = value.intval;
	}

	return current_now;
}
static int get_cable_compensation_voltage(
	struct sec_fuelgauge_info *fuelgauge, int vcell)
{
	int comp_value;

	comp_value = 0;
	comp_value = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).cable_comp_voltage,
		get_battery_data(fuelgauge).cable_comp_voltage_size,
		vcell);

	/* no need to reset SOC with 0mA charging current */
	if (!fuelgauge->info.current_now)
		fuelgauge->info.reset_percentage = 0;

	/* rescale by charging current */
	comp_value = comp_value * fuelgauge->info.current_now / 1000;

	dev_dbg(&fuelgauge->client->dev,
		"%s: cable comp value (%dmV, current %dmA)\n", __func__,
		comp_value, fuelgauge->info.current_now);

	return comp_value;
}
static int adc_get_vcell(struct i2c_client *client)
{
	union power_supply_propval cable;
	union power_supply_propval event;
	union power_supply_propval is_charging;
	struct sec_fuelgauge_info *fuelgauge =
				i2c_get_clientdata(client);
	int vcell, vcell_raw;

	vcell = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).adc2vcell_table,
		get_battery_data(fuelgauge).adc2vcell_table_size,
		adc_get_adc_value(fuelgauge, SEC_BAT_ADC_CHANNEL_VOLTAGE_NOW));
	vcell_raw = vcell;

	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_ONLINE, cable);
	/* get current event status */
	event.intval = BATT_EVENT;
	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_TECHNOLOGY, event);
	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_CHARGE_NOW, is_charging);

	if (is_charging.intval != SEC_BATTERY_CHARGING_NONE) {
		/* compensate voltage by cable only in charging status */
		if (cable.intval != POWER_SUPPLY_TYPE_BATTERY)
			vcell += get_cable_compensation_voltage(
				fuelgauge, vcell);
	} else {
		/* need compensation before cable detection
		 * in power-off charging
		 */
		if ((cable.intval == POWER_SUPPLY_TYPE_BATTERY) &&
			(fuelgauge->pdata->is_lpm() ||
			fuelgauge->pdata->check_vbus_status())) {
			dev_dbg(&client->dev, "%s: VBUS compensation\n",
				__func__);
			vcell += get_cable_compensation_voltage(
				fuelgauge, vcell);
		}
	}

	if (event.intval) {
		if (fuelgauge->pdata->check_vbus_status() &&
			(event.intval & EVENT_BOOTING))
			dev_dbg(&client->dev, "%s: no event compensation "
				"in booting with charging\n", __func__);
		else
			vcell += get_event_compensation_voltage(
				fuelgauge, event.intval);
	}

#if defined(SEC_FUELGAUGE_ADC_DELTA_COMPENSATION)
	if (!fuelgauge->pdata->monitor_initial_count)
		vcell += get_delta_compensation_voltage(
			fuelgauge, vcell, vcell_raw);
#endif

	return vcell;
}
static int get_delta_compensation_voltage(
	struct sec_fuelgauge_info *fuelgauge, int vcell, int vcell_raw)
{
	int last_time, delta_time, delta_voltage_now, delta_current_now;
	int delta_voltage_now_in_sec, delta_compensation_voltage;

	delta_compensation_voltage = 0;
	last_time = fuelgauge->info.last_vcell_check_time.tv_sec;
	do_gettimeofday(&(fuelgauge->info.last_vcell_check_time));
	if (last_time) {
		delta_time = fuelgauge->info.last_vcell_check_time.tv_sec -
			last_time;

		if (delta_time > get_battery_data(fuelgauge).delta_reset_time) {
			dev_dbg(&fuelgauge->client->dev,
				"%s: reset delta compensation\n", __func__);
			delta_voltage_now = 0;
			delta_current_now = 0;
			fuelgauge->info.current_compensation = 0;
			goto no_delta_compensation;
		}

		/* to get compensation voltage,
		 * use raw vcell without compensation
		 */
		delta_compensation_voltage = adc_get_data_by_adc(fuelgauge,
			get_battery_data(fuelgauge).cable_comp_voltage,
			get_battery_data(fuelgauge).cable_comp_voltage_size,
			vcell_raw) * fuelgauge->info.current_compensation /
			1000;

		delta_voltage_now = vcell + delta_compensation_voltage -
			fuelgauge->info.voltage_now;

		fuelgauge->info.delta_voltage_now_in_sec =
			delta_voltage_now * 1000 / delta_time;

		if (delta_voltage_now < 0)
			delta_voltage_now_in_sec =
				-(fuelgauge->info.delta_voltage_now_in_sec);
		else
			delta_voltage_now_in_sec =
				fuelgauge->info.delta_voltage_now_in_sec;

		if ((delta_time <
			get_battery_data(fuelgauge).delta_check_time) &&
			(delta_voltage_now_in_sec >
			get_battery_data(fuelgauge).delta_comp_limit)) {
			/* to get delta current,
			 * use raw vcell without compensation
			 */
			delta_current_now = -(delta_voltage_now * 1000 /
				adc_get_data_by_adc(fuelgauge,
				get_battery_data(fuelgauge).cable_comp_voltage,
				get_battery_data(fuelgauge).cable_comp_voltage_size,
				vcell));

			/* to show compensation value, added minus */
			dev_dbg(&fuelgauge->client->dev,
				"%s: delta compensation (%dmA)\n",
				__func__, -delta_current_now);
			fuelgauge->info.current_compensation +=
				delta_current_now;

			/* to get compensation voltage,
			 * use raw vcell without compensation
			 */
			delta_compensation_voltage =
				adc_get_data_by_adc(fuelgauge,
				get_battery_data(fuelgauge).cable_comp_voltage,
				get_battery_data(fuelgauge).cable_comp_voltage_size,
				vcell_raw) *
				fuelgauge->info.current_compensation / 1000;
		} else
			delta_current_now =
				fuelgauge->info.current_compensation;

		if (!delta_compensation_voltage) {
			dev_dbg(&fuelgauge->client->dev,
				"%s: no need delta compensation "
				"vcell raw %dmV, comp vol %dmV, dv %dmV\n",
				__func__, vcell_raw, delta_compensation_voltage,
				delta_voltage_now);
			fuelgauge->info.current_compensation = 0;
		}

no_delta_compensation:
		dev_dbg(&fuelgauge->client->dev,
			"%s: dtime %dsec, dvoltage %dmV, dcurrent %dmA, "
			"dvoltage/sec %duV, delta comp voltage %dmV, "
			"compensation current %dmA\n",
			__func__, delta_time,
			delta_voltage_now, delta_current_now,
			fuelgauge->info.delta_voltage_now_in_sec,
			delta_compensation_voltage,
			fuelgauge->info.current_compensation);
	}

	return delta_compensation_voltage;
}