linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Baolin Wang <baolin.wang@linaro.org>
To: sre@kernel.org
Cc: orsonzhai@gmail.com, zhang.lyra@gmail.com,
	yuanjiang.yu@unisoc.com, baolin.wang@linaro.org,
	vincent.guittot@linaro.org, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 4/6] power: supply: sc27xx: Optimize the battery capacity calibration
Date: Wed, 31 Jul 2019 18:00:26 +0800	[thread overview]
Message-ID: <6d4155a2d95a67546c27b49ba4cd1ab2898cb570.1564566425.git.baolin.wang@linaro.org> (raw)
In-Reply-To: <cover.1564566425.git.baolin.wang@linaro.org>
In-Reply-To: <cover.1564566425.git.baolin.wang@linaro.org>

From: Yuanjiang Yu <yuanjiang.yu@unisoc.com>

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>
---
 drivers/power/supply/sc27xx_fuel_gauge.c |  127 ++++++++++++++++++++++--------
 1 file changed, 92 insertions(+), 35 deletions(-)

diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c
index ab3afa1..f670131 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 {
 };
 
 static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity);
+static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
+					    int cap, int int_mode);
 
 static const char * const sc27xx_charger_supply_name[] = {
 	"sc2731_charger",
@@ -389,6 +391,9 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap)
 	delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap);
 	*cap = delta_cap + data->init_cap;
 
+	/* Calibrate the battery capacity in a normal range. */
+	sc27xx_fgu_capacity_calibration(data, *cap, false);
+
 	return 0;
 }
 
@@ -661,50 +666,62 @@ static int sc27xx_fgu_property_is_writeable(struct power_supply *psy,
 
 static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap)
 {
+	int ret;
+
 	data->init_cap = cap;
-	data->init_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, data->init_cap);
+	ret = sc27xx_fgu_get_clbcnt(data, &data->init_clbcnt);
+	if (ret)
+		dev_err(data->dev, "failed to get init coulomb counter\n");
 }
 
-static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
+static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
+					    int cap, int int_mode)
 {
-	struct sc27xx_fgu_data *data = dev_id;
-	int ret, cap, ocv, adc;
-	u32 status;
-
-	mutex_lock(&data->lock);
+	int ret, ocv, chg_sts, adc;
 
-	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_INT_STS,
-			  &status);
-	if (ret)
-		goto out;
+	ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
+	if (ret) {
+		dev_err(data->dev, "get battery ocv error.\n");
+		return;
+	}
 
-	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_CLR,
-				 status, status);
-	if (ret)
-		goto out;
+	ret = sc27xx_fgu_get_status(data, &chg_sts);
+	if (ret) {
+		dev_err(data->dev, "get charger status error.\n");
+		return;
+	}
 
 	/*
-	 * When low overload voltage interrupt happens, we should calibrate the
-	 * battery capacity in lower voltage stage.
+	 * If we are in charging mode, then we do not need to calibrate the
+	 * lower capacity.
 	 */
-	if (!(status & SC27XX_FGU_LOW_OVERLOAD_INT))
-		goto out;
+	if (chg_sts == POWER_SUPPLY_STATUS_CHARGING)
+		return;
 
