| .. | .. |
|---|
| 33 | 33 | #include <linux/iio/types.h> |
|---|
| 34 | 34 | #include <linux/mfd/motorola-cpcap.h> |
|---|
| 35 | 35 | |
|---|
| 36 | | -#include <asm/div64.h> |
|---|
| 37 | | - |
|---|
| 38 | 36 | /* |
|---|
| 39 | 37 | * Register bit defines for CPCAP_REG_BPEOL. Some of these seem to |
|---|
| 40 | 38 | * map to MC13783UG.pdf "Table 5-19. Register 13, Power Control 0" |
|---|
| .. | .. |
|---|
| 52 | 50 | #define CPCAP_REG_BPEOL_BIT_BATTDETEN BIT(1) /* Enable battery detect */ |
|---|
| 53 | 51 | #define CPCAP_REG_BPEOL_BIT_EOLSEL BIT(0) /* BPDET = 0, EOL = 1 */ |
|---|
| 54 | 52 | |
|---|
| 53 | +/* |
|---|
| 54 | + * Register bit defines for CPCAP_REG_CCC1. These seem similar to the twl6030 |
|---|
| 55 | + * coulomb counter registers rather than the mc13892 registers. Both twl6030 |
|---|
| 56 | + * and mc13892 set bits 2 and 1 to reset and clear registers. But mc13892 |
|---|
| 57 | + * sets bit 0 to start the coulomb counter while twl6030 sets bit 0 to stop |
|---|
| 58 | + * the coulomb counter like cpcap does. So for now, we use the twl6030 style |
|---|
| 59 | + * naming for the registers. |
|---|
| 60 | + */ |
|---|
| 61 | +#define CPCAP_REG_CCC1_ACTIVE_MODE1 BIT(4) /* Update rate */ |
|---|
| 62 | +#define CPCAP_REG_CCC1_ACTIVE_MODE0 BIT(3) /* Update rate */ |
|---|
| 63 | +#define CPCAP_REG_CCC1_AUTOCLEAR BIT(2) /* Resets sample registers */ |
|---|
| 64 | +#define CPCAP_REG_CCC1_CAL_EN BIT(1) /* Clears after write in 1s */ |
|---|
| 65 | +#define CPCAP_REG_CCC1_PAUSE BIT(0) /* Stop counters, allow write */ |
|---|
| 66 | +#define CPCAP_REG_CCC1_RESET_MASK (CPCAP_REG_CCC1_AUTOCLEAR | \ |
|---|
| 67 | + CPCAP_REG_CCC1_CAL_EN) |
|---|
| 68 | + |
|---|
| 69 | +#define CPCAP_REG_CCCC2_RATE1 BIT(5) |
|---|
| 70 | +#define CPCAP_REG_CCCC2_RATE0 BIT(4) |
|---|
| 71 | +#define CPCAP_REG_CCCC2_ENABLE BIT(3) |
|---|
| 72 | + |
|---|
| 55 | 73 | #define CPCAP_BATTERY_CC_SAMPLE_PERIOD_MS 250 |
|---|
| 56 | 74 | |
|---|
| 57 | 75 | enum { |
|---|
| .. | .. |
|---|
| 64 | 82 | |
|---|
| 65 | 83 | enum cpcap_battery_irq_action { |
|---|
| 66 | 84 | CPCAP_BATTERY_IRQ_ACTION_NONE, |
|---|
| 85 | + CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE, |
|---|
| 67 | 86 | CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW, |
|---|
| 68 | 87 | CPCAP_BATTERY_IRQ_ACTION_POWEROFF, |
|---|
| 69 | 88 | }; |
|---|
| .. | .. |
|---|
| 76 | 95 | }; |
|---|
| 77 | 96 | |
|---|
| 78 | 97 | struct cpcap_battery_config { |
|---|
| 79 | | - int ccm; |
|---|
| 80 | 98 | int cd_factor; |
|---|
| 81 | 99 | struct power_supply_info info; |
|---|
| 100 | + struct power_supply_battery_info bat; |
|---|
| 82 | 101 | }; |
|---|
| 83 | 102 | |
|---|
| 84 | 103 | struct cpcap_coulomb_counter_data { |
|---|
| 85 | 104 | s32 sample; /* 24 or 32 bits */ |
|---|
| 86 | 105 | s32 accumulator; |
|---|
| 87 | | - s16 offset; /* 10-bits */ |
|---|
| 106 | + s16 offset; /* 9 bits */ |
|---|
| 107 | + s16 integrator; /* 13 or 16 bits */ |
|---|
| 88 | 108 | }; |
|---|
| 89 | 109 | |
|---|
| 90 | 110 | enum cpcap_battery_state { |
|---|
| .. | .. |
|---|
| 110 | 130 | struct power_supply *psy; |
|---|
| 111 | 131 | struct cpcap_battery_config config; |
|---|
| 112 | 132 | struct cpcap_battery_state_data state[CPCAP_BATTERY_STATE_NR]; |
|---|
| 133 | + u32 cc_lsb; /* μAms per LSB */ |
|---|
| 113 | 134 | atomic_t active; |
|---|
| 114 | 135 | int status; |
|---|
| 115 | 136 | u16 vendor; |
|---|
| .. | .. |
|---|
| 217 | 238 | s16 offset, u32 divider) |
|---|
| 218 | 239 | { |
|---|
| 219 | 240 | s64 acc; |
|---|
| 220 | | - u64 tmp; |
|---|
| 221 | | - int avg_current; |
|---|
| 222 | | - u32 cc_lsb; |
|---|
| 223 | 241 | |
|---|
| 224 | 242 | if (!divider) |
|---|
| 225 | 243 | return 0; |
|---|
| 226 | 244 | |
|---|
| 227 | | - offset &= 0x7ff; /* 10-bits, signed */ |
|---|
| 228 | | - |
|---|
| 229 | | - switch (ddata->vendor) { |
|---|
| 230 | | - case CPCAP_VENDOR_ST: |
|---|
| 231 | | - cc_lsb = 95374; /* μAms per LSB */ |
|---|
| 232 | | - break; |
|---|
| 233 | | - case CPCAP_VENDOR_TI: |
|---|
| 234 | | - cc_lsb = 91501; /* μAms per LSB */ |
|---|
| 235 | | - break; |
|---|
| 236 | | - default: |
|---|
| 237 | | - return -EINVAL; |
|---|
| 238 | | - } |
|---|
| 239 | | - |
|---|
| 240 | 245 | acc = accumulator; |
|---|
| 241 | | - acc = acc - ((s64)sample * offset); |
|---|
| 242 | | - cc_lsb = (cc_lsb * ddata->config.cd_factor) / 1000; |
|---|
| 246 | + acc -= (s64)sample * offset; |
|---|
| 247 | + acc *= ddata->cc_lsb; |
|---|
| 248 | + acc *= -1; |
|---|
| 249 | + acc = div_s64(acc, divider); |
|---|
| 243 | 250 | |
|---|
| 244 | | - if (acc >= 0) |
|---|
| 245 | | - tmp = acc; |
|---|
| 246 | | - else |
|---|
| 247 | | - tmp = acc * -1; |
|---|
| 248 | | - |
|---|
| 249 | | - tmp = tmp * cc_lsb; |
|---|
| 250 | | - do_div(tmp, divider); |
|---|
| 251 | | - avg_current = tmp; |
|---|
| 252 | | - |
|---|
| 253 | | - if (acc >= 0) |
|---|
| 254 | | - return -avg_current; |
|---|
| 255 | | - else |
|---|
| 256 | | - return avg_current; |
|---|
| 251 | + return acc; |
|---|
| 257 | 252 | } |
|---|
| 258 | 253 | |
|---|
| 259 | 254 | /* 3600000μAms = 1μAh */ |
|---|
| .. | .. |
|---|
| 279 | 274 | /** |
|---|
| 280 | 275 | * cpcap_battery_read_accumulated - reads cpcap coulomb counter |
|---|
| 281 | 276 | * @ddata: device driver data |
|---|
| 282 | | - * @regs: coulomb counter values |
|---|
| 277 | + * @ccd: coulomb counter values |
|---|
| 283 | 278 | * |
|---|
| 284 | 279 | * Based on Motorola mapphone kernel function data_read_regs(). |
|---|
| 285 | 280 | * Looking at the registers, the coulomb counter seems similar to |
|---|
| .. | .. |
|---|
| 295 | 290 | cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata, |
|---|
| 296 | 291 | struct cpcap_coulomb_counter_data *ccd) |
|---|
| 297 | 292 | { |
|---|
| 298 | | - u16 buf[7]; /* CPCAP_REG_CC1 to CCI */ |
|---|
| 293 | + u16 buf[7]; /* CPCAP_REG_CCS1 to CCI */ |
|---|
| 299 | 294 | int error; |
|---|
| 300 | 295 | |
|---|
| 301 | 296 | ccd->sample = 0; |
|---|
| 302 | 297 | ccd->accumulator = 0; |
|---|
| 303 | 298 | ccd->offset = 0; |
|---|
| 299 | + ccd->integrator = 0; |
|---|
| 304 | 300 | |
|---|
| 305 | 301 | /* Read coulomb counter register range */ |
|---|
| 306 | 302 | error = regmap_bulk_read(ddata->reg, CPCAP_REG_CCS1, |
|---|
| .. | .. |
|---|
| 318 | 314 | ccd->accumulator = ((s16)buf[3]) << 16; |
|---|
| 319 | 315 | ccd->accumulator |= buf[2]; |
|---|
| 320 | 316 | |
|---|
| 321 | | - /* Offset value CPCAP_REG_CCO */ |
|---|
| 322 | | - ccd->offset = buf[5]; |
|---|
| 317 | + /* |
|---|
| 318 | + * Coulomb counter calibration offset is CPCAP_REG_CCM, |
|---|
| 319 | + * REG_CCO seems unused |
|---|
| 320 | + */ |
|---|
| 321 | + ccd->offset = buf[4]; |
|---|
| 322 | + ccd->offset = sign_extend32(ccd->offset, 9); |
|---|
| 323 | 323 | |
|---|
| 324 | | - /* Adjust offset based on mode value CPCAP_REG_CCM? */ |
|---|
| 325 | | - if (buf[4] >= 0x200) |
|---|
| 326 | | - ccd->offset |= 0xfc00; |
|---|
| 324 | + /* Integrator register CPCAP_REG_CCI */ |
|---|
| 325 | + if (ddata->vendor == CPCAP_VENDOR_TI) |
|---|
| 326 | + ccd->integrator = sign_extend32(buf[6], 13); |
|---|
| 327 | + else |
|---|
| 328 | + ccd->integrator = (s16)buf[6]; |
|---|
| 327 | 329 | |
|---|
| 328 | 330 | return cpcap_battery_cc_to_uah(ddata, |
|---|
| 329 | 331 | ccd->sample, |
|---|
| .. | .. |
|---|
| 338 | 340 | static int cpcap_battery_cc_get_avg_current(struct cpcap_battery_ddata *ddata) |
|---|
| 339 | 341 | { |
|---|
| 340 | 342 | int value, acc, error; |
|---|
| 341 | | - s32 sample = 1; |
|---|
| 343 | + s32 sample; |
|---|
| 342 | 344 | s16 offset; |
|---|
| 343 | | - |
|---|
| 344 | | - if (ddata->vendor == CPCAP_VENDOR_ST) |
|---|
| 345 | | - sample = 4; |
|---|
| 346 | 345 | |
|---|
| 347 | 346 | /* Coulomb counter integrator */ |
|---|
| 348 | 347 | error = regmap_read(ddata->reg, CPCAP_REG_CCI, &value); |
|---|
| 349 | 348 | if (error) |
|---|
| 350 | 349 | return error; |
|---|
| 351 | 350 | |
|---|
| 352 | | - if ((ddata->vendor == CPCAP_VENDOR_TI) && (value > 0x2000)) |
|---|
| 353 | | - value = value | 0xc000; |
|---|
| 351 | + if (ddata->vendor == CPCAP_VENDOR_TI) { |
|---|
| 352 | + acc = sign_extend32(value, 13); |
|---|
| 353 | + sample = 1; |
|---|
| 354 | + } else { |
|---|
| 355 | + acc = (s16)value; |
|---|
| 356 | + sample = 4; |
|---|
| 357 | + } |
|---|
| 354 | 358 | |
|---|
| 355 | | - acc = (s16)value; |
|---|
| 356 | | - |
|---|
| 357 | | - /* Coulomb counter sample time */ |
|---|
| 359 | + /* Coulomb counter calibration offset */ |
|---|
| 358 | 360 | error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); |
|---|
| 359 | 361 | if (error) |
|---|
| 360 | 362 | return error; |
|---|
| 361 | 363 | |
|---|
| 362 | | - if (value < 0x200) |
|---|
| 363 | | - offset = value; |
|---|
| 364 | | - else |
|---|
| 365 | | - offset = value | 0xfc00; |
|---|
| 364 | + offset = sign_extend32(value, 9); |
|---|
| 366 | 365 | |
|---|
| 367 | 366 | return cpcap_battery_cc_to_ua(ddata, sample, acc, offset); |
|---|
| 368 | 367 | } |
|---|
| .. | .. |
|---|
| 371 | 370 | { |
|---|
| 372 | 371 | struct cpcap_battery_state_data *state = cpcap_battery_latest(ddata); |
|---|
| 373 | 372 | |
|---|
| 374 | | - /* Basically anything that measures above 4347000 is full */ |
|---|
| 375 | | - if (state->voltage >= (ddata->config.info.voltage_max_design - 4000)) |
|---|
| 373 | + if (state->voltage >= |
|---|
| 374 | + (ddata->config.bat.constant_charge_voltage_max_uv - 18000)) |
|---|
| 376 | 375 | return true; |
|---|
| 377 | 376 | |
|---|
| 378 | 377 | return false; |
|---|
| .. | .. |
|---|
| 419 | 418 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
|---|
| 420 | 419 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, |
|---|
| 421 | 420 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
|---|
| 421 | + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, |
|---|
| 422 | 422 | POWER_SUPPLY_PROP_CURRENT_AVG, |
|---|
| 423 | 423 | POWER_SUPPLY_PROP_CURRENT_NOW, |
|---|
| 424 | 424 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
|---|
| .. | .. |
|---|
| 477 | 477 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
|---|
| 478 | 478 | val->intval = ddata->config.info.voltage_min_design; |
|---|
| 479 | 479 | break; |
|---|
| 480 | + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
|---|
| 481 | + val->intval = ddata->config.bat.constant_charge_voltage_max_uv; |
|---|
| 482 | + break; |
|---|
| 480 | 483 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
|---|
| 481 | | - if (cached) { |
|---|
| 484 | + sample = latest->cc.sample - previous->cc.sample; |
|---|
| 485 | + if (!sample) { |
|---|
| 482 | 486 | val->intval = cpcap_battery_cc_get_avg_current(ddata); |
|---|
| 483 | 487 | break; |
|---|
| 484 | 488 | } |
|---|
| 485 | | - sample = latest->cc.sample - previous->cc.sample; |
|---|
| 486 | 489 | accumulator = latest->cc.accumulator - previous->cc.accumulator; |
|---|
| 487 | 490 | val->intval = cpcap_battery_cc_to_ua(ddata, sample, |
|---|
| 488 | 491 | accumulator, |
|---|
| .. | .. |
|---|
| 499 | 502 | val->intval = div64_s64(tmp, 100); |
|---|
| 500 | 503 | break; |
|---|
| 501 | 504 | case POWER_SUPPLY_PROP_POWER_AVG: |
|---|
| 502 | | - if (cached) { |
|---|
| 505 | + sample = latest->cc.sample - previous->cc.sample; |
|---|
| 506 | + if (!sample) { |
|---|
| 503 | 507 | tmp = cpcap_battery_cc_get_avg_current(ddata); |
|---|
| 504 | 508 | tmp *= (latest->voltage / 10000); |
|---|
| 505 | 509 | val->intval = div64_s64(tmp, 100); |
|---|
| 506 | 510 | break; |
|---|
| 507 | 511 | } |
|---|
| 508 | | - sample = latest->cc.sample - previous->cc.sample; |
|---|
| 509 | 512 | accumulator = latest->cc.accumulator - previous->cc.accumulator; |
|---|
| 510 | 513 | tmp = cpcap_battery_cc_to_ua(ddata, sample, accumulator, |
|---|
| 511 | 514 | latest->cc.offset); |
|---|
| .. | .. |
|---|
| 542 | 545 | return 0; |
|---|
| 543 | 546 | } |
|---|
| 544 | 547 | |
|---|
| 548 | +static int cpcap_battery_update_charger(struct cpcap_battery_ddata *ddata, |
|---|
| 549 | + int const_charge_voltage) |
|---|
| 550 | +{ |
|---|
| 551 | + union power_supply_propval prop; |
|---|
| 552 | + union power_supply_propval val; |
|---|
| 553 | + struct power_supply *charger; |
|---|
| 554 | + int error; |
|---|
| 555 | + |
|---|
| 556 | + charger = power_supply_get_by_name("usb"); |
|---|
| 557 | + if (!charger) |
|---|
| 558 | + return -ENODEV; |
|---|
| 559 | + |
|---|
| 560 | + error = power_supply_get_property(charger, |
|---|
| 561 | + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, |
|---|
| 562 | + &prop); |
|---|
| 563 | + if (error) |
|---|
| 564 | + goto out_put; |
|---|
| 565 | + |
|---|
| 566 | + /* Allow charger const voltage lower than battery const voltage */ |
|---|
| 567 | + if (const_charge_voltage > prop.intval) |
|---|
| 568 | + goto out_put; |
|---|
| 569 | + |
|---|
| 570 | + val.intval = const_charge_voltage; |
|---|
| 571 | + |
|---|
| 572 | + error = power_supply_set_property(charger, |
|---|
| 573 | + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, |
|---|
| 574 | + &val); |
|---|
| 575 | +out_put: |
|---|
| 576 | + power_supply_put(charger); |
|---|
| 577 | + |
|---|
| 578 | + return error; |
|---|
| 579 | +} |
|---|
| 580 | + |
|---|
| 581 | +static int cpcap_battery_set_property(struct power_supply *psy, |
|---|
| 582 | + enum power_supply_property psp, |
|---|
| 583 | + const union power_supply_propval *val) |
|---|
| 584 | +{ |
|---|
| 585 | + struct cpcap_battery_ddata *ddata = power_supply_get_drvdata(psy); |
|---|
| 586 | + |
|---|
| 587 | + switch (psp) { |
|---|
| 588 | + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
|---|
| 589 | + if (val->intval < ddata->config.info.voltage_min_design) |
|---|
| 590 | + return -EINVAL; |
|---|
| 591 | + if (val->intval > ddata->config.info.voltage_max_design) |
|---|
| 592 | + return -EINVAL; |
|---|
| 593 | + |
|---|
| 594 | + ddata->config.bat.constant_charge_voltage_max_uv = val->intval; |
|---|
| 595 | + |
|---|
| 596 | + return cpcap_battery_update_charger(ddata, val->intval); |
|---|
| 597 | + default: |
|---|
| 598 | + return -EINVAL; |
|---|
| 599 | + } |
|---|
| 600 | + |
|---|
| 601 | + return 0; |
|---|
| 602 | +} |
|---|
| 603 | + |
|---|
| 604 | +static int cpcap_battery_property_is_writeable(struct power_supply *psy, |
|---|
| 605 | + enum power_supply_property psp) |
|---|
| 606 | +{ |
|---|
| 607 | + switch (psp) { |
|---|
| 608 | + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
|---|
| 609 | + return 1; |
|---|
| 610 | + default: |
|---|
| 611 | + return 0; |
|---|
| 612 | + } |
|---|
| 613 | +} |
|---|
| 614 | + |
|---|
| 545 | 615 | static irqreturn_t cpcap_battery_irq_thread(int irq, void *data) |
|---|
| 546 | 616 | { |
|---|
| 547 | 617 | struct cpcap_battery_ddata *ddata = data; |
|---|
| .. | .. |
|---|
| 556 | 626 | break; |
|---|
| 557 | 627 | } |
|---|
| 558 | 628 | |
|---|
| 559 | | - if (!d) |
|---|
| 629 | + if (list_entry_is_head(d, &ddata->irq_list, node)) |
|---|
| 560 | 630 | return IRQ_NONE; |
|---|
| 561 | 631 | |
|---|
| 562 | 632 | latest = cpcap_battery_latest(ddata); |
|---|
| 563 | 633 | |
|---|
| 564 | 634 | switch (d->action) { |
|---|
| 635 | + case CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE: |
|---|
| 636 | + dev_info(ddata->dev, "Coulomb counter calibration done\n"); |
|---|
| 637 | + break; |
|---|
| 565 | 638 | case CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW: |
|---|
| 566 | | - if (latest->counter_uah >= 0) |
|---|
| 567 | | - dev_warn(ddata->dev, "Battery low at 3.3V!\n"); |
|---|
| 639 | + if (latest->current_ua >= 0) |
|---|
| 640 | + dev_warn(ddata->dev, "Battery low at %imV!\n", |
|---|
| 641 | + latest->voltage / 1000); |
|---|
| 568 | 642 | break; |
|---|
| 569 | 643 | case CPCAP_BATTERY_IRQ_ACTION_POWEROFF: |
|---|
| 570 | | - if (latest->counter_uah >= 0) { |
|---|
| 644 | + if (latest->current_ua >= 0 && latest->voltage <= 3200000) { |
|---|
| 571 | 645 | dev_emerg(ddata->dev, |
|---|
| 572 | | - "Battery empty at 3.1V, powering off\n"); |
|---|
| 646 | + "Battery empty at %imV, powering off\n", |
|---|
| 647 | + latest->voltage / 1000); |
|---|
| 573 | 648 | orderly_poweroff(true); |
|---|
| 574 | 649 | } |
|---|
| 575 | 650 | break; |
|---|
| .. | .. |
|---|
| 595 | 670 | |
|---|
| 596 | 671 | error = devm_request_threaded_irq(ddata->dev, irq, NULL, |
|---|
| 597 | 672 | cpcap_battery_irq_thread, |
|---|
| 598 | | - IRQF_SHARED, |
|---|
| 673 | + IRQF_SHARED | IRQF_ONESHOT, |
|---|
| 599 | 674 | name, ddata); |
|---|
| 600 | 675 | if (error) { |
|---|
| 601 | 676 | dev_err(ddata->dev, "could not get irq %s: %i\n", |
|---|
| .. | .. |
|---|
| 611 | 686 | d->name = name; |
|---|
| 612 | 687 | d->irq = irq; |
|---|
| 613 | 688 | |
|---|
| 614 | | - if (!strncmp(name, "lowbph", 6)) |
|---|
| 689 | + if (!strncmp(name, "cccal", 5)) |
|---|
| 690 | + d->action = CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE; |
|---|
| 691 | + else if (!strncmp(name, "lowbph", 6)) |
|---|
| 615 | 692 | d->action = CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW; |
|---|
| 616 | 693 | else if (!strncmp(name, "lowbpl", 6)) |
|---|
| 617 | 694 | d->action = CPCAP_BATTERY_IRQ_ACTION_POWEROFF; |
|---|
| .. | .. |
|---|
| 624 | 701 | static int cpcap_battery_init_interrupts(struct platform_device *pdev, |
|---|
| 625 | 702 | struct cpcap_battery_ddata *ddata) |
|---|
| 626 | 703 | { |
|---|
| 627 | | - const char * const cpcap_battery_irqs[] = { |
|---|
| 704 | + static const char * const cpcap_battery_irqs[] = { |
|---|
| 628 | 705 | "eol", "lowbph", "lowbpl", |
|---|
| 629 | 706 | "chrgcurr1", "battdetb" |
|---|
| 630 | 707 | }; |
|---|
| .. | .. |
|---|
| 636 | 713 | if (error) |
|---|
| 637 | 714 | return error; |
|---|
| 638 | 715 | } |
|---|
| 716 | + |
|---|
| 717 | + /* Enable calibration interrupt if already available in dts */ |
|---|
| 718 | + cpcap_battery_init_irq(pdev, ddata, "cccal"); |
|---|
| 639 | 719 | |
|---|
| 640 | 720 | /* Enable low battery interrupts for 3.3V high and 3.1V low */ |
|---|
| 641 | 721 | error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL, |
|---|
| .. | .. |
|---|
| 671 | 751 | return 0; |
|---|
| 672 | 752 | |
|---|
| 673 | 753 | out_err: |
|---|
| 674 | | - dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", |
|---|
| 675 | | - error); |
|---|
| 754 | + return dev_err_probe(ddata->dev, error, |
|---|
| 755 | + "could not initialize VBUS or ID IIO\n"); |
|---|
| 756 | +} |
|---|
| 757 | + |
|---|
| 758 | +/* Calibrate coulomb counter */ |
|---|
| 759 | +static int cpcap_battery_calibrate(struct cpcap_battery_ddata *ddata) |
|---|
| 760 | +{ |
|---|
| 761 | + int error, ccc1, value; |
|---|
| 762 | + unsigned long timeout; |
|---|
| 763 | + |
|---|
| 764 | + error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &ccc1); |
|---|
| 765 | + if (error) |
|---|
| 766 | + return error; |
|---|
| 767 | + |
|---|
| 768 | + timeout = jiffies + msecs_to_jiffies(6000); |
|---|
| 769 | + |
|---|
| 770 | + /* Start calibration */ |
|---|
| 771 | + error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1, |
|---|
| 772 | + 0xffff, |
|---|
| 773 | + CPCAP_REG_CCC1_CAL_EN); |
|---|
| 774 | + if (error) |
|---|
| 775 | + goto restore; |
|---|
| 776 | + |
|---|
| 777 | + while (time_before(jiffies, timeout)) { |
|---|
| 778 | + error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &value); |
|---|
| 779 | + if (error) |
|---|
| 780 | + goto restore; |
|---|
| 781 | + |
|---|
| 782 | + if (!(value & CPCAP_REG_CCC1_CAL_EN)) |
|---|
| 783 | + break; |
|---|
| 784 | + |
|---|
| 785 | + error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); |
|---|
| 786 | + if (error) |
|---|
| 787 | + goto restore; |
|---|
| 788 | + |
|---|
| 789 | + msleep(300); |
|---|
| 790 | + } |
|---|
| 791 | + |
|---|
| 792 | + /* Read calibration offset from CCM */ |
|---|
| 793 | + error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); |
|---|
| 794 | + if (error) |
|---|
| 795 | + goto restore; |
|---|
| 796 | + |
|---|
| 797 | + dev_info(ddata->dev, "calibration done: 0x%04x\n", value); |
|---|
| 798 | + |
|---|
| 799 | +restore: |
|---|
| 800 | + if (error) |
|---|
| 801 | + dev_err(ddata->dev, "%s: error %i\n", __func__, error); |
|---|
| 802 | + |
|---|
| 803 | + error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1, |
|---|
| 804 | + 0xffff, ccc1); |
|---|
| 805 | + if (error) |
|---|
| 806 | + dev_err(ddata->dev, "%s: restore error %i\n", |
|---|
| 807 | + __func__, error); |
|---|
| 676 | 808 | |
|---|
| 677 | 809 | return error; |
|---|
| 678 | 810 | } |
|---|
| .. | .. |
|---|
| 688 | 820 | * at 3078000. The device will die around 2743000. |
|---|
| 689 | 821 | */ |
|---|
| 690 | 822 | static const struct cpcap_battery_config cpcap_battery_default_data = { |
|---|
| 691 | | - .ccm = 0x3ff, |
|---|
| 692 | 823 | .cd_factor = 0x3cc, |
|---|
| 693 | 824 | .info.technology = POWER_SUPPLY_TECHNOLOGY_LION, |
|---|
| 694 | 825 | .info.voltage_max_design = 4351000, |
|---|
| 695 | 826 | .info.voltage_min_design = 3100000, |
|---|
| 696 | 827 | .info.charge_full_design = 1740000, |
|---|
| 828 | + .bat.constant_charge_voltage_max_uv = 4200000, |
|---|
| 697 | 829 | }; |
|---|
| 698 | 830 | |
|---|
| 699 | 831 | #ifdef CONFIG_OF |
|---|
| .. | .. |
|---|
| 742 | 874 | if (error) |
|---|
| 743 | 875 | return error; |
|---|
| 744 | 876 | |
|---|
| 745 | | - platform_set_drvdata(pdev, ddata); |
|---|
| 877 | + switch (ddata->vendor) { |
|---|
| 878 | + case CPCAP_VENDOR_ST: |
|---|
| 879 | + ddata->cc_lsb = 95374; /* μAms per LSB */ |
|---|
| 880 | + break; |
|---|
| 881 | + case CPCAP_VENDOR_TI: |
|---|
| 882 | + ddata->cc_lsb = 91501; /* μAms per LSB */ |
|---|
| 883 | + break; |
|---|
| 884 | + default: |
|---|
| 885 | + return -EINVAL; |
|---|
| 886 | + } |
|---|
| 887 | + ddata->cc_lsb = (ddata->cc_lsb * ddata->config.cd_factor) / 1000; |
|---|
| 746 | 888 | |
|---|
| 747 | | - error = regmap_update_bits(ddata->reg, CPCAP_REG_CCM, |
|---|
| 748 | | - 0xffff, ddata->config.ccm); |
|---|
| 749 | | - if (error) |
|---|
| 750 | | - return error; |
|---|
| 889 | + platform_set_drvdata(pdev, ddata); |
|---|
| 751 | 890 | |
|---|
| 752 | 891 | error = cpcap_battery_init_interrupts(pdev, ddata); |
|---|
| 753 | 892 | if (error) |
|---|
| .. | .. |
|---|
| 761 | 900 | if (!psy_desc) |
|---|
| 762 | 901 | return -ENOMEM; |
|---|
| 763 | 902 | |
|---|
| 764 | | - psy_desc->name = "battery", |
|---|
| 765 | | - psy_desc->type = POWER_SUPPLY_TYPE_BATTERY, |
|---|
| 766 | | - psy_desc->properties = cpcap_battery_props, |
|---|
| 767 | | - psy_desc->num_properties = ARRAY_SIZE(cpcap_battery_props), |
|---|
| 768 | | - psy_desc->get_property = cpcap_battery_get_property, |
|---|
| 903 | + psy_desc->name = "battery"; |
|---|
| 904 | + psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; |
|---|
| 905 | + psy_desc->properties = cpcap_battery_props; |
|---|
| 906 | + psy_desc->num_properties = ARRAY_SIZE(cpcap_battery_props); |
|---|
| 907 | + psy_desc->get_property = cpcap_battery_get_property; |
|---|
| 908 | + psy_desc->set_property = cpcap_battery_set_property; |
|---|
| 909 | + psy_desc->property_is_writeable = cpcap_battery_property_is_writeable; |
|---|
| 769 | 910 | |
|---|
| 770 | 911 | psy_cfg.of_node = pdev->dev.of_node; |
|---|
| 771 | 912 | psy_cfg.drv_data = ddata; |
|---|
| .. | .. |
|---|
| 780 | 921 | |
|---|
| 781 | 922 | atomic_set(&ddata->active, 1); |
|---|
| 782 | 923 | |
|---|
| 924 | + error = cpcap_battery_calibrate(ddata); |
|---|
| 925 | + if (error) |
|---|
| 926 | + return error; |
|---|
| 927 | + |
|---|
| 783 | 928 | return 0; |
|---|
| 784 | 929 | } |
|---|
| 785 | 930 | |
|---|