@@ -51,6 +51,7 @@ enum sbs_capacity_mode {
CAPACITY_MODE_AMPS = 0,
CAPACITY_MODE_WATTS = BATTERY_MODE_CAPACITY_MASK
};
+#define BATTERY_MODE_CHARGER_MASK (1<<14)
/* manufacturer access defines */
#define MANUFACTURER_ACCESS_STATUS 0x0006
@@ -157,6 +158,7 @@ struct sbs_info {
bool is_present;
struct gpio_desc *gpio_detect;
bool enable_detection;
+ bool charger_broadcasts;
int last_state;
int poll_time;
u32 i2c_retry_count;
@@ -596,6 +598,34 @@ static int sbs_get_property_index(struct i2c_client *client,
return -EINVAL;
}
+static void sbs_disable_charger_broadcasts(struct sbs_info *chip)
+{
+ int val = sbs_read_word_data(chip->client, BATTERY_MODE_OFFSET);
+ if (val < 0)
+ goto exit;
+
+ val |= BATTERY_MODE_CHARGER_MASK;
+
+ val = sbs_write_word_data(chip->client, BATTERY_MODE_OFFSET, val);
+
+exit:
+ if (val < 0)
+ dev_err(&chip->client->dev,
+ "Failed to disable charger broadcasting: %d\n", val);
+ else
+ dev_dbg(&chip->client->dev, "%s\n", __func__);
+}
+
+static void sbs_set_is_present(struct sbs_info *chip, bool is_present)
+{
+ dev_dbg(&chip->client->dev, "%s %d\n", __func__, is_present);
+
+ if (!chip->is_present && is_present && !chip->charger_broadcasts)
+ sbs_disable_charger_broadcasts(chip);
+
+ chip->is_present = is_present;
+}
+
static int sbs_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -610,7 +640,7 @@ static int sbs_get_property(struct power_supply *psy,
return ret;
if (psp == POWER_SUPPLY_PROP_PRESENT) {
val->intval = ret;
- chip->is_present = val->intval;
+ sbs_set_is_present(chip, val->intval);
return 0;
}
if (ret == 0)
@@ -706,7 +736,7 @@ static int sbs_get_property(struct power_supply *psy,
if (!chip->gpio_detect &&
chip->is_present != (ret >= 0)) {
- chip->is_present = (ret >= 0);
+ sbs_set_is_present(chip, ret >= 0);
power_supply_changed(chip->power_supply);
}
@@ -737,7 +767,7 @@ static void sbs_supply_changed(struct sbs_info *chip)
ret = gpiod_get_value_cansleep(chip->gpio_detect);
if (ret < 0)
return;
- chip->is_present = ret;
+ sbs_set_is_present(chip, ret);
power_supply_changed(battery);
}
@@ -862,6 +892,9 @@ static int sbs_probe(struct i2c_client *client,
force_load = of_property_read_bool(client->dev.of_node,
"sbs,force-load");
+ chip->charger_broadcasts = !of_property_read_bool(client->dev.of_node,
+ "sbs,disable-charger-broadcasts");
+
chip->gpio_detect = devm_gpiod_get_optional(&client->dev,
"sbs,battery-detect", GPIOD_IN);
if (IS_ERR(chip->gpio_detect)) {
In certain designs, it is possible to add a battery on a populated i2c bus without an sbs compliant charger. In that case, the battery will un-necessarily and sometimes un-desirably master the bus trying to write info in the charger. It is observed in many occasion that these battery "broadcasts" are even corrupting other ongoing master to slave communication. I.e. the multi-master support in the battery is inadequate. Thankfully, the CHARGER_MODE bit allows designers to disable that SBS battery behaviour. This needs to be done once when the battery is first seen on the bus. Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com> --- drivers/power/supply/sbs-battery.c | 39 +++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)