diff options
| author | Abhijeet Dharmapurikar <adharmap@codeaurora.org> | 2016-07-08 11:39:23 -0700 |
|---|---|---|
| committer | Abhijeet Dharmapurikar <adharmap@codeaurora.org> | 2016-07-20 17:46:58 -0700 |
| commit | cb5b737ccfdaa6deb023fd8865c23c9e6610e284 (patch) | |
| tree | ffd53fb3df90a2ac0d00e8169b0407520a50f236 | |
| parent | 14e3191326bace52dfef6d0fb8702882a55936c7 (diff) | |
smb-lib: Add support for thermal daemon throttling fcc
Add support to configure the reduced fcc as per thermal mitigation
levels.
At the max level disable charging and at the lowest level (zero)
remove all the mitigation. The intermediate levels would
end up configuring a reduced fcc.
Note that between the profile and Qnovo, the driver needs to
choose the maximum fcc. However, if thermal mitigation is active i.e.
it is at any level above zero, this needs to reduced to the fcc at
that thermal level. Use cascaded votables for this, where profile and
qnovo usecase vote for FCC_MAX and the result of FCC_MAX and thermal
levels vote for fcc.
Change-Id: I4f72857557222cbd719da7bd177511951ef7f1ff
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
| -rw-r--r-- | Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt | 9 | ||||
| -rw-r--r-- | drivers/power/qcom-charger/qpnp-qnovo.c | 15 | ||||
| -rw-r--r-- | drivers/power/qcom-charger/qpnp-smb2.c | 41 | ||||
| -rw-r--r-- | drivers/power/qcom-charger/smb-lib.c | 51 | ||||
| -rw-r--r-- | drivers/power/qcom-charger/smb-lib.h | 12 |
5 files changed, 113 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt index 368f0b8c9525..5a415d04fbcf 100644 --- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt @@ -56,6 +56,15 @@ Charger specific properties: Definition: Specifies the DC input power limit in micro-watts. If the value is not present, 8W is used as default. +- qcom,thermal-mitigation + Usage: optional + Value type: Array of <u32> + Definition: Array of fast charge current limit values for + different system thermal mitigation levels. + This should be a flat array that denotes the + maximum charge current in mA for each thermal + level. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= diff --git a/drivers/power/qcom-charger/qpnp-qnovo.c b/drivers/power/qcom-charger/qpnp-qnovo.c index d50188a5efbf..2418b112d670 100644 --- a/drivers/power/qcom-charger/qpnp-qnovo.c +++ b/drivers/power/qcom-charger/qpnp-qnovo.c @@ -153,7 +153,7 @@ struct qnovo { struct work_struct status_change_work; int fv_uV_request; int fcc_uA_request; - struct votable *fcc_votable; + struct votable *fcc_max_votable; struct votable *fv_votable; }; @@ -243,8 +243,9 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, vote(chip->fv_votable, QNOVO_VOTER, false, 0); } if (chip->fcc_uA_request != -EINVAL) { - if (chip->fcc_votable) - vote(chip->fcc_votable, QNOVO_VOTER, false, 0); + if (chip->fcc_max_votable) + vote(chip->fcc_max_votable, QNOVO_VOTER, + false, 0); } } @@ -265,10 +266,10 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, true, chip->fv_uV_request); } if (chip->fcc_uA_request != -EINVAL) { - if (!chip->fcc_votable) - chip->fcc_votable = find_votable("FCC"); - if (chip->fcc_votable) - vote(chip->fcc_votable, QNOVO_VOTER, + if (!chip->fcc_max_votable) + chip->fcc_max_votable = find_votable("FCC_MAX"); + if (chip->fcc_max_votable) + vote(chip->fcc_max_votable, QNOVO_VOTER, true, chip->fcc_uA_request); } } diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index cb48f9c87e65..b59eb00d6728 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -146,7 +146,7 @@ static int smb2_parse_dt(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; struct device_node *node = chg->dev->of_node; - int rc; + int rc, byte_len; if (!node) { pr_err("device tree node missing\n"); @@ -181,6 +181,25 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chip->dt.wipower_max_uw = SMB2_DEFAULT_WPWR_UW; + if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) { + chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation", + chg->thermal_mitigation, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + return 0; } @@ -360,6 +379,7 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, }; static int smb2_batt_get_prop(struct power_supply *psy, @@ -387,9 +407,11 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: smblib_get_prop_batt_capacity(chg, val); break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + smblib_get_prop_system_temp_level(chg, val); + break; default: - pr_err("batt power supply prop %d not supported\n", - psp); + pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; } @@ -400,17 +422,21 @@ static int smb2_batt_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) { + int rc = 0; struct smb_charger *chg = power_supply_get_drvdata(psy); switch (prop) { case POWER_SUPPLY_PROP_INPUT_SUSPEND: - smblib_set_prop_input_suspend(chg, val); + rc = smblib_set_prop_input_suspend(chg, val); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + rc = smblib_set_prop_system_temp_level(chg, val); break; default: - return -EINVAL; + rc = -EINVAL; } - return 0; + return rc; } static int smb2_batt_prop_is_writeable(struct power_supply *psy, @@ -418,6 +444,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy, { switch (psp) { case POWER_SUPPLY_PROP_INPUT_SUSPEND: + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: return 1; default: break; @@ -608,7 +635,7 @@ static int smb2_init_hw(struct smb2 *chip) DEFAULT_VOTER, chip->dt.suspend_input, 0); vote(chg->dc_suspend_votable, DEFAULT_VOTER, chip->dt.suspend_input, 0); - vote(chg->fcc_votable, + vote(chg->fcc_max_votable, DEFAULT_VOTER, true, chip->dt.fcc_ua); vote(chg->fv_votable, DEFAULT_VOTER, true, chip->dt.fv_uv); diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 8f5e3ecc6c60..bb644a4b0cf0 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -400,6 +400,14 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, suspend); } +static int smblib_fcc_max_vote_callback(struct votable *votable, void *data, + int fcc_ua, const char *client) +{ + struct smb_charger *chg = data; + + return vote(chg->fcc_votable, FCC_MAX_RESULT, true, fcc_ua); +} + static int smblib_fcc_vote_callback(struct votable *votable, void *data, int fcc_ua, const char *client) { @@ -850,6 +858,13 @@ done: return rc; } +int smblib_get_prop_system_temp_level(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = chg->system_temp_level; + return 0; +} + /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -876,6 +891,31 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg, return rc; } +int smblib_set_prop_system_temp_level(struct smb_charger *chg, + const union power_supply_propval *val) +{ + if (val->intval < 0) + return -EINVAL; + + if (chg->thermal_levels <= 0) + return -EINVAL; + + if (val->intval > chg->thermal_levels) + return -EINVAL; + + chg->system_temp_level = val->intval; + if (chg->system_temp_level == chg->thermal_levels) + return vote(chg->chg_disable_votable, THERMAL_DAEMON, true, 0); + + vote(chg->chg_disable_votable, THERMAL_DAEMON, false, 0); + if (chg->system_temp_level == 0) + return vote(chg->fcc_votable, THERMAL_DAEMON, false, 0); + + vote(chg->fcc_votable, THERMAL_DAEMON, true, + chg->thermal_mitigation[chg->system_temp_level]); + return 0; +} + /******************* * USB PSY GETTERS * *******************/ @@ -1694,7 +1734,15 @@ int smblib_create_votables(struct smb_charger *chg) return rc; } - chg->fcc_votable = create_votable("FCC", VOTE_MAX, + chg->fcc_max_votable = create_votable("FCC_MAX", VOTE_MAX, + smblib_fcc_max_vote_callback, + chg); + if (IS_ERR(chg->fcc_max_votable)) { + rc = PTR_ERR(chg->fcc_max_votable); + return rc; + } + + chg->fcc_votable = create_votable("FCC", VOTE_MIN, smblib_fcc_vote_callback, chg); if (IS_ERR(chg->fcc_votable)) { @@ -1804,6 +1852,7 @@ int smblib_deinit(struct smb_charger *chg) { destroy_votable(chg->usb_suspend_votable); destroy_votable(chg->dc_suspend_votable); + destroy_votable(chg->fcc_max_votable); destroy_votable(chg->fcc_votable); destroy_votable(chg->fv_votable); destroy_votable(chg->usb_icl_votable); diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index 06a4428ffd13..2b6462d99341 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -31,6 +31,8 @@ enum print_reason { #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" enum smb_mode { PARALLEL_MASTER = 0, @@ -106,6 +108,7 @@ struct smb_charger { /* votables */ struct votable *usb_suspend_votable; struct votable *dc_suspend_votable; + struct votable *fcc_max_votable; struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; @@ -126,6 +129,10 @@ struct smb_charger { int voltage_max_uv; bool pd_active; bool vbus_present; + + int system_temp_level; + int thermal_levels; + int *thermal_mitigation; }; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); @@ -172,8 +179,13 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_health(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_system_temp_level(struct smb_charger *chg, + union power_supply_propval *val); + int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_set_prop_system_temp_level(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_get_prop_usb_present(struct smb_charger *chg, union power_supply_propval *val); |
