From: Abhijeet Dharmapurikar Date: Wed, 8 Feb 2017 21:35:14 +0000 (-0800) Subject: smb-lib: add support of ICL voting based on charger X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=3a3c5fd62ecae1a880958a8788db34539099d399;p=sagit-ice-cold%2Fkernel_xiaomi_msm8998.git smb-lib: add support of ICL voting based on charger Add support to vote for ICL based on charger type. Following are the current limit for chargers: Legacy adapters: CDP: 1500mA, DCP: 1800mA, HVDCP: 3000mA TypeC Adapters: Based on the current advertised by the adapter. Change-Id: Ia5dbf73c29949a94e096ca6233a33c40da744140 Signed-off-by: Ashay Jaiswal Signed-off-by: Abhijeet Dharmapurikar --- diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 3bfab47dd6c9..73ccb9a0bb7d 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -663,8 +663,7 @@ static int smb2_usb_main_set_prop(struct power_supply *psy, rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval); break; case POWER_SUPPLY_PROP_ICL_REDUCTION: - chg->icl_reduction_ua = val->intval; - rc = rerun_election(chg->usb_icl_votable); + rc = smblib_set_icl_reduction(chg, val->intval); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval); @@ -1316,9 +1315,10 @@ static int smb2_init_hw(struct smb2 *chip) if (chip->dt.fv_uv < 0) smblib_get_charge_param(chg, &chg->param.fv, &chip->dt.fv_uv); + smblib_get_charge_param(chg, &chg->param.usb_icl, + &chg->default_icl_ua); if (chip->dt.usb_icl_ua < 0) - smblib_get_charge_param(chg, &chg->param.usb_icl, - &chip->dt.usb_icl_ua); + chip->dt.usb_icl_ua = chg->default_icl_ua; if (chip->dt.dc_icl_ua < 0) smblib_get_charge_param(chg, &chg->param.dc_icl, @@ -1580,6 +1580,7 @@ static int smb2_chg_config_init(struct smb2 *chip) switch (pmic_rev_id->pmic_subtype) { case PMI8998_SUBTYPE: + chip->chg.smb_version = PMI8998_SUBTYPE; chip->chg.wa_flags |= BOOST_BACK_WA; if (pmic_rev_id->rev4 == PMI8998_V1P1_REV4) /* PMI rev 1.1 */ chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT; @@ -1594,6 +1595,7 @@ static int smb2_chg_config_init(struct smb2 *chip) chg->chg_freq.freq_above_otg_threshold = 800; break; case PM660_SUBTYPE: + chip->chg.smb_version = PM660_SUBTYPE; chip->chg.wa_flags |= BOOST_BACK_WA; chg->param.freq_buck = pm660_params.freq_buck; chg->param.freq_boost = pm660_params.freq_boost; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 11c82b53a9a1..c5714fb4b4cb 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "smb-lib.h" @@ -156,11 +157,24 @@ int smblib_icl_override(struct smb_charger *chg, bool override) int rc; bool override_status; u8 stat; + u16 reg; - rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat); + switch (chg->smb_version) { + case PMI8998_SUBTYPE: + reg = APSD_RESULT_STATUS_REG; + break; + case PM660_SUBTYPE: + reg = AICL_STATUS_REG; + break; + default: + smblib_dbg(chg, PR_MISC, "Unknown chip version=%x\n", + chg->smb_version); + return -EINVAL; + } + + rc = smblib_read(chg, reg, &stat); if (rc < 0) { - smblib_err(chg, "Couldn't read APSD_RESULT_STATUS_REG rc=%d\n", - rc); + smblib_err(chg, "Couldn't read reg=%x rc=%d\n", reg, rc); return rc; } override_status = (bool)(stat & ICL_OVERRIDE_LATCH_BIT); @@ -640,6 +654,19 @@ static void smblib_uusb_removal(struct smb_charger *chg) rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc); + + /* clear USB ICL vote for DCP_VOTER */ + rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); + if (rc < 0) + smblib_err(chg, + "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); + + /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ + rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); + if (rc < 0) + smblib_err(chg, + "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", + rc); } static bool smblib_sysok_reason_usbin(struct smb_charger *chg) @@ -2203,12 +2230,19 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } - /* remove DCP_VOTER */ + /* clear USB ICL vote for DCP_VOTER */ rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); - if (rc < 0) { - smblib_err(chg, "Couldn't unvote DCP rc=%d\n", rc); - return rc; - } + if (rc < 0) + smblib_err(chg, + "Couldn't un-vote DCP from USB ICL rc=%d\n", + rc); + + /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ + rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); + if (rc < 0) + smblib_err(chg, + "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", + rc); /* remove USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); @@ -2255,39 +2289,6 @@ int smblib_set_prop_ship_mode(struct smb_charger *chg, return rc; } -/*********************** -* USB MAIN PSY GETTERS * -*************************/ -int smblib_get_prop_fcc_delta(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0; - - rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc); - step_cc_delta_ua = 0; - } else { - hw_cc_delta_ua = step_cc_delta_ua; - } - - rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc); - jeita_cc_delta_ua = 0; - } else if (jeita_cc_delta_ua < 0) { - /* HW will take the min between JEITA and step charge */ - hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua); - } - - val->intval = hw_cc_delta_ua; - return 0; -} - -/*********************** -* USB MAIN PSY SETTERS * -*************************/ - int smblib_reg_block_update(struct smb_charger *chg, struct reg_info *entry) { @@ -2463,6 +2464,155 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, return rc; } +/*********************** +* USB MAIN PSY GETTERS * +*************************/ +int smblib_get_prop_fcc_delta(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0; + + rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc); + step_cc_delta_ua = 0; + } else { + hw_cc_delta_ua = step_cc_delta_ua; + } + + rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc); + jeita_cc_delta_ua = 0; + } else if (jeita_cc_delta_ua < 0) { + /* HW will take the min between JEITA and step charge */ + hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua); + } + + val->intval = hw_cc_delta_ua; + return 0; +} + +/*********************** +* USB MAIN PSY SETTERS * +*************************/ + +#define SDP_CURRENT_MA 500000 +#define CDP_CURRENT_MA 1500000 +#define DCP_CURRENT_MA 1500000 +#define HVDCP_CURRENT_MA 3000000 +#define TYPEC_DEFAULT_CURRENT_MA 900000 +#define TYPEC_MEDIUM_CURRENT_MA 1500000 +#define TYPEC_HIGH_CURRENT_MA 3000000 +static int smblib_get_charge_current(struct smb_charger *chg, + int *total_current_ua) +{ + const struct apsd_result *apsd_result = smblib_update_usb_type(chg); + union power_supply_propval val = {0, }; + int rc, typec_source_rd, current_ua; + bool non_compliant; + u8 stat5; + + rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc); + return rc; + } + non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT; + + /* get settled ICL */ + rc = smblib_get_prop_input_current_settled(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc); + return rc; + } + + typec_source_rd = smblib_get_prop_ufp_mode(chg); + + /* QC 2.0/3.0 adapter */ + if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) { + *total_current_ua = HVDCP_CURRENT_MA; + return 0; + } + + if (non_compliant) { + switch (apsd_result->bit) { + case CDP_CHARGER_BIT: + current_ua = CDP_CURRENT_MA; + break; + case DCP_CHARGER_BIT: + case OCP_CHARGER_BIT: + case FLOAT_CHARGER_BIT: + current_ua = DCP_CURRENT_MA; + break; + default: + current_ua = 0; + break; + } + + *total_current_ua = max(current_ua, val.intval); + return 0; + } + + switch (typec_source_rd) { + case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: + switch (apsd_result->bit) { + case CDP_CHARGER_BIT: + current_ua = CDP_CURRENT_MA; + break; + case DCP_CHARGER_BIT: + case OCP_CHARGER_BIT: + case FLOAT_CHARGER_BIT: + current_ua = chg->default_icl_ua; + break; + default: + current_ua = 0; + break; + } + break; + case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: + current_ua = TYPEC_MEDIUM_CURRENT_MA; + break; + case POWER_SUPPLY_TYPEC_SOURCE_HIGH: + current_ua = TYPEC_HIGH_CURRENT_MA; + break; + case POWER_SUPPLY_TYPEC_NON_COMPLIANT: + case POWER_SUPPLY_TYPEC_NONE: + default: + current_ua = 0; + break; + } + + *total_current_ua = max(current_ua, val.intval); + return 0; +} + +int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua) +{ + int current_ua, rc; + + if (reduction_ua == 0) { + chg->icl_reduction_ua = 0; + vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); + } else { + /* + * No usb_icl voter means we are defaulting to hw chosen + * max limit. We need a vote from s/w to enforce the reduction. + */ + if (get_effective_result(chg->usb_icl_votable) == -EINVAL) { + rc = smblib_get_charge_current(chg, ¤t_ua); + if (rc < 0) { + pr_err("Failed to get ICL rc=%d\n", rc); + return rc; + } + vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, true, + current_ua); + } + } + + return rerun_election(chg->usb_icl_votable); +} + /************************ * PARALLEL PSY GETTERS * ************************/ @@ -2984,6 +3134,13 @@ static void typec_source_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); + + /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ + rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); + if (rc < 0) + smblib_err(chg, + "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", + rc); } static void typec_source_insertion(struct smb_charger *chg) diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index a0190ae44f29..8b130d7c4f1f 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -31,6 +31,7 @@ enum print_reason { #define USER_VOTER "USER_VOTER" #define PD_VOTER "PD_VOTER" #define DCP_VOTER "DCP_VOTER" +#define PL_USBIN_USBIN_VOTER "PL_USBIN_USBIN_VOTER" #define USB_PSY_VOTER "USB_PSY_VOTER" #define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER" #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" @@ -171,6 +172,7 @@ struct smb_charger { enum smb_mode mode; bool external_vconn; struct smb_chg_freq chg_freq; + int smb_version; /* locks */ struct mutex write_lock; @@ -244,6 +246,7 @@ struct smb_charger { bool vconn_en; int otg_attempts; int vconn_attempts; + int default_icl_ua; /* workaround flag */ u32 wa_flags; @@ -408,6 +411,7 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_get_prop_fcc_delta(struct smb_charger *chg, union power_supply_propval *val); int smblib_icl_override(struct smb_charger *chg, bool override); +int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg);