diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 3538310ae107..817e2ce65b02 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -234,7 +234,11 @@ struct battery_chg_dev { struct notifier_block reboot_notifier; u32 thermal_fcc_ua; u32 restrict_fcc_ua; + u32 last_fcc_ua; + u32 usb_icl_ua; bool restrict_chg_en; + /* To track the driver initialization status */ + bool initialized; }; static const int battery_prop_map[BATT_PROP_MAX] = { @@ -421,14 +425,6 @@ static void battery_chg_notify_enable(struct battery_chg_dev *bcdev) pr_err("Failed to enable notification rc=%d\n", rc); } -static void battery_chg_subsys_up_work(struct work_struct *work) -{ - struct battery_chg_dev *bcdev = container_of(work, - struct battery_chg_dev, subsys_up_work); - - battery_chg_notify_enable(bcdev); -} - static void battery_chg_state_cb(void *priv, enum pmic_glink_state state) { struct battery_chg_dev *bcdev = priv; @@ -636,6 +632,11 @@ static void battery_chg_update_usb_type_work(struct work_struct *work) return; } + /* Reset usb_icl_ua whenever USB adapter type changes */ + if (pst->prop[USB_ADAP_TYPE] != POWER_SUPPLY_USB_TYPE_SDP && + pst->prop[USB_ADAP_TYPE] != POWER_SUPPLY_USB_TYPE_PD) + bcdev->usb_icl_ua = 0; + pr_debug("usb_adap_type: %u\n", pst->prop[USB_ADAP_TYPE]); switch (pst->prop[USB_ADAP_TYPE]) { @@ -720,6 +721,12 @@ static int battery_chg_callback(void *priv, void *data, size_t len) pr_debug("owner: %u type: %u opcode: %#x len: %zu\n", hdr->owner, hdr->type, hdr->opcode, len); + if (!bcdev->initialized) { + pr_debug("Driver initialization failed: Dropping glink callback message: state %d\n", + bcdev->state); + return 0; + } + if (hdr->opcode == BC_NOTIFY_IND) handle_notification(bcdev, data, len); else @@ -811,8 +818,10 @@ static int usb_psy_set_icl(struct battery_chg_dev *bcdev, u32 prop_id, int val) int rc; rc = read_property_id(bcdev, pst, USB_ADAP_TYPE); - if (rc < 0) + if (rc < 0) { + pr_err("Failed to read prop USB_ADAP_TYPE, rc=%d\n", rc); return rc; + } /* Allow this only for SDP or USB_PD and not for other charger types */ if (pst->prop[USB_ADAP_TYPE] != POWER_SUPPLY_USB_TYPE_SDP && @@ -831,8 +840,12 @@ static int usb_psy_set_icl(struct battery_chg_dev *bcdev, u32 prop_id, int val) temp = UINT_MAX; rc = write_property_id(bcdev, pst, prop_id, temp); - if (!rc) + if (rc < 0) { + pr_err("Failed to set ICL (%u uA) rc=%d\n", temp, rc); + } else { pr_debug("Set ICL to %u\n", temp); + bcdev->usb_icl_ua = temp; + } return rc; } @@ -946,10 +959,12 @@ static int __battery_psy_set_charge_current(struct battery_chg_dev *bcdev, rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_BATTERY], BATT_CHG_CTRL_LIM, fcc_ua); - if (rc < 0) + if (rc < 0) { pr_err("Failed to set FCC %u, rc=%d\n", fcc_ua, rc); - else + } else { pr_debug("Set FCC to %u uA\n", fcc_ua); + bcdev->last_fcc_ua = fcc_ua; + } return rc; } @@ -1128,6 +1143,38 @@ static int battery_chg_init_psy(struct battery_chg_dev *bcdev) return 0; } +static void battery_chg_subsys_up_work(struct work_struct *work) +{ + struct battery_chg_dev *bcdev = container_of(work, + struct battery_chg_dev, subsys_up_work); + int rc; + + battery_chg_notify_enable(bcdev); + + /* + * Give some time after enabling notification so that USB adapter type + * information can be obtained properly which is essential for setting + * USB ICL. + */ + msleep(200); + + if (bcdev->last_fcc_ua) { + rc = __battery_psy_set_charge_current(bcdev, + bcdev->last_fcc_ua); + if (rc < 0) + pr_err("Failed to set FCC (%u uA), rc=%d\n", + bcdev->last_fcc_ua, rc); + } + + if (bcdev->usb_icl_ua) { + rc = usb_psy_set_icl(bcdev, USB_INPUT_CURR_LIMIT, + bcdev->usb_icl_ua); + if (rc < 0) + pr_err("Failed to set ICL(%u uA), rc=%d\n", + bcdev->usb_icl_ua, rc); + } +} + static int wireless_fw_send_firmware(struct battery_chg_dev *bcdev, const struct firmware *fw) { @@ -1695,8 +1742,11 @@ static int battery_chg_parse_dt(struct battery_chg_dev *bcdev) len = rc; rc = read_property_id(bcdev, pst, BATT_CHG_CTRL_LIM_MAX); - if (rc < 0) + if (rc < 0) { + pr_err("Failed to read prop BATT_CHG_CTRL_LIM_MAX, rc=%d\n", + rc); return rc; + } prev = pst->prop[BATT_CHG_CTRL_LIM_MAX]; @@ -1827,13 +1877,16 @@ static int battery_chg_probe(struct platform_device *pdev) return rc; } + bcdev->initialized = true; bcdev->reboot_notifier.notifier_call = battery_chg_ship_mode; bcdev->reboot_notifier.priority = 255; register_reboot_notifier(&bcdev->reboot_notifier); rc = battery_chg_parse_dt(bcdev); - if (rc < 0) + if (rc < 0) { + dev_err(dev, "Failed to parse dt rc=%d\n", rc); goto error; + } bcdev->restrict_fcc_ua = DEFAULT_RESTRICT_FCC_UA; platform_set_drvdata(pdev, bcdev); @@ -1846,7 +1899,7 @@ static int battery_chg_probe(struct platform_device *pdev) bcdev->battery_class.class_groups = battery_class_groups; rc = class_register(&bcdev->battery_class); if (rc < 0) { - pr_err("Failed to create battery_class rc=%d\n", rc); + dev_err(dev, "Failed to create battery_class rc=%d\n", rc); goto error; } @@ -1856,6 +1909,8 @@ static int battery_chg_probe(struct platform_device *pdev) return 0; error: + bcdev->initialized = false; + complete(&bcdev->ack); pmic_glink_unregister_client(bcdev->client); unregister_reboot_notifier(&bcdev->reboot_notifier); return rc;