From 0bca9d95c7ccadf36e62449f045a53109d17fa08 Mon Sep 17 00:00:00 2001 From: Vic Wei Date: Mon, 22 Jan 2018 08:21:03 -0800 Subject: [PATCH] battery: handle early/late suspend/resume of i2c bus The i2c bus could suspend right after the parallel charger's suspend i.e. no i2c access available during suspend_noirq stages. Similarly on the resume path, there is no i2c access until resume() callback. However the PMI can handle interrupts right before its own suspend_irq and right after its own resume_irq. Those interrupts could invoke transactions for parallel charger but that is either too late or very early for any i2c transactions. To fix this, hold a wakelock once parallel is enabled and release the wakelock 5 seconds after parallel is disabled. Change-Id: Id517b5afca090d7f3ccb31e640512bdb9f902377 Signed-off-by: Harry Yang Signed-off-by: Vic Wei --- drivers/power/supply/qcom/battery.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 68640e349765..e068bec8b85e 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -58,6 +58,7 @@ struct pl_data { struct delayed_work status_change_work; struct work_struct pl_disable_forever_work; struct delayed_work pl_taper_work; + struct delayed_work pl_awake_work; struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; @@ -640,6 +641,14 @@ static void pl_disable_forever_work(struct work_struct *work) vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER, false, 0); } +static void pl_awake_work(struct work_struct *work) +{ + struct pl_data *chip = container_of(work, + struct pl_data, pl_awake_work.work); + + vote(chip->pl_awake_votable, PL_VOTER, false, 0); +} + static int pl_disable_vote_callback(struct votable *votable, void *data, int pl_disable, const char *client) { @@ -652,6 +661,11 @@ static int pl_disable_vote_callback(struct votable *votable, chip->pl_settled_ua = 0; if (!pl_disable) { /* enable */ + /* keep system awake to talk to slave charger through i2c */ + cancel_delayed_work_sync(&chip->pl_awake_work); + if (chip->pl_awake_votable) + vote(chip->pl_awake_votable, PL_VOTER, true, 0); + rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); if (rc == -ENODEV) { @@ -712,6 +726,11 @@ static int pl_disable_vote_callback(struct votable *votable, } rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); + + cancel_delayed_work_sync(&chip->pl_awake_work); + if (chip->pl_awake_votable) + schedule_delayed_work(&chip->pl_awake_work, + msecs_to_jiffies(5000)); } pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", @@ -1098,6 +1117,7 @@ int qcom_batt_init(void) INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work); INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work); + INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work); rc = pl_register_notifier(chip); if (rc < 0) { @@ -1151,6 +1171,7 @@ void qcom_batt_deinit(void) cancel_delayed_work_sync(&chip->status_change_work); cancel_delayed_work_sync(&chip->pl_taper_work); cancel_work_sync(&chip->pl_disable_forever_work); + cancel_delayed_work_sync(&chip->pl_awake_work); power_supply_unreg_notifier(&chip->nb); destroy_votable(chip->pl_enable_votable_indirect);