bq20z75: Add support for charge properties

Adding support for charge properties for gas gauge.

Also ensuring that battery mode is correct now for energy as well as
charge properties by setting it on the fly.

I also added 2 functions to power_supply.h to help identify the units for
specific properties more easily by power supplies.

Signed-off-by: Rhyland Klein <rklein@nvidia.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>

authored by

Rhyland Klein and committed by
Anton Vorontsov
51d07566 1bae4ce2

+131 -11
+87 -11
drivers/power/bq20z75.c
··· 38 REG_CYCLE_COUNT, 39 REG_SERIAL_NUMBER, 40 REG_REMAINING_CAPACITY, 41 REG_FULL_CHARGE_CAPACITY, 42 REG_DESIGN_CAPACITY, 43 REG_DESIGN_VOLTAGE, 44 }; 45 46 /* manufacturer access defines */ ··· 89 BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), 90 [REG_REMAINING_CAPACITY] = 91 BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), 92 [REG_FULL_CHARGE_CAPACITY] = 93 BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), 94 [REG_TIME_TO_EMPTY] = 95 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 96 65535), ··· 107 BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), 108 [REG_DESIGN_CAPACITY] = 109 BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 110 65535), 111 [REG_DESIGN_VOLTAGE] = 112 BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, ··· 135 POWER_SUPPLY_PROP_ENERGY_NOW, 136 POWER_SUPPLY_PROP_ENERGY_FULL, 137 POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 138 }; 139 140 struct bq20z75_info { ··· 281 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 282 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 283 case POWER_SUPPLY_PROP_CURRENT_NOW: 284 val->intval *= BASE_UNIT_CONVERSION; 285 break; 286 ··· 305 } 306 } 307 308 static int bq20z75_get_battery_capacity(struct i2c_client *client, 309 int reg_offset, enum power_supply_property psp, 310 union power_supply_propval *val) 311 { 312 s32 ret; 313 314 ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); 315 if (ret < 0) ··· 354 val->intval = min(ret, 100); 355 } else 356 val->intval = ret; 357 358 return 0; 359 } ··· 379 return 0; 380 } 381 382 static int bq20z75_get_property(struct power_supply *psy, 383 enum power_supply_property psp, 384 union power_supply_propval *val) 385 { 386 - int count; 387 int ret; 388 struct bq20z75_info *bq20z75_device = container_of(psy, 389 struct bq20z75_info, power_supply); ··· 418 case POWER_SUPPLY_PROP_ENERGY_NOW: 419 case POWER_SUPPLY_PROP_ENERGY_FULL: 420 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 421 case POWER_SUPPLY_PROP_CAPACITY: 422 - for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { 423 - if (psp == bq20z75_data[count].psp) 424 - break; 425 - } 426 427 - ret = bq20z75_get_battery_capacity(client, count, psp, val); 428 if (ret) 429 return ret; 430 ··· 446 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 447 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: 448 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 449 - for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { 450 - if (psp == bq20z75_data[count].psp) 451 - break; 452 - } 453 454 - ret = bq20z75_get_battery_property(client, count, psp, val); 455 if (ret) 456 return ret; 457
··· 38 REG_CYCLE_COUNT, 39 REG_SERIAL_NUMBER, 40 REG_REMAINING_CAPACITY, 41 + REG_REMAINING_CAPACITY_CHARGE, 42 REG_FULL_CHARGE_CAPACITY, 43 + REG_FULL_CHARGE_CAPACITY_CHARGE, 44 REG_DESIGN_CAPACITY, 45 + REG_DESIGN_CAPACITY_CHARGE, 46 REG_DESIGN_VOLTAGE, 47 + }; 48 + 49 + /* Battery Mode defines */ 50 + #define BATTERY_MODE_OFFSET 0x03 51 + #define BATTERY_MODE_MASK 0x8000 52 + enum bq20z75_battery_mode { 53 + BATTERY_MODE_AMPS, 54 + BATTERY_MODE_WATTS 55 }; 56 57 /* manufacturer access defines */ ··· 78 BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), 79 [REG_REMAINING_CAPACITY] = 80 BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), 81 + [REG_REMAINING_CAPACITY_CHARGE] = 82 + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), 83 [REG_FULL_CHARGE_CAPACITY] = 84 BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), 85 + [REG_FULL_CHARGE_CAPACITY_CHARGE] = 86 + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), 87 [REG_TIME_TO_EMPTY] = 88 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 89 65535), ··· 92 BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), 93 [REG_DESIGN_CAPACITY] = 94 BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 95 + 65535), 96 + [REG_DESIGN_CAPACITY_CHARGE] = 97 + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, 98 65535), 99 [REG_DESIGN_VOLTAGE] = 100 BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, ··· 117 POWER_SUPPLY_PROP_ENERGY_NOW, 118 POWER_SUPPLY_PROP_ENERGY_FULL, 119 POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 120 + POWER_SUPPLY_PROP_CHARGE_NOW, 121 + POWER_SUPPLY_PROP_CHARGE_FULL, 122 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 123 }; 124 125 struct bq20z75_info { ··· 260 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 261 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 262 case POWER_SUPPLY_PROP_CURRENT_NOW: 263 + case POWER_SUPPLY_PROP_CHARGE_NOW: 264 + case POWER_SUPPLY_PROP_CHARGE_FULL: 265 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 266 val->intval *= BASE_UNIT_CONVERSION; 267 break; 268 ··· 281 } 282 } 283 284 + static enum bq20z75_battery_mode 285 + bq20z75_set_battery_mode(struct i2c_client *client, 286 + enum bq20z75_battery_mode mode) 287 + { 288 + int ret, original_val; 289 + 290 + original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET); 291 + if (original_val < 0) 292 + return original_val; 293 + 294 + if ((original_val & BATTERY_MODE_MASK) == mode) 295 + return mode; 296 + 297 + if (mode == BATTERY_MODE_AMPS) 298 + ret = original_val & ~BATTERY_MODE_MASK; 299 + else 300 + ret = original_val | BATTERY_MODE_MASK; 301 + 302 + ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret); 303 + if (ret < 0) 304 + return ret; 305 + 306 + return original_val & BATTERY_MODE_MASK; 307 + } 308 + 309 static int bq20z75_get_battery_capacity(struct i2c_client *client, 310 int reg_offset, enum power_supply_property psp, 311 union power_supply_propval *val) 312 { 313 s32 ret; 314 + enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS; 315 + 316 + if (power_supply_is_amp_property(psp)) 317 + mode = BATTERY_MODE_AMPS; 318 + 319 + mode = bq20z75_set_battery_mode(client, mode); 320 + if (mode < 0) 321 + return mode; 322 323 ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); 324 if (ret < 0) ··· 297 val->intval = min(ret, 100); 298 } else 299 val->intval = ret; 300 + 301 + ret = bq20z75_set_battery_mode(client, mode); 302 + if (ret < 0) 303 + return ret; 304 305 return 0; 306 } ··· 318 return 0; 319 } 320 321 + static int bq20z75_get_property_index(struct i2c_client *client, 322 + enum power_supply_property psp) 323 + { 324 + int count; 325 + for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) 326 + if (psp == bq20z75_data[count].psp) 327 + return count; 328 + 329 + dev_warn(&client->dev, 330 + "%s: Invalid Property - %d\n", __func__, psp); 331 + 332 + return -EINVAL; 333 + } 334 + 335 static int bq20z75_get_property(struct power_supply *psy, 336 enum power_supply_property psp, 337 union power_supply_propval *val) 338 { 339 + int ps_index; 340 int ret; 341 struct bq20z75_info *bq20z75_device = container_of(psy, 342 struct bq20z75_info, power_supply); ··· 343 case POWER_SUPPLY_PROP_ENERGY_NOW: 344 case POWER_SUPPLY_PROP_ENERGY_FULL: 345 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 346 + case POWER_SUPPLY_PROP_CHARGE_NOW: 347 + case POWER_SUPPLY_PROP_CHARGE_FULL: 348 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 349 case POWER_SUPPLY_PROP_CAPACITY: 350 + ps_index = bq20z75_get_property_index(client, psp); 351 + if (ps_index < 0) 352 + return ps_index; 353 354 + ret = bq20z75_get_battery_capacity(client, ps_index, psp, val); 355 if (ret) 356 return ret; 357 ··· 369 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 370 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: 371 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 372 + ps_index = bq20z75_get_property_index(client, psp); 373 + if (ps_index < 0) 374 + return ps_index; 375 376 + ret = bq20z75_get_battery_property(client, ps_index, psp, val); 377 if (ret) 378 return ret; 379
+44
include/linux/power_supply.h
··· 213 /* For APM emulation, think legacy userspace. */ 214 extern struct class *power_supply_class; 215 216 #endif /* __LINUX_POWER_SUPPLY_H__ */
··· 213 /* For APM emulation, think legacy userspace. */ 214 extern struct class *power_supply_class; 215 216 + static inline bool power_supply_is_amp_property(enum power_supply_property psp) 217 + { 218 + switch (psp) { 219 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 220 + case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: 221 + case POWER_SUPPLY_PROP_CHARGE_FULL: 222 + case POWER_SUPPLY_PROP_CHARGE_EMPTY: 223 + case POWER_SUPPLY_PROP_CHARGE_NOW: 224 + case POWER_SUPPLY_PROP_CHARGE_AVG: 225 + case POWER_SUPPLY_PROP_CHARGE_COUNTER: 226 + case POWER_SUPPLY_PROP_CURRENT_MAX: 227 + case POWER_SUPPLY_PROP_CURRENT_NOW: 228 + case POWER_SUPPLY_PROP_CURRENT_AVG: 229 + return 1; 230 + default: 231 + break; 232 + } 233 + 234 + return 0; 235 + } 236 + 237 + static inline bool power_supply_is_watt_property(enum power_supply_property psp) 238 + { 239 + switch (psp) { 240 + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 241 + case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: 242 + case POWER_SUPPLY_PROP_ENERGY_FULL: 243 + case POWER_SUPPLY_PROP_ENERGY_EMPTY: 244 + case POWER_SUPPLY_PROP_ENERGY_NOW: 245 + case POWER_SUPPLY_PROP_ENERGY_AVG: 246 + case POWER_SUPPLY_PROP_VOLTAGE_MAX: 247 + case POWER_SUPPLY_PROP_VOLTAGE_MIN: 248 + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 249 + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 250 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 251 + case POWER_SUPPLY_PROP_VOLTAGE_AVG: 252 + return 1; 253 + default: 254 + break; 255 + } 256 + 257 + return 0; 258 + } 259 + 260 #endif /* __LINUX_POWER_SUPPLY_H__ */