From 9c5b523f78f344d72fb934f1f6c021b58316feec Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Sat, 18 Feb 2017 10:11:34 +0530 Subject: [PATCH] power: qcom-charger: delay ICL change reporting to parallel psy ICL change interrupt triggers whenever there is change in the input ICL, in case of AICL restart(done as part of S/W base pulsing) AICL starts from 500mA and ICL change gets triggered for every 25mA ICL as part of AICL ramping. ICL change handler generates a power_supply event on parallel psys and thus causing parallel framework to re-split ICL for every 25mA. Fix this by delaying power_supply event until AICL settles. Change-Id: I9270a99f536db4534e46764b2e053ff93b38cb54 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/smb-lib.c | 56 +++++++++++++++++++++++++++++-------- drivers/power/supply/qcom/smb-lib.h | 1 + 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 896da30a5699..ce2e077c4f07 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -3080,26 +3080,38 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) } #define USB_WEAK_INPUT_UA 1400000 +#define ICL_CHANGE_DELAY_MS 1000 irqreturn_t smblib_handle_icl_change(int irq, void *data) { + u8 stat; + int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS; struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; - int rc, settled_ua; - - rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc); - return IRQ_HANDLED; - } if (chg->mode == PARALLEL_MASTER) { - power_supply_changed(chg->usb_main_psy); - vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, - settled_ua >= USB_WEAK_INPUT_UA, 0); + rc = smblib_read(chg, AICL_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", + rc); + return IRQ_HANDLED; + } + + rc = smblib_get_charge_param(chg, &chg->param.icl_stat, + &settled_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc); + return IRQ_HANDLED; + } + + /* If AICL settled then schedule work now */ + if ((settled_ua == get_effective_result(chg->usb_icl_votable)) + || (stat & AICL_DONE_BIT)) + delay = 0; + + schedule_delayed_work(&chg->icl_change_work, + msecs_to_jiffies(delay)); } - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s icl_settled=%d\n", - irq_data->name, settled_ua); return IRQ_HANDLED; } @@ -3968,6 +3980,25 @@ static void smblib_otg_ss_done_work(struct work_struct *work) mutex_unlock(&chg->otg_oc_lock); } +static void smblib_icl_change_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + icl_change_work.work); + int rc, settled_ua; + + rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc); + return; + } + + power_supply_changed(chg->usb_main_psy); + vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, + settled_ua >= USB_WEAK_INPUT_UA, 0); + + smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua); +} + static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; @@ -4148,6 +4179,7 @@ int smblib_init(struct smb_charger *chg) INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work); + INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); chg->fake_capacity = -EINVAL; switch (chg->mode) { diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 0ee591d5e6ce..7c29954b3bff 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -280,6 +280,7 @@ struct smb_charger { struct work_struct otg_oc_work; struct work_struct vconn_oc_work; struct delayed_work otg_ss_done_work; + struct delayed_work icl_change_work; /* cached status */ int voltage_min_uv; -- 2.11.0