diff options
author | Harry Yang <harryy@codeaurora.org> | 2016-10-04 17:03:56 -0700 |
---|---|---|
committer | Harry Yang <harryy@codeaurora.org> | 2016-10-26 14:22:51 -0700 |
commit | b6d02534923c81c5f6500d65da97a5e95c6492fc (patch) | |
tree | d1dc4226db2393673b48784cf28979a0123412e1 /drivers | |
parent | 46aa49c1188a77f52dc4969f82292c176d8f399b (diff) |
qcom-charger: set optimal buck switching frequency
Reduce the power dissipation impact by choosing the optimal
switching frequency per input voltage.
The optimal switching frequences are chosen as follow,
5V only = 600kHz
6-8V QC3 = 800kHz
9V QC2 or vanilla PD = 1.0MHz
12V QC2 or PD adapter = 1.2MHz
CRs-Fixed: 1048242
Change-Id: I2ef9f3e122b39682a743334668fcd0aeb085e147
Signed-off-by: Harry Yang <harryy@codeaurora.org>
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/qcom-charger/qpnp-smb2.c | 7 | ||||
-rw-r--r-- | drivers/power/qcom-charger/smb-lib.c | 121 | ||||
-rw-r--r-- | drivers/power/qcom-charger/smb-reg.h | 1 |
3 files changed, 121 insertions, 8 deletions
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 93965dbe99ae..f9d76c56aa2e 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -203,6 +203,13 @@ static struct smb_params v1_params = { .get_proc = smblib_mapping_cc_delta_to_field_value, .set_proc = smblib_mapping_cc_delta_from_field_value, }, + .freq_buck = { + .name = "buck switching frequency", + .reg = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG, + .min_u = 600, + .max_u = 2000, + .step_u = 200, + }, }; #define STEP_CHARGING_MAX_STEPS 5 diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 5785e42e0140..3fba91a257a8 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -220,6 +220,34 @@ int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend) return rc; } +#define FSW_600HZ_FOR_5V 600 +#define FSW_800HZ_FOR_6V_8V 800 +#define FSW_1MHZ_FOR_REMOVAL 1000 +#define FSW_1MHZ_FOR_9V 1000 +#define FSW_1P2MHZ_FOR_12V 1200 +static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz) +{ + union power_supply_propval pval = {0, }; + int rc = 0; + + rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz); + if (rc < 0) + dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc); + + if (chg->mode == PARALLEL_MASTER && chg->pl.psy) { + pval.intval = fsw_khz; + rc = power_supply_set_property(chg->pl.psy, + POWER_SUPPLY_PROP_BUCK_FREQ, &pval); + if (rc < 0) { + dev_err(chg->dev, + "Could not set parallel buck_freq rc=%d\n", rc); + return rc; + } + } + + return rc; +} + struct apsd_result { const char * const name; const u8 bit; @@ -416,10 +444,13 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) { allowed_voltage = USBIN_ADAPTER_ALLOW_5V; + smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V); } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) { allowed_voltage = USBIN_ADAPTER_ALLOW_9V; + smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V); } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) { allowed_voltage = USBIN_ADAPTER_ALLOW_12V; + smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V); } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) { allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V; } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) { @@ -2167,6 +2198,16 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) int rc; u8 stat; + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); + return IRQ_HANDLED; + } + + chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); + smblib_set_opt_freq_buck(chg, + chg->vbus_present ? FSW_600HZ_FOR_5V : FSW_1MHZ_FOR_REMOVAL); + /* fetch the DPDM regulator */ if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, "dpdm-supply", NULL)) { @@ -2181,14 +2222,6 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) if (!chg->dpdm_reg) goto skip_dpdm_float; - rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); - return IRQ_HANDLED; - } - - chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); - if (chg->vbus_present) { if (!regulator_is_enabled(chg->dpdm_reg)) { smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); @@ -2260,6 +2293,60 @@ static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +#define QC3_PULSES_FOR_6V 5 +#define QC3_PULSES_FOR_9V 20 +#define QC3_PULSES_FOR_12V 35 +static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg) +{ + int rc; + u8 stat; + int pulses; + + if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) { + rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, + "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc); + return; + } + + switch (stat & QC_2P0_STATUS_MASK) { + case QC_5V_BIT: + smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V); + break; + case QC_9V_BIT: + smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V); + break; + case QC_12V_BIT: + smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V); + break; + default: + smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_REMOVAL); + break; + } + } + + if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) { + rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, + "Couldn't read QC_PULSE_COUNT rc=%d\n", rc); + return; + } + pulses = (stat & QC_PULSE_COUNT_MASK); + + if (pulses < QC3_PULSES_FOR_6V) + smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V); + else if (pulses < QC3_PULSES_FOR_9V) + smblib_set_opt_freq_buck(chg, FSW_800HZ_FOR_6V_8V); + else if (pulses < QC3_PULSES_FOR_12V) + smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V); + else + smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V); + + } +} + static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg, bool rising) { @@ -2272,10 +2359,20 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; + int rc; if (!rising) return; + /* + * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage + * change interrupt. + */ + rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG, + AUTH_IRQ_EN_CFG_BIT, 0); + if (rc < 0) + smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc); + if (chg->mode == PARALLEL_MASTER) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); @@ -2381,6 +2478,8 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) smblib_handle_slow_plugin_timeout(chg, (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT)); + smblib_hvdcp_adaptive_voltage_change(chg); + power_supply_changed(chg->usb_psy); return IRQ_HANDLED; @@ -2399,6 +2498,12 @@ static void typec_source_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->hvdcp_detect_work); + /* reset AUTH_IRQ_EN_CFG_BIT */ + rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG, + AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc); + /* reconfigure allowed voltage for HVDCP */ rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V); diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h index ba501761c209..a74fcf730a8c 100644 --- a/drivers/power/qcom-charger/smb-reg.h +++ b/drivers/power/qcom-charger/smb-reg.h @@ -428,6 +428,7 @@ enum { #define USBIN_5V_TO_12V_BIT BIT(2) #define USBIN_5V_TO_9V_BIT BIT(1) #define USBIN_5V_BIT BIT(0) +#define QC_2P0_STATUS_MASK GENMASK(2, 0) #define APSD_STATUS_REG (USBIN_BASE + 0x07) #define APSD_STATUS_7_BIT BIT(7) |