From 7cb260336d2ece5a200d4dc8eed1b7ad14b68e21 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Wed, 28 Sep 2016 10:47:29 -0700 Subject: [PATCH] qcom-charger: Add USBIN proxy votable for parallel charging USB charger voltage votes indenpently, along with ICL through intermediate USBIN votable. This change can correctly capture strong chargers by monitoring input voltage or charger type. CRs-Fixed: 1069575 Change-Id: I36843279fdac909966b3f01b5a6716d191fab903 Signed-off-by: Harry Yang --- drivers/power/qcom-charger/qpnp-smb2.c | 2 +- drivers/power/qcom-charger/smb-lib.c | 100 +++++++++++++------------ drivers/power/qcom-charger/smb-lib.h | 9 ++- 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 2c228cc6f4b2..4f0e6c676a98 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -983,7 +983,7 @@ static int smb2_init_hw(struct smb2 *chip) /* votes must be cast before configuring software control */ vote(chg->pl_disable_votable, - USBIN_ICL_VOTER, true, 0); + PL_INDIRECT_VOTER, true, 0); vote(chg->pl_disable_votable, CHG_STATE_VOTER, true, 0); vote(chg->pl_disable_votable, diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 1d4a89b3cebb..836af1541919 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -521,7 +521,7 @@ static int smblib_fcc_max_vote_callback(struct votable *votable, void *data, { struct smb_charger *chg = data; - return vote(chg->fcc_votable, FCC_MAX_RESULT, true, fcc_ua); + return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua); } static int smblib_fcc_vote_callback(struct votable *votable, void *data, @@ -731,6 +731,17 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data, return 0; } + +static int smblib_pl_enable_indirect_vote_callback(struct votable *votable, + void *data, int chg_enable, const char *client) +{ + struct smb_charger *chg = data; + + vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0); + + return 0; +} + /***************** * OTG REGULATOR * *****************/ @@ -1144,13 +1155,14 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, chg->system_temp_level = val->intval; if (chg->system_temp_level == chg->thermal_levels) - return vote(chg->chg_disable_votable, THERMAL_DAEMON, true, 0); + return vote(chg->chg_disable_votable, + THERMAL_DAEMON_VOTER, true, 0); - vote(chg->chg_disable_votable, THERMAL_DAEMON, false, 0); + vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0); if (chg->system_temp_level == 0) - return vote(chg->fcc_votable, THERMAL_DAEMON, false, 0); + return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0); - vote(chg->fcc_votable, THERMAL_DAEMON, true, + vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, chg->thermal_mitigation[chg->system_temp_level]); return 0; } @@ -1589,7 +1601,11 @@ int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, return rc; } - chg->voltage_min_uv = val->intval; + if (chg->mode == PARALLEL_MASTER) + vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, + min_uv > MICRO_5V, 0); + + chg->voltage_min_uv = min_uv; return rc; } @@ -1607,7 +1623,7 @@ int smblib_set_prop_usb_voltage_max(struct smb_charger *chg, return rc; } - chg->voltage_max_uv = val->intval; + chg->voltage_max_uv = max_uv; return rc; } @@ -1875,50 +1891,23 @@ skip_dpdm_float: return IRQ_HANDLED; } -#define MICRO_5P5V 5500000 -#define USB_WEAK_INPUT_MA 1400000 -static bool is_icl_pl_ready(struct smb_charger *chg) -{ - union power_supply_propval pval = {0, }; - int icl_ma; - int rc; - - rc = smblib_get_prop_usb_voltage_now(chg, &pval); - if (rc < 0) { - dev_err(chg->dev, "Couldn't get prop usb voltage rc=%d\n", rc); - /* proceed with a convervative value */ - pval.intval = MICRO_5P5V; - } - - if (pval.intval <= MICRO_5P5V) { - rc = smblib_get_charge_param(chg, - &chg->param.icl_stat, &icl_ma); - if (rc < 0) { - dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", - rc); - return false; - } - - if (icl_ma < USB_WEAK_INPUT_MA) - return false; - } - - /* - * Always enable parallel charging when USB INPUT is higher than 5V - * regardless of the AICL results. Assume chargers above 5V are strong - */ - - return true; -} - +#define USB_WEAK_INPUT_MA 1400000 irqreturn_t smblib_handle_icl_change(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + int icl_ma; + int rc; + + rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ma); + if (rc < 0) { + dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", rc); + return IRQ_HANDLED; + } if (chg->mode == PARALLEL_MASTER) - vote(chg->pl_disable_votable, USBIN_ICL_VOTER, - !is_icl_pl_ready(chg), 0); + vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, + icl_ma >= USB_WEAK_INPUT_MA, 0); smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); @@ -1955,6 +1944,9 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (!rising) return; + if (chg->mode == PARALLEL_MASTER) + vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); + /* the APSD done handler will set the USB supply type */ apsd_result = smblib_get_apsd_result(chg); smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", @@ -2080,8 +2072,9 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg, !rising || sink_attached, 0); if (!rising || sink_attached) { - /* icl votes to disable parallel charging */ - vote(chg->pl_disable_votable, USBIN_ICL_VOTER, true, 0); + /* reset both usbin current and voltage votes */ + vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); + vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); /* reset taper_end voter here */ vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0); } @@ -2319,6 +2312,15 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT", + VOTE_SET_ANY, + smblib_pl_enable_indirect_vote_callback, + chg); + if (IS_ERR(chg->pl_enable_votable_indirect)) { + rc = PTR_ERR(chg->pl_enable_votable_indirect); + return rc; + } + return rc; } @@ -2344,6 +2346,10 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->awake_votable); if (chg->pl_disable_votable) destroy_votable(chg->pl_disable_votable); + if (chg->chg_disable_votable) + destroy_votable(chg->chg_disable_votable); + if (chg->pl_enable_votable_indirect) + destroy_votable(chg->pl_enable_votable_indirect); } static void smblib_iio_deinit(struct smb_charger *chg) diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index 1d34e156792f..7a113bbaf8cc 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -29,12 +29,14 @@ enum print_reason { #define PD_VOTER "PD_VOTER" #define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER" #define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER" -#define USBIN_ICL_VOTER "USBIN_ICL_VOTER" +#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" +#define USBIN_I_VOTER "USBIN_I_VOTER" +#define USBIN_V_VOTER "USBIN_V_VOTER" #define CHG_STATE_VOTER "CHG_STATE_VOTER" #define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER" #define TAPER_END_VOTER "TAPER_END_VOTER" -#define FCC_MAX_RESULT "FCC_MAX_RESULT" -#define THERMAL_DAEMON "THERMAL_DAEMON" +#define FCC_MAX_RESULT_VOTER "FCC_MAX_RESULT_VOTER" +#define THERMAL_DAEMON_VOTER "THERMAL_DAEMON_VOTER" enum smb_mode { PARALLEL_MASTER = 0, @@ -140,6 +142,7 @@ struct smb_charger { struct votable *awake_votable; struct votable *pl_disable_votable; struct votable *chg_disable_votable; + struct votable *pl_enable_votable_indirect; /* work */ struct work_struct bms_update_work;