summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuanjiang Yu <yuanjiang.yu@unisoc.com>2019-07-31 06:00:26 -0400
committerSebastian Reichel <sre@kernel.org>2019-09-02 16:59:50 -0400
commit580665279fb6a16eb119ec80a5be1b3ec7a641a0 (patch)
treebe9a721e6da270f8237e336c612a4998a74b658e
parentff062d06948c012cbfd6f5947b599be5ea1c3799 (diff)
power: supply: sc27xx: Optimize the battery capacity calibration
This patch factors out the capacity calibration into one single function to calibrate the battery capacity, and adding more abnormal cases to calibrate the capacity when the OCV value is not matchable with current capacity. Moreover we also allow to calibrate the capacity when charger magager tries to get current capacity to make sure we give a correct capacity for userspace. Signed-off-by: Yuanjiang Yu <yuanjiang.yu@unisoc.com> Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
-rw-r--r--drivers/power/supply/sc27xx_fuel_gauge.c127
1 files changed, 92 insertions, 35 deletions
diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c
index 096da951f465..6071671caaa9 100644
--- a/drivers/power/supply/sc27xx_fuel_gauge.c
+++ b/drivers/power/supply/sc27xx_fuel_gauge.c
@@ -109,6 +109,8 @@ struct sc27xx_fgu_data {
109}; 109};
110 110
111static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity); 111static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity);
112static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
113 int cap, bool int_mode);
112 114
113static const char * const sc27xx_charger_supply_name[] = { 115static const char * const sc27xx_charger_supply_name[] = {
114 "sc2731_charger", 116 "sc2731_charger",
@@ -389,6 +391,9 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap)
389 delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap); 391 delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap);
390 *cap = delta_cap + data->init_cap; 392 *cap = delta_cap + data->init_cap;
391 393
394 /* Calibrate the battery capacity in a normal range. */
395 sc27xx_fgu_capacity_calibration(data, *cap, false);
396
392 return 0; 397 return 0;
393} 398}
394 399
@@ -661,50 +666,62 @@ static const struct power_supply_desc sc27xx_fgu_desc = {
661 666
662static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap) 667static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap)
663{ 668{
669 int ret;
670
664 data->init_cap = cap; 671 data->init_cap = cap;
665 data->init_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, data->init_cap); 672 ret = sc27xx_fgu_get_clbcnt(data, &data->init_clbcnt);
673 if (ret)
674 dev_err(data->dev, "failed to get init coulomb counter\n");
666} 675}
667 676
668static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id) 677static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
678 int cap, bool int_mode)
669{ 679{
670 struct sc27xx_fgu_data *data = dev_id; 680 int ret, ocv, chg_sts, adc;
671 int ret, cap, ocv, adc;
672 u32 status;
673
674 mutex_lock(&data->lock);
675 681
676 ret = regmap_read(data->regmap, data->base + SC27XX_FGU_INT_STS, 682 ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
677 &status); 683 if (ret) {
678 if (ret) 684 dev_err(data->dev, "get battery ocv error.\n");
679 goto out; 685 return;
686 }
680 687
681 ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_CLR, 688 ret = sc27xx_fgu_get_status(data, &chg_sts);
682 status, status); 689 if (ret) {
683 if (ret) 690 dev_err(data->dev, "get charger status error.\n");
684 goto out; 691 return;
692 }
685 693
686 /* 694 /*
687 * When low overload voltage interrupt happens, we should calibrate the 695 * If we are in charging mode, then we do not need to calibrate the
688 * battery capacity in lower voltage stage. 696 * lower capacity.
689 */ 697 */
690 if (!(status & SC27XX_FGU_LOW_OVERLOAD_INT)) 698 if (chg_sts == POWER_SUPPLY_STATUS_CHARGING)
691 goto out; 699 return;
692 700
693 ret = sc27xx_fgu_get_capacity(data, &cap); 701 if ((ocv > data->cap_table[0].ocv && cap < 100) || cap > 100) {
694 if (ret) 702 /*
695 goto out; 703 * If current OCV value is larger than the max OCV value in
696 704 * OCV table, or the current capacity is larger than 100,
697 ret = sc27xx_fgu_get_vbat_ocv(data, &ocv); 705 * we should force the inititial capacity to 100.
698 if (ret) 706 */
699 goto out; 707 sc27xx_fgu_adjust_cap(data, 100);
700 708 } else if (ocv <= data->cap_table[data->table_len - 1].ocv) {
701 /* 709 /*
702 * If current OCV value is less than the minimum OCV value in OCV table, 710 * If current OCV value is leass than the minimum OCV value in
703 * which means now battery capacity is 0%, and we should adjust the 711 * OCV table, we should force the inititial capacity to 0.
704 * inititial capacity to 0. 712 */
705 */
706 if (ocv <= data->cap_table[data->table_len - 1].ocv) {
707 sc27xx_fgu_adjust_cap(data, 0); 713 sc27xx_fgu_adjust_cap(data, 0);
714 } else if ((ocv > data->cap_table[data->table_len - 1].ocv && cap <= 0) ||
715 (ocv > data->min_volt && cap <= data->alarm_cap)) {
716 /*
717 * If current OCV value is not matchable with current capacity,
718 * we should re-calculate current capacity by looking up the
719 * OCV table.
720 */
721 int cur_cap = power_supply_ocv2cap_simple(data->cap_table,
722 data->table_len, ocv);
723
724 sc27xx_fgu_adjust_cap(data, cur_cap);
708 } else if (ocv <= data->min_volt) { 725 } else if (ocv <= data->min_volt) {
709 /* 726 /*
710 * If current OCV value is less than the low alarm voltage, but 727 * If current OCV value is less than the low alarm voltage, but
@@ -713,7 +730,7 @@ static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
713 */ 730 */
714 if (cap > data->alarm_cap) { 731 if (cap > data->alarm_cap) {
715 sc27xx_fgu_adjust_cap(data, data->alarm_cap); 732 sc27xx_fgu_adjust_cap(data, data->alarm_cap);
716 } else if (cap <= 0) { 733 } else {
717 int cur_cap; 734 int cur_cap;
718 735
719 /* 736 /*
@@ -728,15 +745,55 @@ static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
728 sc27xx_fgu_adjust_cap(data, cur_cap); 745 sc27xx_fgu_adjust_cap(data, cur_cap);
729 } 746 }
730 747
748 if (!int_mode)
749 return;
750
731 /* 751 /*
732 * After adjusting the battery capacity, we should set the 752 * After adjusting the battery capacity, we should set the
733 * lowest alarm voltage instead. 753 * lowest alarm voltage instead.
734 */ 754 */
735 data->min_volt = data->cap_table[data->table_len - 1].ocv; 755 data->min_volt = data->cap_table[data->table_len - 1].ocv;
756 data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table,
757 data->table_len,
758 data->min_volt);
759
736 adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000); 760 adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000);
737 regmap_update_bits(data->regmap, data->base + SC27XX_FGU_LOW_OVERLOAD, 761 regmap_update_bits(data->regmap,
762 data->base + SC27XX_FGU_LOW_OVERLOAD,
738 SC27XX_FGU_LOW_OVERLOAD_MASK, adc); 763 SC27XX_FGU_LOW_OVERLOAD_MASK, adc);
739 } 764 }
765}
766
767static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
768{
769 struct sc27xx_fgu_data *data = dev_id;
770 int ret, cap;
771 u32 status;
772
773 mutex_lock(&data->lock);
774
775 ret = regmap_read(data->regmap, data->base + SC27XX_FGU_INT_STS,
776 &status);
777 if (ret)
778 goto out;
779
780 ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_CLR,
781 status, status);
782 if (ret)
783 goto out;
784
785 /*
786 * When low overload voltage interrupt happens, we should calibrate the
787 * battery capacity in lower voltage stage.
788 */
789 if (!(status & SC27XX_FGU_LOW_OVERLOAD_INT))
790 goto out;
791
792 ret = sc27xx_fgu_get_capacity(data, &cap);
793 if (ret)
794 goto out;
795
796 sc27xx_fgu_capacity_calibration(data, cap, true);
740 797
741out: 798out:
742 mutex_unlock(&data->lock); 799 mutex_unlock(&data->lock);