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 38 REG_CYCLE_COUNT, 39 39 REG_SERIAL_NUMBER, 40 40 REG_REMAINING_CAPACITY, 41 + REG_REMAINING_CAPACITY_CHARGE, 41 42 REG_FULL_CHARGE_CAPACITY, 43 + REG_FULL_CHARGE_CAPACITY_CHARGE, 42 44 REG_DESIGN_CAPACITY, 45 + REG_DESIGN_CAPACITY_CHARGE, 43 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 44 55 }; 45 56 46 57 /* manufacturer access defines */ ··· 89 78 BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), 90 79 [REG_REMAINING_CAPACITY] = 91 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), 92 83 [REG_FULL_CHARGE_CAPACITY] = 93 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), 94 87 [REG_TIME_TO_EMPTY] = 95 88 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 96 89 65535), ··· 107 92 BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), 108 93 [REG_DESIGN_CAPACITY] = 109 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, 110 98 65535), 111 99 [REG_DESIGN_VOLTAGE] = 112 100 BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, ··· 135 117 POWER_SUPPLY_PROP_ENERGY_NOW, 136 118 POWER_SUPPLY_PROP_ENERGY_FULL, 137 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, 138 123 }; 139 124 140 125 struct bq20z75_info { ··· 281 260 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 282 261 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 283 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: 284 266 val->intval *= BASE_UNIT_CONVERSION; 285 267 break; 286 268 ··· 305 281 } 306 282 } 307 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 + 308 309 static int bq20z75_get_battery_capacity(struct i2c_client *client, 309 310 int reg_offset, enum power_supply_property psp, 310 311 union power_supply_propval *val) 311 312 { 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; 313 322 314 323 ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); 315 324 if (ret < 0) ··· 354 297 val->intval = min(ret, 100); 355 298 } else 356 299 val->intval = ret; 300 + 301 + ret = bq20z75_set_battery_mode(client, mode); 302 + if (ret < 0) 303 + return ret; 357 304 358 305 return 0; 359 306 } ··· 379 318 return 0; 380 319 } 381 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 + 382 335 static int bq20z75_get_property(struct power_supply *psy, 383 336 enum power_supply_property psp, 384 337 union power_supply_propval *val) 385 338 { 386 - int count; 339 + int ps_index; 387 340 int ret; 388 341 struct bq20z75_info *bq20z75_device = container_of(psy, 389 342 struct bq20z75_info, power_supply); ··· 418 343 case POWER_SUPPLY_PROP_ENERGY_NOW: 419 344 case POWER_SUPPLY_PROP_ENERGY_FULL: 420 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: 421 349 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 - } 350 + ps_index = bq20z75_get_property_index(client, psp); 351 + if (ps_index < 0) 352 + return ps_index; 426 353 427 - ret = bq20z75_get_battery_capacity(client, count, psp, val); 354 + ret = bq20z75_get_battery_capacity(client, ps_index, psp, val); 428 355 if (ret) 429 356 return ret; 430 357 ··· 446 369 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 447 370 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: 448 371 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 - } 372 + ps_index = bq20z75_get_property_index(client, psp); 373 + if (ps_index < 0) 374 + return ps_index; 453 375 454 - ret = bq20z75_get_battery_property(client, count, psp, val); 376 + ret = bq20z75_get_battery_property(client, ps_index, psp, val); 455 377 if (ret) 456 378 return ret; 457 379
+44
include/linux/power_supply.h
··· 213 213 /* For APM emulation, think legacy userspace. */ 214 214 extern struct class *power_supply_class; 215 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 + 216 260 #endif /* __LINUX_POWER_SUPPLY_H__ */