From 648cd705463c3ddfccd7caea5f6e5a7745ee7f24 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 13 Apr 2021 14:28:57 -0700 Subject: [PATCH 1/6] power: qti_battery_charger: support configuring wireless FW update time Currently, during wireless FW update process, qti_battery_charger driver waits for FW update status for a period of 1 second after sending all of the FW chunks. This wireless FW update time depends on the wireless transceiver being used. E.g. IDT9412 needed only 1 second but IDT9415 requires up to 2 seconds as computing and validating the CRC seems to be consuming more time. To support such variance in wireless FW update time, add a parameter which can be configured at runtime. This can be configured (in ms) as below. echo 2000 > /sys/class/qcom-battery/wireless_fw_update_time_ms Change-Id: Ifa8104544138254e1029ab1fcaa9f40e61cc0961 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 22ef4150b91a..d1ef01573da6 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -235,6 +235,7 @@ struct battery_chg_dev { bool wls_fw_update_reqd; u32 wls_fw_version; u16 wls_fw_crc; + u32 wls_fw_update_time_ms; struct notifier_block reboot_notifier; u32 thermal_fcc_ua; u32 restrict_fcc_ua; @@ -1335,13 +1336,16 @@ static int wireless_fw_update(struct battery_chg_dev *bcdev, bool force) goto release_fw; } + pr_debug("Waiting for fw_update_ack\n"); rc = wait_for_completion_timeout(&bcdev->fw_update_ack, - msecs_to_jiffies(WLS_FW_UPDATE_TIME_MS)); + msecs_to_jiffies(bcdev->wls_fw_update_time_ms)); if (!rc) { pr_err("Error, timed out updating firmware\n"); rc = -ETIMEDOUT; goto release_fw; } else { + pr_debug("Waited for %d ms\n", + bcdev->wls_fw_update_time_ms - jiffies_to_msecs(rc)); rc = 0; } @@ -1356,6 +1360,29 @@ static int wireless_fw_update(struct battery_chg_dev *bcdev, bool force) return rc; } +static ssize_t wireless_fw_update_time_ms_store(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + + if (kstrtou32(buf, 0, &bcdev->wls_fw_update_time_ms)) + return -EINVAL; + + return count; +} + +static ssize_t wireless_fw_update_time_ms_show(struct class *c, + struct class_attribute *attr, char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + + return scnprintf(buf, PAGE_SIZE, "%u\n", bcdev->wls_fw_update_time_ms); +} +static CLASS_ATTR_RW(wireless_fw_update_time_ms); + static ssize_t wireless_fw_crc_store(struct class *c, struct class_attribute *attr, const char *buf, size_t count) @@ -1719,6 +1746,7 @@ static struct attribute *battery_class_attrs[] = { &class_attr_wireless_fw_force_update.attr, &class_attr_wireless_fw_version.attr, &class_attr_wireless_fw_crc.attr, + &class_attr_wireless_fw_update_time_ms.attr, &class_attr_ship_mode_en.attr, &class_attr_restrict_chg.attr, &class_attr_restrict_cur.attr, @@ -1948,6 +1976,7 @@ static int battery_chg_probe(struct platform_device *pdev) goto error; } + bcdev->wls_fw_update_time_ms = WLS_FW_UPDATE_TIME_MS; battery_chg_add_debugfs(bcdev); battery_chg_notify_enable(bcdev); device_init_wakeup(bcdev->dev, true); From 7fbbeb3710d995ab7c82a6084db8257605b8ab58 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 20 Apr 2021 10:08:39 -0700 Subject: [PATCH 2/6] power: supply: qti_battery_charger: Handle BC_SHIP_MODE_REQ_SET response During shutdown when configuring ship mode based on user request, battery charger driver sends BC_SHIP_MODE_REQ_SET message to the charger firmware to do configuration before the shutdown. However the response from the charger firmware is not handled and hence a timeout is observed in the logs. Fix it. Fixes: 1df95fc50926 ("power: supply: qti_battery_charger: Enable Ship mode shutdown") Change-Id: I9149a256e4af40c3dcf2f0019f27e711a97f4493 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index d1ef01573da6..134181bfc69f 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -570,7 +570,8 @@ static void handle_message(struct battery_chg_dev *bcdev, void *data, break; case BC_SET_NOTIFY_REQ: case BC_SHUTDOWN_NOTIFY: - /* Always ACK response for notify request */ + case BC_SHIP_MODE_REQ_SET: + /* Always ACK response for notify or ship_mode request */ ack_set = true; break; case BC_WLS_FW_CHECK_UPDATE: From e395d85f4e00c30c38ef3bf143be6e12755f65c3 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 17 Jun 2021 20:03:08 -0700 Subject: [PATCH 3/6] power: supply: qti_battery_charger: Increase wireless FW prepare time Currently, prepare time for wireless FW update is set to 300 ms. This was sufficient enough for previous targets which had used wireless receiver IDT9412. For IDT9415, a prepare time > 300 ms is required to make sure pre-regulator is disabled and WLS_IN is plugged out. Hence, increase this to 1 second so that it can be well accommodated. Change-Id: Ibff4ec606257e04fcf0405c3f145585d30a38ed7 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 134181bfc69f..4f3f2aa93e01 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -45,7 +45,7 @@ /* Generic definitions */ #define MAX_STR_LEN 128 #define BC_WAIT_TIME_MS 1000 -#define WLS_FW_PREPARE_TIME_MS 300 +#define WLS_FW_PREPARE_TIME_MS 1000 #define WLS_FW_WAIT_TIME_MS 500 #define WLS_FW_UPDATE_TIME_MS 1000 #define WLS_FW_BUF_SIZE 128 From 721490d386a0e07bbbd438a59a0691f2b155bfa9 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 16 Jul 2021 13:43:04 -0700 Subject: [PATCH 4/6] power: supply: qti_battery_charger: add support for emergency shutdown Currently, when SOC reaches 0 and device is not charging, we depend on the userspace (e.g. Android battery manager service) to initiate a shutdown. Sometimes, this takes more time than expected (> 20 seconds). When the device is discharging with a high system load, this may cause device to brown out as the battery voltage can go below the safe operating level. Add support to initiate an emergency shutdown when the following conditions are met. - Battery SOC is 0 - Battery is not charging - Battery voltage is lower than a specified level Add "qcom,shutdown-voltage" to support this. Change-Id: I542ae08037c4e9db23d338b8de2eeb32c809a0a6 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 4f3f2aa93e01..91fea9808c01 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -225,9 +226,11 @@ struct battery_chg_dev { const char *wls_fw_name; int curr_thermal_level; int num_thermal_levels; + int shutdown_volt_mv; atomic_t state; struct work_struct subsys_up_work; struct work_struct usb_type_work; + struct work_struct battery_check_work; int fake_soc; bool block_tx; bool ship_mode_en; @@ -680,6 +683,60 @@ static void battery_chg_update_usb_type_work(struct work_struct *work) } } +static void battery_chg_check_status_work(struct work_struct *work) +{ + struct battery_chg_dev *bcdev = container_of(work, + struct battery_chg_dev, + battery_check_work); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_BATTERY]; + int rc; + + rc = read_property_id(bcdev, pst, BATT_STATUS); + if (rc < 0) { + pr_err("Failed to read BATT_STATUS, rc=%d\n", rc); + return; + } + + if (pst->prop[BATT_STATUS] == POWER_SUPPLY_STATUS_CHARGING) { + pr_debug("Battery is charging\n"); + return; + } + + rc = read_property_id(bcdev, pst, BATT_CAPACITY); + if (rc < 0) { + pr_err("Failed to read BATT_CAPACITY, rc=%d\n", rc); + return; + } + + if (DIV_ROUND_CLOSEST(pst->prop[BATT_CAPACITY], 100) > 0) { + pr_debug("Battery SOC is > 0\n"); + return; + } + + /* + * If we are here, then battery is not charging and SOC is 0. + * Check the battery voltage and if it's lower than shutdown voltage, + * then initiate an emergency shutdown. + */ + + rc = read_property_id(bcdev, pst, BATT_VOLT_NOW); + if (rc < 0) { + pr_err("Failed to read BATT_VOLT_NOW, rc=%d\n", rc); + return; + } + + if (pst->prop[BATT_VOLT_NOW] / 1000 > bcdev->shutdown_volt_mv) { + pr_debug("Battery voltage is > %d mV\n", + bcdev->shutdown_volt_mv); + return; + } + + pr_emerg("Initiating a shutdown in 100 ms\n"); + msleep(100); + pr_emerg("Attempting kernel_power_off: Battery voltage low\n"); + kernel_power_off(); +} + static void handle_notification(struct battery_chg_dev *bcdev, void *data, size_t len) { @@ -697,6 +754,8 @@ static void handle_notification(struct battery_chg_dev *bcdev, void *data, case BC_BATTERY_STATUS_GET: case BC_GENERIC_NOTIFY: pst = &bcdev->psy_list[PSY_TYPE_BATTERY]; + if (bcdev->shutdown_volt_mv > 0) + schedule_work(&bcdev->battery_check_work); break; case BC_USB_STATUS_GET: pst = &bcdev->psy_list[PSY_TYPE_USB]; @@ -1799,6 +1858,9 @@ static int battery_chg_parse_dt(struct battery_chg_dev *bcdev) of_property_read_string(node, "qcom,wireless-fw-name", &bcdev->wls_fw_name); + of_property_read_u32(node, "qcom,shutdown-voltage", + &bcdev->shutdown_volt_mv); + rc = of_property_count_elems_of_size(node, "qcom,thermal-mitigation", sizeof(u32)); if (rc <= 0) @@ -1933,6 +1995,7 @@ static int battery_chg_probe(struct platform_device *pdev) init_completion(&bcdev->fw_update_ack); INIT_WORK(&bcdev->subsys_up_work, battery_chg_subsys_up_work); INIT_WORK(&bcdev->usb_type_work, battery_chg_update_usb_type_work); + INIT_WORK(&bcdev->battery_check_work, battery_chg_check_status_work); atomic_set(&bcdev->state, PMIC_GLINK_STATE_UP); bcdev->dev = dev; From 0381948dcc73540a6952038fc9c610635c99fc76 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 30 Sep 2021 10:36:31 -0700 Subject: [PATCH 5/6] power: supply: qti_battery_charger: change battery power supply registration Userspace health HAL implementation waits for capacity property from the battery power supply to be available before starting health HAL service. This is needed to ensure the battery power supply device is found by health HAL consistently. However, if the registration of other power supply devices like USB and Wireless takes time and health HAL initializes before that, Android battery monitor would not be reading any properties from these power supply devices. Fix this by registering the battery power supply after registering USB and Wireless power supply. This would ensure that by the time health HAL initializes, USB and Wireless power supply devices can be available. CRs-Fixed: 2998433 Change-Id: I3b71c86eaa774bdfcef3686109d7a25ac52be16c Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 91fea9808c01..b1e210f43168 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -1192,15 +1192,6 @@ static int battery_chg_init_psy(struct battery_chg_dev *bcdev) psy_cfg.drv_data = bcdev; psy_cfg.of_node = bcdev->dev->of_node; - bcdev->psy_list[PSY_TYPE_BATTERY].psy = - devm_power_supply_register(bcdev->dev, &batt_psy_desc, - &psy_cfg); - if (IS_ERR(bcdev->psy_list[PSY_TYPE_BATTERY].psy)) { - rc = PTR_ERR(bcdev->psy_list[PSY_TYPE_BATTERY].psy); - pr_err("Failed to register battery power supply, rc=%d\n", rc); - return rc; - } - bcdev->psy_list[PSY_TYPE_USB].psy = devm_power_supply_register(bcdev->dev, &usb_psy_desc, &psy_cfg); if (IS_ERR(bcdev->psy_list[PSY_TYPE_USB].psy)) { @@ -1217,6 +1208,15 @@ static int battery_chg_init_psy(struct battery_chg_dev *bcdev) return rc; } + bcdev->psy_list[PSY_TYPE_BATTERY].psy = + devm_power_supply_register(bcdev->dev, &batt_psy_desc, + &psy_cfg); + if (IS_ERR(bcdev->psy_list[PSY_TYPE_BATTERY].psy)) { + rc = PTR_ERR(bcdev->psy_list[PSY_TYPE_BATTERY].psy); + pr_err("Failed to register battery power supply, rc=%d\n", rc); + return rc; + } + return 0; } From d3e136b7232b22e83fd85216081f2c52d8cbbad0 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 3 Dec 2021 19:07:52 -0800 Subject: [PATCH 6/6] power: supply: qti_battery_charger: Fix debugfs_create_bool() usage debugfs_create_bool() return type got changed. Fix it. Change-Id: Ia83ed4b50a42b22718bdf5bc6ba0c2b25f0a5631 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index b1e210f43168..421d11e93dbd 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "BATTERY_CHG: %s: " fmt, __func__ @@ -1820,7 +1821,7 @@ ATTRIBUTE_GROUPS(battery_class); static void battery_chg_add_debugfs(struct battery_chg_dev *bcdev) { int rc; - struct dentry *dir, *file; + struct dentry *dir; dir = debugfs_create_dir("battery_charger", NULL); if (IS_ERR(dir)) { @@ -1830,19 +1831,8 @@ static void battery_chg_add_debugfs(struct battery_chg_dev *bcdev) return; } - file = debugfs_create_bool("block_tx", 0600, dir, &bcdev->block_tx); - if (IS_ERR(file)) { - rc = PTR_ERR(file); - pr_err("Failed to create block_tx debugfs file, rc=%d\n", - rc); - goto error; - } - bcdev->debugfs_dir = dir; - - return; -error: - debugfs_remove_recursive(dir); + debugfs_create_bool("block_tx", 0600, dir, &bcdev->block_tx); } #else static void battery_chg_add_debugfs(struct battery_chg_dev *bcdev) { }