-	ret = sc27xx_fgu_get_capacity(data, &cap);
-	if (ret)
-		goto out;
-
-	ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
-	if (ret)
-		goto out;
-
-	/*
-	 * If current OCV value is less than the minimum OCV value in OCV table,
-	 * which means now battery capacity is 0%, and we should adjust the
-	 * inititial capacity to 0.
-	 */
-	if (ocv <= data->cap_table[data->table_len - 1].ocv) {
+	if ((ocv > data->cap_table[0].ocv && cap < 100) || cap > 100) {
+		/*
+		 * If current OCV value is larger than the max OCV value in
+		 * OCV table, or the current capacity is larger than 100,
+		 * we should force the inititial capacity to 100.
+		 */
+		sc27xx_fgu_adjust_cap(data, 100);
+	} else if (ocv <= data->cap_table[data->table_len - 1].ocv) {
+		/*
+		 * If current OCV value is leass than the minimum OCV value in
+		 * OCV table, we should force the inititial capacity to 0.
+		 */
 		sc27xx_fgu_adjust_cap(data, 0);
+	} else if ((ocv > data->cap_table[data->table_len - 1].ocv && cap <= 0) ||
+		   (ocv > data->min_volt && cap <= data->alarm_cap)) {
+		/*
+		 * If current OCV value is not matchable with current capacity,
+		 * we should re-calculate current capacity by looking up the
+		 * OCV table.
+		 */
+		int cur_cap = power_supply_ocv2cap_simple(data->cap_table,
+							  data->table_len, ocv);
+
+		sc27xx_fgu_adjust_cap(data, cur_cap);
 	} else if (ocv <= data->min_volt) {
 		/*
 		 * 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)
 		 */
 		if (cap > data->alarm_cap) {
 			sc27xx_fgu_adjust_cap(data, data->alarm_cap);
-		} else if (cap <= 0) {
+		} else {
 			int cur_cap;
 
 			/*
@@ -728,15 +745,55 @@ static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
 			sc27xx_fgu_adjust_cap(data, cur_cap);
 		}
 
+		if (!int_mode)
+			return;
+
 		/*
 		 * After adjusting the battery capacity, we should set the
 		 * lowest alarm voltage instead.
 		 */
 		data->min_volt = data->cap_table[data->table_len - 1].ocv;
+		data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table,
+							      data->table_len,
+							      data->min_volt);
+
 		adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000);
-		regmap_update_bits(data->regmap, data->base + SC27XX_FGU_LOW_OVERLOAD,
+		regmap_update_bits(data->regmap,
+				   data->base + SC27XX_FGU_LOW_OVERLOAD,
 				   SC27XX_FGU_LOW_OVERLOAD_MASK, adc);
 	}
+}
+
+static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
+{
+	struct sc27xx_fgu_data *data = dev_id;
+	int ret, cap;
+	u32 status;
+
+	mutex_lock(&data->lock);
+
+	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_INT_STS,
+			  &status);
+	if (ret)
+		goto out;
+
+	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_CLR,
+				 status, status);
+	if (ret)
+		goto out;
+
+	/*
+	 * When low overload voltage interrupt happens, we should calibrate the
+	 * battery capacity in lower voltage stage.
+	 */
+	if (!(status & SC27XX_FGU_LOW_OVERLOAD_INT))
+		goto out;
+
+	ret = sc27xx_fgu_get_capacity(data, &cap);
+	if (ret)
+		goto out;
+
+	sc27xx_fgu_capacity_calibration(data, cap, true);
 
 out:
 	mutex_unlock(&data->lock);
-- 
1.7.9.5


  parent reply	other threads:[~2019-07-31 10:01 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-31 10:00 [PATCH 0/6] Optimize the Spreadtrum SC27xx fuel gauge Baolin Wang
2019-07-31 10:00 ` [PATCH 1/6] power: supply: sc27xx: Add POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN attribute Baolin Wang
2019-07-31 10:00 ` [PATCH 2/6] power: supply: sc27xx: Fix conditon to enable the FGU interrupt Baolin Wang
2019-07-31 10:00 ` [PATCH 3/6] power: supply: sc27xx: Fix the the accuracy issue of coulomb calculation Baolin Wang
2019-07-31 10:00 ` Baolin Wang [this message]
2019-07-31 10:00 ` [PATCH 5/6] power: supply: sc27xx: Make sure the alarm capacity is larger than 0 Baolin Wang
2019-07-31 10:00 ` [PATCH 6/6] power: supply: sc27xx: Add POWER_SUPPLY_PROP_CALIBRATE attribute Baolin Wang
2019-09-02 21:04 ` [PATCH 0/6] Optimize the Spreadtrum SC27xx fuel gauge Sebastian Reichel
2019-09-03  1:34   ` Baolin Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6d4155a2d95a67546c27b49ba4cd1ab2898cb570.1564566425.git.baolin.wang@linaro.org \
    --to=baolin.wang@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=orsonzhai@gmail.com \
    --cc=sre@kernel.org \
    --cc=vincent.guittot@linaro.org \
    --cc=yuanjiang.yu@unisoc.com \
    --cc=zhang.lyra@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).