.. | .. |
---|
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 | |
---|