From fc21ea7f2a3b52e43b012f1436044cdff7697498 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 23 Jun 2016 14:54:43 -0700 Subject: [PATCH] qcom-charger: update parallel charging states after boot If a USB charger is already attached before the master charger probes, the master will miss updating parallel charging states. ICL and charge state change interrupts get triggered before their handlers are registered. Hence these interrupts will not be handled. Obtain the state of missing interrupts by polling status registers. If parallel charging is ready on master side before the parallel charger probes, then parallel charging will not be enabled. Check if parallel charging is ready once the parallel charger probes so parallel charging can be enabled immediately. CRs-Fixed: 1033688 Change-Id: Ic91baeaeb7410b6f265b8bfa8e31e2bcff8dfce2 Signed-off-by: Harry Yang --- drivers/power/qcom-charger/qpnp-smb2.c | 2 + drivers/power/qcom-charger/smb-lib.c | 61 ++++++++++++++++---- drivers/power/qcom-charger/smb-lib.h | 2 + drivers/power/qcom-charger/smb138x-charger.c | 13 +++-- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 542009a03e96..7810ecb9b15b 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -596,6 +596,8 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_usb_plugin(0, &irq_data); smblib_handle_usb_typec_change(0, &irq_data); smblib_handle_usb_source_change(0, &irq_data); + smblib_handle_chg_state_change(0, &irq_data); + smblib_handle_icl_change(0, &irq_data); return 0; } diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 8227183b22d9..55bcc9ec443e 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -339,16 +339,32 @@ static int smblib_detach_usb(struct smb_charger *chg) return rc; } -static struct power_supply *get_parallel_psy(struct smb_charger *chg) +static int pl_notifier_call(struct notifier_block *nb, + unsigned long ev, void *v) { - if (chg->pl.psy) - return chg->pl.psy; + struct power_supply *psy = v; + struct smb_charger *chg = container_of(nb, struct smb_charger, pl.nb); - chg->pl.psy = power_supply_get_by_name("parallel"); - if (!chg->pl.psy) - smblib_dbg(chg, PR_MISC, "parallel charger not found\n"); + if (strcmp(psy->desc->name, "parallel") == 0) { + chg->pl.psy = psy; + schedule_work(&chg->pl_detect_work); + } - return chg->pl.psy; + return NOTIFY_OK; +} + +static int register_pl_notifier(struct smb_charger *chg) +{ + int rc; + + chg->pl.nb.notifier_call = pl_notifier_call; + rc = power_supply_reg_notifier(&chg->pl.nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + return rc; + } + + return 0; } /********************* @@ -436,7 +452,7 @@ static int smblib_fv_vote_callback(struct votable *votable, void *data, return rc; } - if (chg->mode == PARALLEL_MASTER && get_parallel_psy(chg)) { + if (chg->mode == PARALLEL_MASTER && chg->pl.psy) { pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV; rc = power_supply_set_property(chg->pl.psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); @@ -545,7 +561,7 @@ static int smblib_pl_disable_vote_callback(struct votable *votable, void *data, union power_supply_propval pval = {0, }; int rc; - if (chg->mode != PARALLEL_MASTER || !get_parallel_psy(chg)) + if (chg->mode != PARALLEL_MASTER || !chg->pl.psy) return 0; chg->pl.taper_percent = 100; @@ -1208,7 +1224,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - if (chg->mode != PARALLEL_MASTER || !get_parallel_psy(chg)) + if (chg->mode != PARALLEL_MASTER) return IRQ_HANDLED; rc = smblib_get_prop_batt_charge_type(chg, &pval); @@ -1568,6 +1584,17 @@ static void smblib_hvdcp_detect_work(struct work_struct *work) } } +static void smblib_pl_detect_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + pl_detect_work); + + power_supply_unreg_notifier(&chg->pl.nb); + + if (!get_effective_result_locked(chg->pl_disable_votable)) + rerun_election(chg->pl_disable_votable); +} + #define MINIMUM_PARALLEL_FCC_UA 500000 #define PL_TAPER_WORK_DELAY_MS 100 #define TAPER_RESIDUAL_PERCENT 75 @@ -1690,6 +1717,7 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->write_lock); + INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work); @@ -1699,7 +1727,20 @@ int smblib_init(struct smb_charger *chg) if (rc < 0) { dev_err(chg->dev, "Couldn't create votables rc=%d\n", rc); + return rc; } + + chg->pl.psy = power_supply_get_by_name("parallel"); + if (!chg->pl.psy) { + rc = register_pl_notifier(chg); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't register notifier rc=%d\n", + rc); + return rc; + } + } + break; case PARALLEL_SLAVE: break; diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index fe75e0625230..8b3d00b6a5c1 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -65,6 +65,7 @@ struct smb_params { }; struct parallel_params { + struct notifier_block nb; struct power_supply *psy; int *master_percent; int taper_percent; @@ -107,6 +108,7 @@ struct smb_charger { struct votable *pl_disable_votable; /* work */ + struct work_struct pl_detect_work; struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; struct delayed_work pl_taper_work; diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index 2b65bf293cd1..f092f5a580b5 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -842,12 +842,6 @@ static int smb138x_slave_probe(struct smb138x *chip) return rc; } - rc = smb138x_init_parallel_psy(chip); - if (rc < 0) { - pr_err("Couldn't initialize parallel psy rc=%d\n", rc); - return rc; - } - /* suspend usb input */ rc = smblib_set_usb_suspend(chg, true); if (rc < 0) { @@ -878,6 +872,13 @@ static int smb138x_slave_probe(struct smb138x *chip) return rc; } + /* keep at the end of probe, ready to serve before notifying others */ + rc = smb138x_init_parallel_psy(chip); + if (rc < 0) { + pr_err("Couldn't initialize parallel psy rc=%d\n", rc); + return rc; + } + return rc; }