Commit 1f918e0f authored by Linus Walleij's avatar Linus Walleij Committed by Sebastian Reichel
Browse files

power: supply: ab8500: Standardize BTI resistance



The Battery Type Indicator (BTI) resistor is a resistor mounted
between a special terminal on the battery and ground. By sending
a fixed current (such as 7mA) through this resistor and measuring
the voltage over it, the resistance can be determined, and this
verifies the battery type.

Typical side view of the battery:

  o     o     o
 GND   BTI   +3.8V

Typical example of the electrical layout:

  +3.8 V   BTI
    |       |
    | +     |
 _______   [ ] 7kOhm
   ___      |
    |       |
    |       |
   GND     GND

By verifying this resistance before attempting to charge the
battery we add an additional level of security.

In some systems this is used for plug-and-play of batteries with
different capacity. In other cases, this is merely used to verify
that the right type of battery is connected, if several batteries
have the same physical shape and can be plugged into the same
slot. Sometimes this is just a surplus security mechanism.

Nokia and Samsung among many other vendors are known to use these
BTI resistors.

Add the BTI properties to struct power_supply_battery_info and
switch the AB8500 charger code over to using it.

Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent 0e8b903b
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -327,16 +327,6 @@ struct ab8500_maxim_parameters {
	int charger_curr_step_ua;
};

/**
 * struct ab8500_battery_type - different batteries supported
 * @resis_high:			battery upper resistance limit
 * @resis_low:			battery lower resistance limit
 */
struct ab8500_battery_type {
	int resis_high;
	int resis_low;
};

/**
 * struct ab8500_bm_capacity_levels - ab8500 capacity level data
 * @critical:		critical capacity level in percent
@@ -387,7 +377,6 @@ struct ab8500_bm_charger_parameters {
 * @temp_hysteresis	temperature hysteresis
 * @maxi		maximization parameters
 * @cap_levels		capacity in percent for the different capacity levels
 * @bat_type		table of supported battery types
 * @chg_params		charger parameters
 * @fg_params		fuel gauge parameters
 */
@@ -410,7 +399,6 @@ struct ab8500_bm_data {
	int temp_hysteresis;
	const struct ab8500_maxim_parameters *maxi;
	const struct ab8500_bm_capacity_levels *cap_levels;
	struct ab8500_battery_type *bat_type;
	const struct ab8500_bm_charger_parameters *chg_params;
	const struct ab8500_fg_parameters *fg_params;
};
+7 −7
Original line number Diff line number Diff line
@@ -73,12 +73,6 @@ static struct power_supply_maintenance_charge_table ab8500_maint_charg_table[] =
	}
};

/* Default battery type for reference designs is the unknown type */
static struct ab8500_battery_type bat_type_thermistor_unknown = {
	.resis_high = 0,
	.resis_low = 0,
};

static const struct ab8500_bm_capacity_levels cap_levels = {
	.critical	= 2,
	.low		= 10,
@@ -136,7 +130,6 @@ struct ab8500_bm_data ab8500_bm_data = {
	.enable_overshoot       = false,
	.fg_res                 = 100,
	.cap_levels             = &cap_levels,
	.bat_type               = &bat_type_thermistor_unknown,
	.interval_charging      = 5,
	.interval_not_charging  = 120,
	.maxi                   = &ab8500_maxi_params,
@@ -214,6 +207,13 @@ int ab8500_bm_of_probe(struct power_supply *psy,
		bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor);
	}

	/* The default battery is emulated by a resistor at 7K */
	if (bi->bti_resistance_ohm < 0 ||
	    bi->bti_resistance_tolerance < 0) {
		bi->bti_resistance_ohm = 7000;
		bi->bti_resistance_tolerance = 20;
	}

	if (!bi->ocv_table[0]) {
		/* Default capacity table at say 25 degrees Celsius */
		bi->ocv_temp[0] = 25;
+6 −8
Original line number Diff line number Diff line
@@ -237,8 +237,8 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
 */
static int ab8500_btemp_id(struct ab8500_btemp *di)
{
	struct power_supply_battery_info *bi = di->bm->bi;
	int res;
	u8 i;

	di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;

@@ -248,13 +248,11 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
		return -ENXIO;
	}

	if ((res <= di->bm->bat_type->resis_high) &&
	    (res >= di->bm->bat_type->resis_low)) {
		dev_info(di->dev, "Battery detected on BATTEMP"
			 " low %d < res %d < high: %d"
			 " index: %d\n",
			 di->bm->bat_type->resis_low, res,
			 di->bm->bat_type->resis_high, i);
	if (power_supply_battery_bti_in_range(bi, res)) {
		dev_info(di->dev, "Battery detected on BATCTRL (pin C3)"
			 " resistance %d Ohm = %d Ohm +/- %d%%\n",
			 res, bi->bti_resistance_ohm,
			 bi->bti_resistance_tolerance);
	} else {
		dev_warn(di->dev, "Battery identified as unknown"
			 ", resistance %d Ohm\n", res);
+0 −4
Original line number Diff line number Diff line
@@ -2241,10 +2241,6 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
				if (!di->flags.batt_id_received &&
				    (bi && (bi->technology !=
					    POWER_SUPPLY_TECHNOLOGY_UNKNOWN))) {
					const struct ab8500_battery_type *b;

					b = di->bm->bat_type;

					di->flags.batt_id_received = true;

					di->bat_cap.max_mah_design =
+25 −1
Original line number Diff line number Diff line
@@ -608,6 +608,8 @@ int power_supply_get_battery_info(struct power_supply *psy,
	info->temp_max                       = INT_MAX;
	info->factory_internal_resistance_uohm  = -EINVAL;
	info->resist_table                   = NULL;
	info->bti_resistance_ohm             = -EINVAL;
	info->bti_resistance_tolerance       = -EINVAL;

	for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
		info->ocv_table[index]       = NULL;
@@ -938,6 +940,28 @@ int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info,
}
EXPORT_SYMBOL_GPL(power_supply_batinfo_ocv2cap);

bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
				       int resistance)
{
	int low, high;

	/* Nothing like this can be checked */
	if (info->bti_resistance_ohm <= 0)
		return false;

	/* This will be extremely strict and unlikely to work */
	if (info->bti_resistance_tolerance <= 0)
		return (info->bti_resistance_ohm == resistance);

	low = info->bti_resistance_ohm -
		(info->bti_resistance_ohm * info->bti_resistance_tolerance) / 100;
	high = info->bti_resistance_ohm +
		(info->bti_resistance_ohm * info->bti_resistance_tolerance) / 100;

	return ((resistance >= low) && (resistance <= high));
}
EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range);

int power_supply_get_property(struct power_supply *psy,
			    enum power_supply_property psp,
			    union power_supply_propval *val)
Loading