aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam Breck <liam@networkimprov.net>2017-01-18 12:26:53 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-14 08:00:15 -0400
commit7f2b4ad9c07af5291ff4b18548160b2816cda849 (patch)
tree8430ba6f3bf86b1e55635af0f0a102f13aff1858
parent4b7dac0a23b7c416b30962362268e8e55da9eaff (diff)
power: supply: bq24190_charger: Don't read fault register outside irq_handle_thread()
commit 68abfb8015832ddf728b911769659468efaf8bd9 upstream. Caching the fault register after a single I2C read may not keep an accurate value. Fix by doing two reads in irq_handle_thread() and using the cached value elsewhere. If a safety timer fault later clears itself, we apparently don't get an interrupt (INT), however other interrupts would refresh the register cache. From the data sheet: "When a fault occurs, the charger device sends out INT and keeps the fault state in REG09 until the host reads the fault register. Before the host reads REG09 and all the faults are cleared, the charger device would not send any INT upon new faults. In order to read the current fault status, the host has to read REG09 two times consecutively. The 1st reads fault register status from the last read [1] and the 2nd reads the current fault register status." [1] presumably a typo; should be "last fault" Fixes: d7bf353fd0aa3 ("bq24190_charger: Add support for TI BQ24190 Battery Charger") Signed-off-by: Liam Breck <kernel@networkimprov.net> Acked-by: Mark Greer <mgreer@animalcreek.com> Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Sebastian Reichel <sre@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/power/supply/bq24190_charger.c94
1 files changed, 27 insertions, 67 deletions
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 94d282286bfd..5659b831720f 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -144,10 +144,7 @@
144 * so the first read after a fault returns the latched value and subsequent 144 * so the first read after a fault returns the latched value and subsequent
145 * reads return the current value. In order to return the fault status 145 * reads return the current value. In order to return the fault status
146 * to the user, have the interrupt handler save the reg's value and retrieve 146 * to the user, have the interrupt handler save the reg's value and retrieve
147 * it in the appropriate health/status routine. Each routine has its own 147 * it in the appropriate health/status routine.
148 * flag indicating whether it should use the value stored by the last run
149 * of the interrupt handler or do an actual reg read. That way each routine
150 * can report back whatever fault may have occured.
151 */ 148 */
152struct bq24190_dev_info { 149struct bq24190_dev_info {
153 struct i2c_client *client; 150 struct i2c_client *client;
@@ -159,9 +156,6 @@ struct bq24190_dev_info {
159 unsigned int gpio_int; 156 unsigned int gpio_int;
160 unsigned int irq; 157 unsigned int irq;
161 struct mutex f_reg_lock; 158 struct mutex f_reg_lock;
162 bool charger_health_valid;
163 bool battery_health_valid;
164 bool battery_status_valid;
165 u8 f_reg; 159 u8 f_reg;
166 u8 ss_reg; 160 u8 ss_reg;
167 u8 watchdog; 161 u8 watchdog;
@@ -635,21 +629,11 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
635 union power_supply_propval *val) 629 union power_supply_propval *val)
636{ 630{
637 u8 v; 631 u8 v;
638 int health, ret; 632 int health;
639 633
640 mutex_lock(&bdi->f_reg_lock); 634 mutex_lock(&bdi->f_reg_lock);
641 635 v = bdi->f_reg;
642 if (bdi->charger_health_valid) { 636 mutex_unlock(&bdi->f_reg_lock);
643 v = bdi->f_reg;
644 bdi->charger_health_valid = false;
645 mutex_unlock(&bdi->f_reg_lock);
646 } else {
647 mutex_unlock(&bdi->f_reg_lock);
648
649 ret = bq24190_read(bdi, BQ24190_REG_F, &v);
650 if (ret < 0)
651 return ret;
652 }
653 637
654 if (v & BQ24190_REG_F_BOOST_FAULT_MASK) { 638 if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
655 /* 639 /*
@@ -936,18 +920,8 @@ static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
936 int status, ret; 920 int status, ret;
937 921
938 mutex_lock(&bdi->f_reg_lock); 922 mutex_lock(&bdi->f_reg_lock);
939 923 chrg_fault = bdi->f_reg;
940 if (bdi->battery_status_valid) { 924 mutex_unlock(&bdi->f_reg_lock);
941 chrg_fault = bdi->f_reg;
942 bdi->battery_status_valid = false;
943 mutex_unlock(&bdi->f_reg_lock);
944 } else {
945 mutex_unlock(&bdi->f_reg_lock);
946
947 ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
948 if (ret < 0)
949 return ret;
950 }
951 925
952 chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK; 926 chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
953 chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT; 927 chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
@@ -995,21 +969,11 @@ static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
995 union power_supply_propval *val) 969 union power_supply_propval *val)
996{ 970{
997 u8 v; 971 u8 v;
998 int health, ret; 972 int health;
999 973
1000 mutex_lock(&bdi->f_reg_lock); 974 mutex_lock(&bdi->f_reg_lock);
1001 975 v = bdi->f_reg;
1002 if (bdi->battery_health_valid) { 976 mutex_unlock(&bdi->f_reg_lock);
1003 v = bdi->f_reg;
1004 bdi->battery_health_valid = false;
1005 mutex_unlock(&bdi->f_reg_lock);
1006 } else {
1007 mutex_unlock(&bdi->f_reg_lock);
1008
1009 ret = bq24190_read(bdi, BQ24190_REG_F, &v);
1010 if (ret < 0)
1011 return ret;
1012 }
1013 977
1014 if (v & BQ24190_REG_F_BAT_FAULT_MASK) { 978 if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
1015 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 979 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
@@ -1201,7 +1165,7 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
1201 | BQ24190_REG_F_NTC_FAULT_MASK; 1165 | BQ24190_REG_F_NTC_FAULT_MASK;
1202 bool alert_charger = false, alert_battery = false; 1166 bool alert_charger = false, alert_battery = false;
1203 u8 ss_reg = 0, f_reg = 0; 1167 u8 ss_reg = 0, f_reg = 0;
1204 int ret; 1168 int i, ret;
1205 1169
1206 pm_runtime_get_sync(bdi->dev); 1170 pm_runtime_get_sync(bdi->dev);
1207 1171
@@ -1231,33 +1195,35 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
1231 alert_battery = true; 1195 alert_battery = true;
1232 if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss)) 1196 if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss))
1233 alert_charger = true; 1197 alert_charger = true;
1234
1235 bdi->ss_reg = ss_reg; 1198 bdi->ss_reg = ss_reg;
1236 } 1199 }
1237 1200
1238 mutex_lock(&bdi->f_reg_lock); 1201 i = 0;
1239 1202 do {
1240 ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg); 1203 ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
1241 if (ret < 0) { 1204 if (ret < 0) {
1242 mutex_unlock(&bdi->f_reg_lock); 1205 dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
1243 dev_err(bdi->dev, "Can't read F reg: %d\n", ret); 1206 goto out;
1244 goto out; 1207 }
1245 } 1208 } while (f_reg && ++i < 2);
1246 1209
1247 if (f_reg != bdi->f_reg) { 1210 if (f_reg != bdi->f_reg) {
1211 dev_info(bdi->dev,
1212 "Fault: boost %d, charge %d, battery %d, ntc %d\n",
1213 !!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK),
1214 !!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK),
1215 !!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK),
1216 !!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK));
1217
1218 mutex_lock(&bdi->f_reg_lock);
1248 if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f)) 1219 if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f))
1249 alert_battery = true; 1220 alert_battery = true;
1250 if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f)) 1221 if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f))
1251 alert_charger = true; 1222 alert_charger = true;
1252
1253 bdi->f_reg = f_reg; 1223 bdi->f_reg = f_reg;
1254 bdi->charger_health_valid = true; 1224 mutex_unlock(&bdi->f_reg_lock);
1255 bdi->battery_health_valid = true;
1256 bdi->battery_status_valid = true;
1257 } 1225 }
1258 1226
1259 mutex_unlock(&bdi->f_reg_lock);
1260
1261 if (alert_charger) 1227 if (alert_charger)
1262 power_supply_changed(bdi->charger); 1228 power_supply_changed(bdi->charger);
1263 if (alert_battery) 1229 if (alert_battery)
@@ -1377,9 +1343,6 @@ static int bq24190_probe(struct i2c_client *client,
1377 mutex_init(&bdi->f_reg_lock); 1343 mutex_init(&bdi->f_reg_lock);
1378 bdi->f_reg = 0; 1344 bdi->f_reg = 0;
1379 bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ 1345 bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
1380 bdi->charger_health_valid = false;
1381 bdi->battery_health_valid = false;
1382 bdi->battery_status_valid = false;
1383 1346
1384 i2c_set_clientdata(client, bdi); 1347 i2c_set_clientdata(client, bdi);
1385 1348
@@ -1492,9 +1455,6 @@ static int bq24190_pm_resume(struct device *dev)
1492 1455
1493 bdi->f_reg = 0; 1456 bdi->f_reg = 0;
1494 bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ 1457 bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
1495 bdi->charger_health_valid = false;
1496 bdi->battery_health_valid = false;
1497 bdi->battery_status_valid = false;
1498 1458
1499 pm_runtime_get_sync(bdi->dev); 1459 pm_runtime_get_sync(bdi->dev);
1500 bq24190_register_reset(bdi); 1460 bq24190_register_reset(bdi);