Loading drivers/power/supply/qcom/step-chg-jeita.c +75 −20 Original line number Diff line number Diff line /* Copyright (c) 2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -79,10 +79,12 @@ struct step_chg_info { struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; struct wakeup_source *step_chg_ws; struct power_supply *batt_psy; struct power_supply *bms_psy; struct power_supply *main_psy; struct power_supply *usb_psy; struct delayed_work status_change_work; struct delayed_work get_config_work; struct notifier_block nb; Loading Loading @@ -119,6 +121,17 @@ static bool is_bms_available(struct step_chg_info *chip) return true; } static bool is_usb_available(struct step_chg_info *chip) { if (!chip->usb_psy) chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) return false; return true; } static int read_range_data_from_node(struct device_node *node, const char *prop_str, struct range_data *ranges, u32 max_threshold, u32 max_value) Loading Loading @@ -486,6 +499,7 @@ static int handle_step_chg_config(struct step_chg_info *chip) return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000); } #define JEITA_SUSPEND_HYST_UV 50000 static int handle_jeita(struct step_chg_info *chip) { union power_supply_propval pval = {0, }; Loading @@ -504,6 +518,8 @@ static int handle_jeita(struct step_chg_info *chip) vote(chip->fcc_votable, JEITA_VOTER, false, 0); if (chip->fv_votable) vote(chip->fv_votable, JEITA_VOTER, false, 0); if (chip->usb_icl_votable) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); return 0; } Loading @@ -525,12 +541,8 @@ static int handle_jeita(struct step_chg_info *chip) pval.intval, &chip->jeita_fcc_index, &fcc_ua); if (rc < 0) { /* remove the vote if no step-based fcc is found */ if (chip->fcc_votable) vote(chip->fcc_votable, JEITA_VOTER, false, 0); goto update_time; } if (rc < 0) fcc_ua = 0; if (!chip->fcc_votable) chip->fcc_votable = find_votable("FCC"); Loading @@ -538,7 +550,7 @@ static int handle_jeita(struct step_chg_info *chip) /* changing FCC is a must */ return -EINVAL; vote(chip->fcc_votable, JEITA_VOTER, true, fcc_ua); vote(chip->fcc_votable, JEITA_VOTER, fcc_ua ? true : false, fcc_ua); rc = get_val(chip->jeita_fv_config->fv_cfg, chip->jeita_fv_config->hysteresis, Loading @@ -546,21 +558,45 @@ static int handle_jeita(struct step_chg_info *chip) pval.intval, &chip->jeita_fv_index, &fv_uv); if (rc < 0) { /* remove the vote if no step-based fcc is found */ if (chip->fv_votable) vote(chip->fv_votable, JEITA_VOTER, false, 0); goto update_time; } if (rc < 0) fv_uv = 0; chip->fv_votable = find_votable("FV"); if (!chip->fv_votable) goto update_time; vote(chip->fv_votable, JEITA_VOTER, true, fv_uv); if (!chip->usb_icl_votable) chip->usb_icl_votable = find_votable("USB_ICL"); pr_debug("%s = %d FCC = %duA FV = %duV\n", chip->jeita_fcc_config->prop_name, pval.intval, fcc_ua, fv_uv); if (!chip->usb_icl_votable) goto set_jeita_fv; /* * If JEITA float voltage is same as max-vfloat of battery then * skip any further VBAT specific checks. */ rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); if (rc || (pval.intval == fv_uv)) { vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); goto set_jeita_fv; } /* * Suspend USB input path if battery voltage is above * JEITA VFLOAT threshold. */ if (fv_uv > 0) { rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); if (!rc && (pval.intval > fv_uv)) vote(chip->usb_icl_votable, JEITA_VOTER, true, 0); else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV)) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); } set_jeita_fv: vote(chip->fv_votable, JEITA_VOTER, fv_uv ? true : false, fv_uv); update_time: chip->jeita_last_update_time = ktime_get(); Loading Loading @@ -618,11 +654,13 @@ static void status_change_work(struct work_struct *work) int reschedule_us; int reschedule_jeita_work_us = 0; int reschedule_step_work_us = 0; union power_supply_propval prop = {0, }; if (!is_batt_available(chip)) return; goto exit_work; handle_battery_insertion(chip); /* skip elapsed_us debounce for handling battery temperature */ rc = handle_jeita(chip); if (rc > 0) Loading @@ -636,12 +674,28 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Couldn't handle step rc = %d\n", rc); /* Remove stale votes on USB removal */ if (is_usb_available(chip)) { prop.intval = 0; power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PRESENT, &prop); if (!prop.intval) { if (chip->usb_icl_votable) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); } } reschedule_us = min(reschedule_jeita_work_us, reschedule_step_work_us); if (reschedule_us == 0) __pm_relax(chip->step_chg_ws); goto exit_work; else schedule_delayed_work(&chip->status_change_work, usecs_to_jiffies(reschedule_us)); return; exit_work: __pm_relax(chip->step_chg_ws); } static int step_chg_notifier_call(struct notifier_block *nb, Loading @@ -653,7 +707,8 @@ static int step_chg_notifier_call(struct notifier_block *nb, if (ev != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; if ((strcmp(psy->desc->name, "battery") == 0)) { if ((strcmp(psy->desc->name, "battery") == 0) || (strcmp(psy->desc->name, "usb") == 0)) { __pm_stay_awake(chip->step_chg_ws); schedule_delayed_work(&chip->status_change_work, 0); } Loading Loading
drivers/power/supply/qcom/step-chg-jeita.c +75 −20 Original line number Diff line number Diff line /* Copyright (c) 2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -79,10 +79,12 @@ struct step_chg_info { struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; struct wakeup_source *step_chg_ws; struct power_supply *batt_psy; struct power_supply *bms_psy; struct power_supply *main_psy; struct power_supply *usb_psy; struct delayed_work status_change_work; struct delayed_work get_config_work; struct notifier_block nb; Loading Loading @@ -119,6 +121,17 @@ static bool is_bms_available(struct step_chg_info *chip) return true; } static bool is_usb_available(struct step_chg_info *chip) { if (!chip->usb_psy) chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) return false; return true; } static int read_range_data_from_node(struct device_node *node, const char *prop_str, struct range_data *ranges, u32 max_threshold, u32 max_value) Loading Loading @@ -486,6 +499,7 @@ static int handle_step_chg_config(struct step_chg_info *chip) return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000); } #define JEITA_SUSPEND_HYST_UV 50000 static int handle_jeita(struct step_chg_info *chip) { union power_supply_propval pval = {0, }; Loading @@ -504,6 +518,8 @@ static int handle_jeita(struct step_chg_info *chip) vote(chip->fcc_votable, JEITA_VOTER, false, 0); if (chip->fv_votable) vote(chip->fv_votable, JEITA_VOTER, false, 0); if (chip->usb_icl_votable) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); return 0; } Loading @@ -525,12 +541,8 @@ static int handle_jeita(struct step_chg_info *chip) pval.intval, &chip->jeita_fcc_index, &fcc_ua); if (rc < 0) { /* remove the vote if no step-based fcc is found */ if (chip->fcc_votable) vote(chip->fcc_votable, JEITA_VOTER, false, 0); goto update_time; } if (rc < 0) fcc_ua = 0; if (!chip->fcc_votable) chip->fcc_votable = find_votable("FCC"); Loading @@ -538,7 +550,7 @@ static int handle_jeita(struct step_chg_info *chip) /* changing FCC is a must */ return -EINVAL; vote(chip->fcc_votable, JEITA_VOTER, true, fcc_ua); vote(chip->fcc_votable, JEITA_VOTER, fcc_ua ? true : false, fcc_ua); rc = get_val(chip->jeita_fv_config->fv_cfg, chip->jeita_fv_config->hysteresis, Loading @@ -546,21 +558,45 @@ static int handle_jeita(struct step_chg_info *chip) pval.intval, &chip->jeita_fv_index, &fv_uv); if (rc < 0) { /* remove the vote if no step-based fcc is found */ if (chip->fv_votable) vote(chip->fv_votable, JEITA_VOTER, false, 0); goto update_time; } if (rc < 0) fv_uv = 0; chip->fv_votable = find_votable("FV"); if (!chip->fv_votable) goto update_time; vote(chip->fv_votable, JEITA_VOTER, true, fv_uv); if (!chip->usb_icl_votable) chip->usb_icl_votable = find_votable("USB_ICL"); pr_debug("%s = %d FCC = %duA FV = %duV\n", chip->jeita_fcc_config->prop_name, pval.intval, fcc_ua, fv_uv); if (!chip->usb_icl_votable) goto set_jeita_fv; /* * If JEITA float voltage is same as max-vfloat of battery then * skip any further VBAT specific checks. */ rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); if (rc || (pval.intval == fv_uv)) { vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); goto set_jeita_fv; } /* * Suspend USB input path if battery voltage is above * JEITA VFLOAT threshold. */ if (fv_uv > 0) { rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); if (!rc && (pval.intval > fv_uv)) vote(chip->usb_icl_votable, JEITA_VOTER, true, 0); else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV)) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); } set_jeita_fv: vote(chip->fv_votable, JEITA_VOTER, fv_uv ? true : false, fv_uv); update_time: chip->jeita_last_update_time = ktime_get(); Loading Loading @@ -618,11 +654,13 @@ static void status_change_work(struct work_struct *work) int reschedule_us; int reschedule_jeita_work_us = 0; int reschedule_step_work_us = 0; union power_supply_propval prop = {0, }; if (!is_batt_available(chip)) return; goto exit_work; handle_battery_insertion(chip); /* skip elapsed_us debounce for handling battery temperature */ rc = handle_jeita(chip); if (rc > 0) Loading @@ -636,12 +674,28 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Couldn't handle step rc = %d\n", rc); /* Remove stale votes on USB removal */ if (is_usb_available(chip)) { prop.intval = 0; power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PRESENT, &prop); if (!prop.intval) { if (chip->usb_icl_votable) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); } } reschedule_us = min(reschedule_jeita_work_us, reschedule_step_work_us); if (reschedule_us == 0) __pm_relax(chip->step_chg_ws); goto exit_work; else schedule_delayed_work(&chip->status_change_work, usecs_to_jiffies(reschedule_us)); return; exit_work: __pm_relax(chip->step_chg_ws); } static int step_chg_notifier_call(struct notifier_block *nb, Loading @@ -653,7 +707,8 @@ static int step_chg_notifier_call(struct notifier_block *nb, if (ev != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; if ((strcmp(psy->desc->name, "battery") == 0)) { if ((strcmp(psy->desc->name, "battery") == 0) || (strcmp(psy->desc->name, "usb") == 0)) { __pm_stay_awake(chip->step_chg_ws); schedule_delayed_work(&chip->status_change_work, 0); } Loading