Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: supply: bq25890: Add support for having a secondary charger IC

Some devices, such as the Lenovo Yoga Tab 3 Pro (YT3-X90F) have multiple
batteries with a separate bq25890 charger for each battery.

This requires some coordination between the chargers specifically
the main charger needs to put the secondary charger in Hi-Z mode when:

1. Enabling its 5V boost (OTG) output to power an external USB device,
to avoid the secondary charger IC seeing this as external Vbus and
then trying to charge the secondary battery from this.

2. Talking the Pump Express protocol to increase the external Vbus voltage.
Having the secondary charger drawing current when the main charger is
trying to talk the Pump Express protocol results in the external Vbus
voltage not being raised.

Add a new "linux,secondary-charger-name" string device-property, which
can be set to the power_supply class device's name of the secondary
charger when there is a secondary charger; and make the Vbus regulator and
Pump Express code put the secondary charger in Hi-Z mode when necessary.

So far this new property is only used on x86/ACPI (non devicetree) devs,
IOW it is not used in actual devicetree files. The devicetree-bindings
maintainers have requested properties like these to not be added to the
devicetree-bindings, so the new property is deliberately not added
to the existing devicetree-bindings.

Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>

authored by

Hans de Goede and committed by
Sebastian Reichel
d54bf877 4e9498b8

+44 -1
+44 -1
drivers/power/supply/bq25890_charger.c
··· 108 108 struct i2c_client *client; 109 109 struct device *dev; 110 110 struct power_supply *charger; 111 + struct power_supply *secondary_chrg; 111 112 struct power_supply_desc desc; 112 113 char name[28]; /* "bq25890-charger-%d" */ 113 114 int id; ··· 1043 1042 { 1044 1043 struct bq25890_device *bq = 1045 1044 container_of(data, struct bq25890_device, pump_express_work.work); 1045 + union power_supply_propval value; 1046 1046 int voltage, i, ret; 1047 1047 1048 1048 dev_dbg(bq->dev, "Start to request input voltage increasing\n"); 1049 + 1050 + /* If there is a second charger put in Hi-Z mode */ 1051 + if (bq->secondary_chrg) { 1052 + value.intval = 0; 1053 + power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value); 1054 + } 1049 1055 1050 1056 /* Enable current pulse voltage control protocol */ 1051 1057 ret = bq25890_field_write(bq, F_PUMPX_EN, 1); ··· 1084 1076 } 1085 1077 1086 1078 bq25890_field_write(bq, F_PUMPX_EN, 0); 1079 + 1080 + if (bq->secondary_chrg) { 1081 + value.intval = 1; 1082 + power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value); 1083 + } 1087 1084 1088 1085 dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n", 1089 1086 voltage); ··· 1136 1123 static int bq25890_vbus_enable(struct regulator_dev *rdev) 1137 1124 { 1138 1125 struct bq25890_device *bq = rdev_get_drvdata(rdev); 1126 + union power_supply_propval val = { 1127 + .intval = 0, 1128 + }; 1129 + 1130 + /* 1131 + * When enabling 5V boost / Vbus output, we need to put the secondary 1132 + * charger in Hi-Z mode to avoid it trying to charge the secondary 1133 + * battery from the 5V boost output. 1134 + */ 1135 + if (bq->secondary_chrg) 1136 + power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val); 1139 1137 1140 1138 return bq25890_set_otg_cfg(bq, 1); 1141 1139 } ··· 1154 1130 static int bq25890_vbus_disable(struct regulator_dev *rdev) 1155 1131 { 1156 1132 struct bq25890_device *bq = rdev_get_drvdata(rdev); 1133 + union power_supply_propval val = { 1134 + .intval = 1, 1135 + }; 1136 + int ret; 1157 1137 1158 - return bq25890_set_otg_cfg(bq, 0); 1138 + ret = bq25890_set_otg_cfg(bq, 0); 1139 + if (ret) 1140 + return ret; 1141 + 1142 + if (bq->secondary_chrg) 1143 + power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val); 1144 + 1145 + return 0; 1159 1146 } 1160 1147 1161 1148 static int bq25890_vbus_is_enabled(struct regulator_dev *rdev) ··· 1377 1342 { 1378 1343 int ret; 1379 1344 struct bq25890_init_data *init = &bq->init_data; 1345 + const char *str; 1346 + 1347 + ret = device_property_read_string(bq->dev, "linux,secondary-charger-name", &str); 1348 + if (ret == 0) { 1349 + bq->secondary_chrg = power_supply_get_by_name(str); 1350 + if (!bq->secondary_chrg) 1351 + return -EPROBE_DEFER; 1352 + } 1380 1353 1381 1354 /* Optional, left at 0 if property is not present */ 1382 1355 device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",