hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/drivers/power/supply/cpcap-battery.c
....@@ -33,8 +33,6 @@
3333 #include <linux/iio/types.h>
3434 #include <linux/mfd/motorola-cpcap.h>
3535
36
-#include <asm/div64.h>
37
-
3836 /*
3937 * Register bit defines for CPCAP_REG_BPEOL. Some of these seem to
4038 * map to MC13783UG.pdf "Table 5-19. Register 13, Power Control 0"
....@@ -52,6 +50,26 @@
5250 #define CPCAP_REG_BPEOL_BIT_BATTDETEN BIT(1) /* Enable battery detect */
5351 #define CPCAP_REG_BPEOL_BIT_EOLSEL BIT(0) /* BPDET = 0, EOL = 1 */
5452
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
+
5573 #define CPCAP_BATTERY_CC_SAMPLE_PERIOD_MS 250
5674
5775 enum {
....@@ -64,6 +82,7 @@
6482
6583 enum cpcap_battery_irq_action {
6684 CPCAP_BATTERY_IRQ_ACTION_NONE,
85
+ CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE,
6786 CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW,
6887 CPCAP_BATTERY_IRQ_ACTION_POWEROFF,
6988 };
....@@ -76,15 +95,16 @@
7695 };
7796
7897 struct cpcap_battery_config {
79
- int ccm;
8098 int cd_factor;
8199 struct power_supply_info info;
100
+ struct power_supply_battery_info bat;
82101 };
83102
84103 struct cpcap_coulomb_counter_data {
85104 s32 sample; /* 24 or 32 bits */
86105 s32 accumulator;
87
- s16 offset; /* 10-bits */
106
+ s16 offset; /* 9 bits */
107
+ s16 integrator; /* 13 or 16 bits */
88108 };
89109
90110 enum cpcap_battery_state {
....@@ -110,6 +130,7 @@
110130 struct power_supply *psy;
111131 struct cpcap_battery_config config;
112132 struct cpcap_battery_state_data state[CPCAP_BATTERY_STATE_NR];
133
+ u32 cc_lsb; /* μAms per LSB */
113134 atomic_t active;
114135 int status;
115136 u16 vendor;
....@@ -217,43 +238,17 @@
217238 s16 offset, u32 divider)
218239 {
219240 s64 acc;
220
- u64 tmp;
221
- int avg_current;
222
- u32 cc_lsb;
223241
224242 if (!divider)
225243 return 0;
226244
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
-
240245 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);
243250
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;
257252 }
258253
259254 /* 3600000μAms = 1μAh */
....@@ -279,7 +274,7 @@
279274 /**
280275 * cpcap_battery_read_accumulated - reads cpcap coulomb counter
281276 * @ddata: device driver data
282
- * @regs: coulomb counter values
277
+ * @ccd: coulomb counter values
283278 *
284279 * Based on Motorola mapphone kernel function data_read_regs().
285280 * Looking at the registers, the coulomb counter seems similar to
....@@ -295,12 +290,13 @@
295290 cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
296291 struct cpcap_coulomb_counter_data *ccd)
297292 {
298
- u16 buf[7]; /* CPCAP_REG_CC1 to CCI */
293
+ u16 buf[7]; /* CPCAP_REG_CCS1 to CCI */
299294 int error;
300295
301296 ccd->sample = 0;
302297 ccd->accumulator = 0;
303298 ccd->offset = 0;
299
+ ccd->integrator = 0;
304300
305301 /* Read coulomb counter register range */
306302 error = regmap_bulk_read(ddata->reg, CPCAP_REG_CCS1,
....@@ -318,12 +314,18 @@
318314 ccd->accumulator = ((s16)buf[3]) << 16;
319315 ccd->accumulator |= buf[2];
320316
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);
323323
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];
327329
328330 return cpcap_battery_cc_to_uah(ddata,
329331 ccd->sample,
....@@ -338,31 +340,28 @@
338340 static int cpcap_battery_cc_get_avg_current(struct cpcap_battery_ddata *ddata)
339341 {
340342 int value, acc, error;
341
- s32 sample = 1;
343
+ s32 sample;
342344 s16 offset;
343
-
344
- if (ddata->vendor == CPCAP_VENDOR_ST)
345
- sample = 4;
346345
347346 /* Coulomb counter integrator */
348347 error = regmap_read(ddata->reg, CPCAP_REG_CCI, &value);
349348 if (error)
350349 return error;
351350
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
+ }
354358
355
- acc = (s16)value;
356
-
357
- /* Coulomb counter sample time */
359
+ /* Coulomb counter calibration offset */
358360 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value);
359361 if (error)
360362 return error;
361363
362
- if (value < 0x200)
363
- offset = value;
364
- else
365
- offset = value | 0xfc00;
364
+ offset = sign_extend32(value, 9);
366365
367366 return cpcap_battery_cc_to_ua(ddata, sample, acc, offset);
368367 }
....@@ -371,8 +370,8 @@
371370 {
372371 struct cpcap_battery_state_data *state = cpcap_battery_latest(ddata);
373372
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))
376375 return true;
377376
378377 return false;
....@@ -419,6 +418,7 @@
419418 POWER_SUPPLY_PROP_VOLTAGE_NOW,
420419 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
421420 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
421
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
422422 POWER_SUPPLY_PROP_CURRENT_AVG,
423423 POWER_SUPPLY_PROP_CURRENT_NOW,
424424 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
....@@ -477,12 +477,15 @@
477477 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
478478 val->intval = ddata->config.info.voltage_min_design;
479479 break;
480
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
481
+ val->intval = ddata->config.bat.constant_charge_voltage_max_uv;
482
+ break;
480483 case POWER_SUPPLY_PROP_CURRENT_AVG:
481
- if (cached) {
484
+ sample = latest->cc.sample - previous->cc.sample;
485
+ if (!sample) {
482486 val->intval = cpcap_battery_cc_get_avg_current(ddata);
483487 break;
484488 }
485
- sample = latest->cc.sample - previous->cc.sample;
486489 accumulator = latest->cc.accumulator - previous->cc.accumulator;
487490 val->intval = cpcap_battery_cc_to_ua(ddata, sample,
488491 accumulator,
....@@ -499,13 +502,13 @@
499502 val->intval = div64_s64(tmp, 100);
500503 break;
501504 case POWER_SUPPLY_PROP_POWER_AVG:
502
- if (cached) {
505
+ sample = latest->cc.sample - previous->cc.sample;
506
+ if (!sample) {
503507 tmp = cpcap_battery_cc_get_avg_current(ddata);
504508 tmp *= (latest->voltage / 10000);
505509 val->intval = div64_s64(tmp, 100);
506510 break;
507511 }
508
- sample = latest->cc.sample - previous->cc.sample;
509512 accumulator = latest->cc.accumulator - previous->cc.accumulator;
510513 tmp = cpcap_battery_cc_to_ua(ddata, sample, accumulator,
511514 latest->cc.offset);
....@@ -542,6 +545,73 @@
542545 return 0;
543546 }
544547
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
+
545615 static irqreturn_t cpcap_battery_irq_thread(int irq, void *data)
546616 {
547617 struct cpcap_battery_ddata *ddata = data;
....@@ -556,20 +626,25 @@
556626 break;
557627 }
558628
559
- if (!d)
629
+ if (list_entry_is_head(d, &ddata->irq_list, node))
560630 return IRQ_NONE;
561631
562632 latest = cpcap_battery_latest(ddata);
563633
564634 switch (d->action) {
635
+ case CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE:
636
+ dev_info(ddata->dev, "Coulomb counter calibration done\n");
637
+ break;
565638 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);
568642 break;
569643 case CPCAP_BATTERY_IRQ_ACTION_POWEROFF:
570
- if (latest->counter_uah >= 0) {
644
+ if (latest->current_ua >= 0 && latest->voltage <= 3200000) {
571645 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);
573648 orderly_poweroff(true);
574649 }
575650 break;
....@@ -595,7 +670,7 @@
595670
596671 error = devm_request_threaded_irq(ddata->dev, irq, NULL,
597672 cpcap_battery_irq_thread,
598
- IRQF_SHARED,
673
+ IRQF_SHARED | IRQF_ONESHOT,
599674 name, ddata);
600675 if (error) {
601676 dev_err(ddata->dev, "could not get irq %s: %i\n",
....@@ -611,7 +686,9 @@
611686 d->name = name;
612687 d->irq = irq;
613688
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))
615692 d->action = CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW;
616693 else if (!strncmp(name, "lowbpl", 6))
617694 d->action = CPCAP_BATTERY_IRQ_ACTION_POWEROFF;
....@@ -624,7 +701,7 @@
624701 static int cpcap_battery_init_interrupts(struct platform_device *pdev,
625702 struct cpcap_battery_ddata *ddata)
626703 {
627
- const char * const cpcap_battery_irqs[] = {
704
+ static const char * const cpcap_battery_irqs[] = {
628705 "eol", "lowbph", "lowbpl",
629706 "chrgcurr1", "battdetb"
630707 };
....@@ -636,6 +713,9 @@
636713 if (error)
637714 return error;
638715 }
716
+
717
+ /* Enable calibration interrupt if already available in dts */
718
+ cpcap_battery_init_irq(pdev, ddata, "cccal");
639719
640720 /* Enable low battery interrupts for 3.3V high and 3.1V low */
641721 error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL,
....@@ -671,8 +751,60 @@
671751 return 0;
672752
673753 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);
676808
677809 return error;
678810 }
....@@ -688,12 +820,12 @@
688820 * at 3078000. The device will die around 2743000.
689821 */
690822 static const struct cpcap_battery_config cpcap_battery_default_data = {
691
- .ccm = 0x3ff,
692823 .cd_factor = 0x3cc,
693824 .info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
694825 .info.voltage_max_design = 4351000,
695826 .info.voltage_min_design = 3100000,
696827 .info.charge_full_design = 1740000,
828
+ .bat.constant_charge_voltage_max_uv = 4200000,
697829 };
698830
699831 #ifdef CONFIG_OF
....@@ -742,12 +874,19 @@
742874 if (error)
743875 return error;
744876
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;
746888
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);
751890
752891 error = cpcap_battery_init_interrupts(pdev, ddata);
753892 if (error)
....@@ -761,11 +900,13 @@
761900 if (!psy_desc)
762901 return -ENOMEM;
763902
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;
769910
770911 psy_cfg.of_node = pdev->dev.of_node;
771912 psy_cfg.drv_data = ddata;
....@@ -780,6 +921,10 @@
780921
781922 atomic_set(&ddata->active, 1);
782923
924
+ error = cpcap_battery_calibrate(ddata);
925
+ if (error)
926
+ return error;
927
+
783928 return 0;
784929 }
785930