* [PATCH v2 0/2] power: supply: qcom_battmgr: Kaanapali current sign and charge current limit
@ 2026-11-12 13:49 Joonhoe Kim
2026-11-12 13:49 ` [PATCH v2 1/2] power: supply: qcom_battmgr: fix the battery current sign on Kaanapali Joonhoe Kim
2026-11-12 13:49 ` [PATCH v2 2/2] power: supply: qcom_battmgr: expose the charge current limit Joonhoe Kim
0 siblings, 2 replies; 3+ messages in thread
From: Joonhoe Kim @ 2026-11-12 13:49 UTC (permalink / raw)
To: sre
Cc: konrad.dybcio, jingyi.wang, kamal.wadhwa, anjelique.melendez,
dhruvin.rajpura, andersson, dmitry.baryshkov, linux-arm-msm,
linux-pm, linux-kernel
Patch 1 fixes the sign of the battery current_now on Kaanapali.
Patch 2 exposes the firmware charge current limit on SM8550-class
batteries as charge_control_limit and charge_control_limit_max.
Patch 1 has no code change. Its sign is still checked only on the
Lenovo Y700 Gen 5 (TB323FU, Kaanapali); Konrad asked Jingyi on v1 to
check QRD/MTP [1], and there has been no reply yet.
Changes in v2:
- 2/2: use guard(mutex) [Konrad]
- 2/2: return -ENODATA when the firmware reports a zero maximum [Konrad]
- Rebased on next-20261111
Link to v1: https://lore.kernel.org/all/20261016124806.1789-1-26rote@gmail.com/
[1] https://lore.kernel.org/all/0e5b7d2e-e141-4ce4-a873-b65bd9ef3c4a@oss.qualcomm.com/
Joonhoe Kim (2):
power: supply: qcom_battmgr: fix the battery current sign on Kaanapali
power: supply: qcom_battmgr: expose the charge current limit
drivers/power/supply/qcom_battmgr.c | 61 +++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
base-commit: aaa2f954c21b205a0bcd0961e5b2be4e82e58455
--
2.53.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 1/2] power: supply: qcom_battmgr: fix the battery current sign on Kaanapali
2026-11-12 13:49 [PATCH v2 0/2] power: supply: qcom_battmgr: Kaanapali current sign and charge current limit Joonhoe Kim
@ 2026-11-12 13:49 ` Joonhoe Kim
2026-11-12 13:49 ` [PATCH v2 2/2] power: supply: qcom_battmgr: expose the charge current limit Joonhoe Kim
1 sibling, 0 replies; 3+ messages in thread
From: Joonhoe Kim @ 2026-11-12 13:49 UTC (permalink / raw)
To: sre
Cc: konrad.dybcio, jingyi.wang, kamal.wadhwa, anjelique.melendez,
dhruvin.rajpura, andersson, dmitry.baryshkov, linux-arm-msm,
linux-pm, linux-kernel
The Kaanapali battery firmware reports the battery current with
discharge positive: on a Lenovo Y700 Gen 5 (TB323FU) current_now reads
-9.1 A while charging and +0.57 A on battery. The power_supply ABI has
charging positive, and upower reports such a charging battery as
discharging.
Other firmware behind the same callback uses the ABI sign [1], so
negate the value only for qcom,kaanapali-pmic-glink.
Fixes: 16a7c32e586e ("power: supply: qcom_battmgr: Add support for Glymur and Kaanapali")
Link: https://lore.kernel.org/all/20260829054546.86210-1-jan.brummer@tabos.org/ [1]
Signed-off-by: Joonhoe Kim <26rote@gmail.com>
---
v2: no code change; reworded the device name.
The sign is checked only on the Y700 Gen 5. On v1 Konrad asked Jingyi
to check QRD/MTP; no reply yet:
https://lore.kernel.org/all/0e5b7d2e-e141-4ce4-a873-b65bd9ef3c4a@oss.qualcomm.com/
drivers/power/supply/qcom_battmgr.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c
index d6e3edbab..58e103e08 100644
--- a/drivers/power/supply/qcom_battmgr.c
+++ b/drivers/power/supply/qcom_battmgr.c
@@ -316,6 +316,7 @@ struct qcom_battmgr {
struct pmic_glink_client *client;
enum qcom_battmgr_variant variant;
+ bool current_inverted;
struct power_supply *ac_psy;
struct power_supply *bat_psy;
@@ -1574,6 +1575,8 @@ static void qcom_battmgr_sm8350_callback(struct qcom_battmgr *battmgr,
break;
case BATT_CURR_NOW:
battmgr->status.current_now = le32_to_cpu(resp->intval.value);
+ if (battmgr->current_inverted)
+ battmgr->status.current_now = -battmgr->status.current_now;
break;
case BATT_TEMP:
val = le32_to_cpu(resp->intval.value);
@@ -1804,6 +1807,9 @@ static int qcom_battmgr_probe(struct auxiliary_device *adev,
else
battmgr->variant = QCOM_BATTMGR_SM8350;
+ battmgr->current_inverted = device_is_compatible(dev->parent,
+ "qcom,kaanapali-pmic-glink");
+
ret = qcom_battmgr_charge_control_thresholds_init(battmgr);
if (ret < 0)
return dev_err_probe(dev, ret,
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v2 2/2] power: supply: qcom_battmgr: expose the charge current limit
2026-11-12 13:49 [PATCH v2 0/2] power: supply: qcom_battmgr: Kaanapali current sign and charge current limit Joonhoe Kim
2026-11-12 13:49 ` [PATCH v2 1/2] power: supply: qcom_battmgr: fix the battery current sign on Kaanapali Joonhoe Kim
@ 2026-11-12 13:49 ` Joonhoe Kim
1 sibling, 0 replies; 3+ messages in thread
From: Joonhoe Kim @ 2026-11-12 13:49 UTC (permalink / raw)
To: sre
Cc: konrad.dybcio, jingyi.wang, kamal.wadhwa, anjelique.melendez,
dhruvin.rajpura, andersson, dmitry.baryshkov, linux-arm-msm,
linux-pm, linux-kernel
The battery manager firmware takes a charge current limit in uA
(BATT_CHG_CTRL_LIM) and reports the highest value it accepts
(BATT_CHG_CTRL_LIM_MAX). Expose them on SM8550 class batteries as
charge_control_limit and charge_control_limit_max, clamping writes to
the maximum.
Also handle the BATTMGR_BAT_PROPERTY_SET response, which was logged as
an unknown message, and return its result.
On a Lenovo Y700 Gen 5 (TB323FU, Kaanapali) with a 45 W PD charger,
limits of 500 mA and 100 mA give about 480 mA and 90 mA of charge
current while the PD contract stays at 9 V. A limit of 0 stops
charging, and this firmware does not resume when the limit is raised
again until the end threshold is moved below the capacity and back.
Signed-off-by: Joonhoe Kim <26rote@gmail.com>
---
v2:
- Use guard(mutex) [Konrad]
- Return -ENODATA when the firmware reports a zero maximum [Konrad]
The downstream qti_battery_charger driver also writes this property in
uA. The thermal mitigation series [1] took a cooling level in
charge_control_limit; Konrad pointed out that the ABI defines it in
uA [2], which this patch follows. Only tested on Kaanapali.
[1] https://lore.kernel.org/all/20260609-cooling_device_reg-v1-2-e15bddcb0086@qti.qualcomm.com/
[2] https://lore.kernel.org/all/d99447c8-f140-4ac1-85e1-a235c37eecde@oss.qualcomm.com/
drivers/power/supply/qcom_battmgr.c | 55 +++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c
index 58e103e08..1c3cd034c 100644
--- a/drivers/power/supply/qcom_battmgr.c
+++ b/drivers/power/supply/qcom_battmgr.c
@@ -262,6 +262,8 @@ struct qcom_battmgr_info {
unsigned int charge_count;
unsigned int charge_ctrl_start;
unsigned int charge_ctrl_end;
+ unsigned int charge_ctrl_limit;
+ unsigned int charge_ctrl_limit_max;
char model_number[BATTMGR_STRING_LEN];
char serial_number[BATTMGR_STRING_LEN];
char oem_info[BATTMGR_STRING_LEN];
@@ -454,6 +456,8 @@ static const u8 sm8350_bat_prop_map[] = {
[POWER_SUPPLY_PROP_POWER_NOW] = BATT_POWER_NOW,
[POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD] = BATT_CHG_CTRL_START_THR,
[POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD] = BATT_CHG_CTRL_END_THR,
+ [POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT] = BATT_CHG_CTRL_LIM,
+ [POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX] = BATT_CHG_CTRL_LIM_MAX,
};
/*
@@ -709,6 +713,12 @@ static int qcom_battmgr_bat_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
val->intval = battmgr->info.charge_ctrl_end;
break;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ val->intval = battmgr->info.charge_ctrl_limit;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
+ val->intval = battmgr->info.charge_ctrl_limit_max;
+ break;
case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
val->intval = battmgr->info.year;
break;
@@ -803,6 +813,29 @@ static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, i
return 0;
}
+static int qcom_battmgr_set_charge_control_limit(struct qcom_battmgr *battmgr, int limit)
+{
+ int ret;
+
+ if (limit < 0)
+ return -EINVAL;
+
+ guard(mutex)(&battmgr->lock);
+
+ ret = qcom_battmgr_request_property(battmgr, BATTMGR_BAT_PROPERTY_GET,
+ BATT_CHG_CTRL_LIM_MAX, 0);
+ if (ret)
+ return ret;
+
+ if (!battmgr->info.charge_ctrl_limit_max)
+ return -ENODATA;
+
+ limit = min_t(u32, limit, battmgr->info.charge_ctrl_limit_max);
+
+ return qcom_battmgr_request_property(battmgr, BATTMGR_BAT_PROPERTY_SET,
+ BATT_CHG_CTRL_LIM, limit);
+}
+
static int qcom_battmgr_charge_control_thresholds_init(struct qcom_battmgr *battmgr)
{
int ret;
@@ -838,6 +871,7 @@ static int qcom_battmgr_bat_is_writeable(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return 1;
default:
return 0;
@@ -860,6 +894,8 @@ static int qcom_battmgr_bat_set_property(struct power_supply *psy,
return qcom_battmgr_set_charge_start_threshold(battmgr, pval->intval);
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
return qcom_battmgr_set_charge_end_threshold(battmgr, pval->intval);
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ return qcom_battmgr_set_charge_control_limit(battmgr, pval->intval);
default:
return -EINVAL;
}
@@ -995,6 +1031,8 @@ static const enum power_supply_property sm8550_bat_props[] = {
POWER_SUPPLY_PROP_POWER_NOW,
POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD,
POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
};
static const struct power_supply_desc sm8550_bat_psy_desc = {
@@ -1618,11 +1656,28 @@ static void qcom_battmgr_sm8350_callback(struct qcom_battmgr *battmgr,
case BATT_CHG_CTRL_END_THR:
battmgr->info.charge_ctrl_end = le32_to_cpu(resp->intval.value);
break;
+ case BATT_CHG_CTRL_LIM:
+ battmgr->info.charge_ctrl_limit = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CHG_CTRL_LIM_MAX:
+ battmgr->info.charge_ctrl_limit_max = le32_to_cpu(resp->intval.value);
+ break;
default:
dev_warn(battmgr->dev, "unknown property %#x\n", property);
break;
}
break;
+ case BATTMGR_BAT_PROPERTY_SET:
+ if (payload_len != sizeof(resp->intval)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for battery property set: %zd\n",
+ payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+
+ battmgr->error = le32_to_cpu(resp->intval.result) ? -EIO : 0;
+ break;
case BATTMGR_USB_PROPERTY_GET:
property = le32_to_cpu(resp->intval.property);
if (payload_len != sizeof(resp->intval)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-12 13:49 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 13:49 [PATCH v2 0/2] power: supply: qcom_battmgr: Kaanapali current sign and charge current limit Joonhoe Kim
2026-11-12 13:49 ` [PATCH v2 1/2] power: supply: qcom_battmgr: fix the battery current sign on Kaanapali Joonhoe Kim
2026-11-12 13:49 ` [PATCH v2 2/2] power: supply: qcom_battmgr: expose the charge current limit Joonhoe Kim
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.