power: battery: Add support for FCC stepping
On some PMIC designs a sudden increase or decrease in FCC can impact the PMIC die thermally, causing the XO to drift. Introduce a logic which gradually ramps up/down the FCC whenever there is a change in its value, this spreads out the thermals over-time. The default step rate is 100mA/sec and the feature can be enabled using the DT property "qcom,fcc-stepping-enable". Change-Id: I59ee932b60766208912054f7031cd34151fb5deb Signed-off-by: Umang Agrawal <uagrawal@codeaurora.org>
This commit is contained in:
parent
eafe2f3d08
commit
491b7aff28
5 changed files with 367 additions and 59 deletions
|
@ -183,6 +183,12 @@ Charger specific properties:
|
||||||
Value type: bool
|
Value type: bool
|
||||||
Definition: Boolean flag which when present enables sw compensation for jeita
|
Definition: Boolean flag which when present enables sw compensation for jeita
|
||||||
|
|
||||||
|
- qcom,fcc-stepping-enable
|
||||||
|
Usage: optional
|
||||||
|
Value type: bool
|
||||||
|
Definition: Boolean flag which when present enables stepwise change in FCC.
|
||||||
|
The default stepping rate is 100mA/sec.
|
||||||
|
|
||||||
=============================================
|
=============================================
|
||||||
Second Level Nodes - SMB2 Charger Peripherals
|
Second Level Nodes - SMB2 Charger Peripherals
|
||||||
=============================================
|
=============================================
|
||||||
|
|
|
@ -40,12 +40,14 @@
|
||||||
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
|
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
|
||||||
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
|
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
|
||||||
#define USBIN_I_VOTER "USBIN_I_VOTER"
|
#define USBIN_I_VOTER "USBIN_I_VOTER"
|
||||||
|
#define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER"
|
||||||
|
|
||||||
struct pl_data {
|
struct pl_data {
|
||||||
int pl_mode;
|
int pl_mode;
|
||||||
int slave_pct;
|
int slave_pct;
|
||||||
int taper_pct;
|
int taper_pct;
|
||||||
int slave_fcc_ua;
|
int slave_fcc_ua;
|
||||||
|
int main_fcc_ua;
|
||||||
int restricted_current;
|
int restricted_current;
|
||||||
bool restricted_charging_enabled;
|
bool restricted_charging_enabled;
|
||||||
struct votable *fcc_votable;
|
struct votable *fcc_votable;
|
||||||
|
@ -59,6 +61,7 @@ struct pl_data {
|
||||||
struct work_struct pl_disable_forever_work;
|
struct work_struct pl_disable_forever_work;
|
||||||
struct delayed_work pl_taper_work;
|
struct delayed_work pl_taper_work;
|
||||||
struct delayed_work pl_awake_work;
|
struct delayed_work pl_awake_work;
|
||||||
|
struct delayed_work fcc_step_update_work;
|
||||||
struct power_supply *main_psy;
|
struct power_supply *main_psy;
|
||||||
struct power_supply *pl_psy;
|
struct power_supply *pl_psy;
|
||||||
struct power_supply *batt_psy;
|
struct power_supply *batt_psy;
|
||||||
|
@ -66,6 +69,13 @@ struct pl_data {
|
||||||
int charge_type;
|
int charge_type;
|
||||||
int total_settled_ua;
|
int total_settled_ua;
|
||||||
int pl_settled_ua;
|
int pl_settled_ua;
|
||||||
|
int fcc_step_update;
|
||||||
|
int main_step_fcc_dir;
|
||||||
|
int main_step_fcc_count;
|
||||||
|
int main_step_fcc_residual;
|
||||||
|
int parallel_step_fcc_dir;
|
||||||
|
int parallel_step_fcc_count;
|
||||||
|
int parallel_step_fcc_residual;
|
||||||
struct class qcom_batt_class;
|
struct class qcom_batt_class;
|
||||||
struct wakeup_source *pl_ws;
|
struct wakeup_source *pl_ws;
|
||||||
struct notifier_block nb;
|
struct notifier_block nb;
|
||||||
|
@ -380,6 +390,10 @@ done:
|
||||||
* FCC *
|
* FCC *
|
||||||
**********/
|
**********/
|
||||||
#define EFFICIENCY_PCT 80
|
#define EFFICIENCY_PCT 80
|
||||||
|
#define FCC_STEP_SIZE_UA 100000
|
||||||
|
#define FCC_STEP_UPDATE_DELAY_MS 1000
|
||||||
|
#define STEP_UP 1
|
||||||
|
#define STEP_DOWN -1
|
||||||
static void get_fcc_split(struct pl_data *chip, int total_ua,
|
static void get_fcc_split(struct pl_data *chip, int total_ua,
|
||||||
int *master_ua, int *slave_ua)
|
int *master_ua, int *slave_ua)
|
||||||
{
|
{
|
||||||
|
@ -432,6 +446,43 @@ static void get_fcc_split(struct pl_data *chip, int total_ua,
|
||||||
*slave_ua = (*slave_ua * chip->taper_pct) / 100;
|
*slave_ua = (*slave_ua * chip->taper_pct) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_fcc_step_update_params(struct pl_data *chip, int main_fcc_ua,
|
||||||
|
int parallel_fcc_ua)
|
||||||
|
{
|
||||||
|
union power_supply_propval pval = {0, };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Read current FCC of main charger */
|
||||||
|
rc = power_supply_get_property(chip->main_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't get main charger current fcc, rc=%d\n", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chip->main_fcc_ua = pval.intval;
|
||||||
|
|
||||||
|
chip->main_step_fcc_dir = (main_fcc_ua > pval.intval) ?
|
||||||
|
STEP_UP : STEP_DOWN;
|
||||||
|
chip->main_step_fcc_count = abs((main_fcc_ua - pval.intval) /
|
||||||
|
FCC_STEP_SIZE_UA);
|
||||||
|
chip->main_step_fcc_residual = (main_fcc_ua - pval.intval) %
|
||||||
|
FCC_STEP_SIZE_UA;
|
||||||
|
|
||||||
|
chip->parallel_step_fcc_dir = (parallel_fcc_ua > chip->slave_fcc_ua) ?
|
||||||
|
STEP_UP : STEP_DOWN;
|
||||||
|
chip->parallel_step_fcc_count = abs((parallel_fcc_ua -
|
||||||
|
chip->slave_fcc_ua) / FCC_STEP_SIZE_UA);
|
||||||
|
chip->parallel_step_fcc_residual = (parallel_fcc_ua -
|
||||||
|
chip->slave_fcc_ua) % FCC_STEP_SIZE_UA;
|
||||||
|
|
||||||
|
pr_debug("Main FCC Stepper parameters: main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d\n",
|
||||||
|
chip->main_step_fcc_dir, chip->main_step_fcc_count,
|
||||||
|
chip->main_step_fcc_residual);
|
||||||
|
pr_debug("Parallel FCC Stepper parameters: parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n",
|
||||||
|
chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count,
|
||||||
|
chip->parallel_step_fcc_residual);
|
||||||
|
}
|
||||||
|
|
||||||
static int pl_fcc_vote_callback(struct votable *votable, void *data,
|
static int pl_fcc_vote_callback(struct votable *votable, void *data,
|
||||||
int total_fcc_ua, const char *client)
|
int total_fcc_ua, const char *client)
|
||||||
{
|
{
|
||||||
|
@ -445,70 +496,109 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
|
||||||
if (!chip->main_psy)
|
if (!chip->main_psy)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!chip->batt_psy) {
|
||||||
|
chip->batt_psy = power_supply_get_by_name("battery");
|
||||||
|
if (!chip->batt_psy)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = power_supply_get_property(chip->batt_psy,
|
||||||
|
POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't read FCC step update status, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
chip->fcc_step_update = pval.intval;
|
||||||
|
pr_debug("FCC Stepper %s\n",
|
||||||
|
pval.intval ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip->fcc_step_update)
|
||||||
|
cancel_delayed_work_sync(&chip->fcc_step_update_work);
|
||||||
|
|
||||||
|
|
||||||
if (chip->pl_mode == POWER_SUPPLY_PL_NONE
|
if (chip->pl_mode == POWER_SUPPLY_PL_NONE
|
||||||
|| get_effective_result_locked(chip->pl_disable_votable)) {
|
|| get_effective_result_locked(chip->pl_disable_votable)) {
|
||||||
|
if (chip->fcc_step_update) {
|
||||||
|
vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
|
||||||
|
true, 0);
|
||||||
|
get_fcc_step_update_params(chip, total_fcc_ua, 0);
|
||||||
|
schedule_delayed_work(&chip->fcc_step_update_work, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
pval.intval = total_fcc_ua;
|
pval.intval = total_fcc_ua;
|
||||||
rc = power_supply_set_property(chip->main_psy,
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
&pval);
|
&pval);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
pr_err("Couldn't set main fcc, rc=%d\n", rc);
|
pr_err("Couldn't set main fcc, rc=%d\n", rc);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
|
if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
|
||||||
get_fcc_split(chip, total_fcc_ua,
|
get_fcc_split(chip, total_fcc_ua,
|
||||||
&master_fcc_ua, &slave_fcc_ua);
|
&master_fcc_ua, &slave_fcc_ua);
|
||||||
|
if (chip->fcc_step_update) {
|
||||||
/*
|
vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
|
||||||
* If there is an increase in slave share
|
true, 0);
|
||||||
* (Also handles parallel enable case)
|
get_fcc_step_update_params(chip, master_fcc_ua,
|
||||||
* Set Main ICL then slave FCC
|
slave_fcc_ua);
|
||||||
* else
|
schedule_delayed_work(&chip->fcc_step_update_work, 0);
|
||||||
* (Also handles parallel disable case)
|
|
||||||
* Set slave ICL then main FCC.
|
|
||||||
*/
|
|
||||||
if (slave_fcc_ua > chip->slave_fcc_ua) {
|
|
||||||
pval.intval = master_fcc_ua;
|
|
||||||
rc = power_supply_set_property(chip->main_psy,
|
|
||||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
|
||||||
&pval);
|
|
||||||
if (rc < 0) {
|
|
||||||
pr_err("Could not set main fcc, rc=%d\n", rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
pval.intval = slave_fcc_ua;
|
|
||||||
rc = power_supply_set_property(chip->pl_psy,
|
|
||||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
|
||||||
&pval);
|
|
||||||
if (rc < 0) {
|
|
||||||
pr_err("Couldn't set parallel fcc, rc=%d\n",
|
|
||||||
rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip->slave_fcc_ua = slave_fcc_ua;
|
|
||||||
} else {
|
} else {
|
||||||
pval.intval = slave_fcc_ua;
|
/*
|
||||||
rc = power_supply_set_property(chip->pl_psy,
|
* If there is an increase in slave share
|
||||||
|
* (Also handles parallel enable case)
|
||||||
|
* Set Main ICL then slave FCC
|
||||||
|
* else
|
||||||
|
* (Also handles parallel disable case)
|
||||||
|
* Set slave ICL then main FCC.
|
||||||
|
*/
|
||||||
|
if (slave_fcc_ua > chip->slave_fcc_ua) {
|
||||||
|
pval.intval = master_fcc_ua;
|
||||||
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
&pval);
|
&pval);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
pr_err("Couldn't set parallel fcc, rc=%d\n",
|
pr_err("Could not set main fcc, rc=%d\n",
|
||||||
rc);
|
rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
chip->slave_fcc_ua = slave_fcc_ua;
|
pval.intval = slave_fcc_ua;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
pval.intval = master_fcc_ua;
|
|
||||||
rc = power_supply_set_property(chip->main_psy,
|
|
||||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
&pval);
|
&pval);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
pr_err("Could not set main fcc, rc=%d\n", rc);
|
pr_err("Couldn't set parallel fcc, rc=%d\n",
|
||||||
return rc;
|
rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->slave_fcc_ua = slave_fcc_ua;
|
||||||
|
} else {
|
||||||
|
pval.intval = slave_fcc_ua;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
|
&pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set parallel fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->slave_fcc_ua = slave_fcc_ua;
|
||||||
|
|
||||||
|
pval.intval = master_fcc_ua;
|
||||||
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
|
&pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Could not set main fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,6 +611,192 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fcc_step_update_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct pl_data *chip = container_of(work,
|
||||||
|
struct pl_data, fcc_step_update_work.work);
|
||||||
|
union power_supply_propval pval = {0, };
|
||||||
|
int reschedule_ms = 0, rc = 0;
|
||||||
|
int main_fcc = chip->main_fcc_ua;
|
||||||
|
int parallel_fcc = chip->slave_fcc_ua;
|
||||||
|
|
||||||
|
if (!chip->usb_psy) {
|
||||||
|
chip->usb_psy = power_supply_get_by_name("usb");
|
||||||
|
if (!chip->usb_psy) {
|
||||||
|
pr_err("Couldn't get usb psy\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether USB is present or not */
|
||||||
|
rc = power_supply_get_property(chip->usb_psy,
|
||||||
|
POWER_SUPPLY_PROP_PRESENT, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't get USB Present status, rc=%d\n", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If USB is not present, then disable parallel and
|
||||||
|
* Main FCC to the effective value of FCC votable and exit.
|
||||||
|
*/
|
||||||
|
if (!pval.intval) {
|
||||||
|
/* Disable parallel */
|
||||||
|
parallel_fcc = 0;
|
||||||
|
pval.intval = 1;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
||||||
|
if (rc < 0)
|
||||||
|
pr_err("Couldn't change slave suspend state rc=%d\n",
|
||||||
|
rc);
|
||||||
|
|
||||||
|
main_fcc = get_effective_result_locked(chip->fcc_votable);
|
||||||
|
pval.intval = main_fcc;
|
||||||
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set main charger fcc, rc=%d\n", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto stepper_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip->main_step_fcc_count) {
|
||||||
|
main_fcc += (FCC_STEP_SIZE_UA * chip->main_step_fcc_dir);
|
||||||
|
chip->main_step_fcc_count--;
|
||||||
|
reschedule_ms = FCC_STEP_UPDATE_DELAY_MS;
|
||||||
|
} else if (chip->main_step_fcc_residual) {
|
||||||
|
main_fcc += chip->main_step_fcc_residual;
|
||||||
|
chip->main_step_fcc_residual = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip->parallel_step_fcc_count) {
|
||||||
|
parallel_fcc += (FCC_STEP_SIZE_UA *
|
||||||
|
chip->parallel_step_fcc_dir);
|
||||||
|
chip->parallel_step_fcc_count--;
|
||||||
|
reschedule_ms = FCC_STEP_UPDATE_DELAY_MS;
|
||||||
|
} else if (chip->parallel_step_fcc_residual) {
|
||||||
|
parallel_fcc += chip->parallel_step_fcc_residual;
|
||||||
|
chip->parallel_step_fcc_residual = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip->pl_mode == POWER_SUPPLY_PL_NONE ||
|
||||||
|
get_effective_result_locked(chip->pl_disable_votable)) {
|
||||||
|
/* Set Parallel FCC */
|
||||||
|
pval.intval = parallel_fcc;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set parallel charger fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set main FCC */
|
||||||
|
pval.intval = main_fcc;
|
||||||
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set main charger fcc, rc=%d\n", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parallel_fcc < MINIMUM_PARALLEL_FCC_UA) {
|
||||||
|
pval.intval = 1;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't change slave suspend state rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parallel_fcc < chip->slave_fcc_ua) {
|
||||||
|
pval.intval = parallel_fcc;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
|
&pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set parallel charger fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pval.intval = main_fcc;
|
||||||
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
|
&pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set main charger fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pval.intval = main_fcc;
|
||||||
|
rc = power_supply_set_property(chip->main_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
|
&pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set main charger fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pval.intval = parallel_fcc;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||||
|
&pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't set parallel charger fcc, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = power_supply_get_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't get slave suspend status, rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable parallel charger only if it was disabled earlier and
|
||||||
|
* configured slave fcc is greater than or equal to 100mA.
|
||||||
|
*/
|
||||||
|
if (pval.intval == 1 && parallel_fcc >= 100000) {
|
||||||
|
pval.intval = 0;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't change slave suspend state rc=%d\n",
|
||||||
|
rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) ||
|
||||||
|
(chip->pl_mode ==
|
||||||
|
POWER_SUPPLY_PL_USBIN_USBIN_EXT))
|
||||||
|
split_settled(chip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stepper_exit:
|
||||||
|
chip->main_fcc_ua = main_fcc;
|
||||||
|
chip->slave_fcc_ua = parallel_fcc;
|
||||||
|
|
||||||
|
if (reschedule_ms) {
|
||||||
|
schedule_delayed_work(&chip->fcc_step_update_work,
|
||||||
|
msecs_to_jiffies(reschedule_ms));
|
||||||
|
pr_debug("Rescheduling FCC_STEPPER work\n");
|
||||||
|
} else {
|
||||||
|
vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
|
#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
|
||||||
static int pl_fv_vote_callback(struct votable *votable, void *data,
|
static int pl_fv_vote_callback(struct votable *votable, void *data,
|
||||||
int fv_uv, const char *client)
|
int fv_uv, const char *client)
|
||||||
|
@ -660,6 +936,9 @@ static int pl_disable_vote_callback(struct votable *votable,
|
||||||
chip->total_settled_ua = 0;
|
chip->total_settled_ua = 0;
|
||||||
chip->pl_settled_ua = 0;
|
chip->pl_settled_ua = 0;
|
||||||
|
|
||||||
|
/* Cancel FCC step change work */
|
||||||
|
cancel_delayed_work_sync(&chip->fcc_step_update_work);
|
||||||
|
|
||||||
if (!pl_disable) { /* enable */
|
if (!pl_disable) { /* enable */
|
||||||
/* keep system awake to talk to slave charger through i2c */
|
/* keep system awake to talk to slave charger through i2c */
|
||||||
cancel_delayed_work_sync(&chip->pl_awake_work);
|
cancel_delayed_work_sync(&chip->pl_awake_work);
|
||||||
|
@ -685,16 +964,19 @@ static int pl_disable_vote_callback(struct votable *votable,
|
||||||
* PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy
|
* PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy
|
||||||
* is seen.
|
* is seen.
|
||||||
*/
|
*/
|
||||||
pval.intval = 0;
|
if (!chip->fcc_step_update) {
|
||||||
rc = power_supply_set_property(chip->pl_psy,
|
pval.intval = 0;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
pr_err("Couldn't change slave suspend state rc=%d\n",
|
pr_err("Couldn't change slave suspend state rc=%d\n",
|
||||||
rc);
|
rc);
|
||||||
|
|
||||||
if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
|
if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) ||
|
||||||
|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
|
(chip->pl_mode ==
|
||||||
split_settled(chip);
|
POWER_SUPPLY_PL_USBIN_USBIN_EXT))
|
||||||
|
split_settled(chip);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* we could have been enabled while in taper mode,
|
* we could have been enabled while in taper mode,
|
||||||
* start the taper work if so
|
* start the taper work if so
|
||||||
|
@ -715,15 +997,18 @@ static int pl_disable_vote_callback(struct votable *votable,
|
||||||
|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
|
|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
|
||||||
split_settled(chip);
|
split_settled(chip);
|
||||||
|
|
||||||
/* pl_psy may be NULL while in the disable branch */
|
if (!chip->fcc_step_update) {
|
||||||
if (chip->pl_psy) {
|
/* pl_psy may be NULL while in the disable branch */
|
||||||
pval.intval = 1;
|
if (chip->pl_psy) {
|
||||||
rc = power_supply_set_property(chip->pl_psy,
|
pval.intval = 1;
|
||||||
|
rc = power_supply_set_property(chip->pl_psy,
|
||||||
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
pr_err("Couldn't change slave suspend state rc=%d\n",
|
pr_err("Couldn't change slave suspend state rc=%d\n",
|
||||||
rc);
|
rc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rerun_election(chip->fcc_votable);
|
rerun_election(chip->fcc_votable);
|
||||||
rerun_election(chip->fv_votable);
|
rerun_election(chip->fv_votable);
|
||||||
|
|
||||||
|
@ -1118,6 +1403,7 @@ int qcom_batt_init(void)
|
||||||
INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
|
INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
|
||||||
INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
|
INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
|
||||||
INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work);
|
INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work);
|
||||||
|
INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work);
|
||||||
|
|
||||||
rc = pl_register_notifier(chip);
|
rc = pl_register_notifier(chip);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
@ -1172,6 +1458,7 @@ void qcom_batt_deinit(void)
|
||||||
cancel_delayed_work_sync(&chip->pl_taper_work);
|
cancel_delayed_work_sync(&chip->pl_taper_work);
|
||||||
cancel_work_sync(&chip->pl_disable_forever_work);
|
cancel_work_sync(&chip->pl_disable_forever_work);
|
||||||
cancel_delayed_work_sync(&chip->pl_awake_work);
|
cancel_delayed_work_sync(&chip->pl_awake_work);
|
||||||
|
cancel_delayed_work_sync(&chip->fcc_step_update_work);
|
||||||
|
|
||||||
power_supply_unreg_notifier(&chip->nb);
|
power_supply_unreg_notifier(&chip->nb);
|
||||||
destroy_votable(chip->pl_enable_votable_indirect);
|
destroy_votable(chip->pl_enable_votable_indirect);
|
||||||
|
|
|
@ -325,6 +325,9 @@ static int smb2_parse_dt(struct smb2 *chip)
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
|
chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
|
||||||
|
|
||||||
|
chg->fcc_stepper_mode = of_property_read_bool(node,
|
||||||
|
"qcom,fcc-stepping-enable");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,6 +944,7 @@ static enum power_supply_property smb2_batt_props[] = {
|
||||||
POWER_SUPPLY_PROP_RERUN_AICL,
|
POWER_SUPPLY_PROP_RERUN_AICL,
|
||||||
POWER_SUPPLY_PROP_DP_DM,
|
POWER_SUPPLY_PROP_DP_DM,
|
||||||
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||||
|
POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int smb2_batt_get_prop(struct power_supply *psy,
|
static int smb2_batt_get_prop(struct power_supply *psy,
|
||||||
|
@ -1049,6 +1053,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
|
||||||
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
||||||
rc = smblib_get_prop_batt_charge_counter(chg, val);
|
rc = smblib_get_prop_batt_charge_counter(chg, val);
|
||||||
break;
|
break;
|
||||||
|
case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE:
|
||||||
|
val->intval = chg->fcc_stepper_mode;
|
||||||
|
break;
|
||||||
default:
|
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;
|
return -EINVAL;
|
||||||
|
|
|
@ -3360,7 +3360,8 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
|
||||||
rc = smblib_request_dpdm(chg, true);
|
rc = smblib_request_dpdm(chg, true);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
|
smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
|
||||||
|
if (chg->fcc_stepper_mode)
|
||||||
|
vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0);
|
||||||
/* Schedule work to enable parallel charger */
|
/* Schedule work to enable parallel charger */
|
||||||
vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
|
vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
|
||||||
schedule_delayed_work(&chg->pl_enable_work,
|
schedule_delayed_work(&chg->pl_enable_work,
|
||||||
|
@ -3379,6 +3380,11 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Force 1500mA FCC on removal */
|
||||||
|
if (chg->fcc_stepper_mode)
|
||||||
|
vote(chg->fcc_votable, FCC_STEPPER_VOTER,
|
||||||
|
true, 1500000);
|
||||||
|
|
||||||
rc = smblib_request_dpdm(chg, false);
|
rc = smblib_request_dpdm(chg, false);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
|
smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
|
||||||
|
|
|
@ -67,6 +67,7 @@ enum print_reason {
|
||||||
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
|
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
|
||||||
#define WBC_VOTER "WBC_VOTER"
|
#define WBC_VOTER "WBC_VOTER"
|
||||||
#define OV_VOTER "OV_VOTER"
|
#define OV_VOTER "OV_VOTER"
|
||||||
|
#define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER"
|
||||||
|
|
||||||
#define VCONN_MAX_ATTEMPTS 3
|
#define VCONN_MAX_ATTEMPTS 3
|
||||||
#define OTG_MAX_ATTEMPTS 3
|
#define OTG_MAX_ATTEMPTS 3
|
||||||
|
@ -346,6 +347,7 @@ struct smb_charger {
|
||||||
u8 float_cfg;
|
u8 float_cfg;
|
||||||
bool use_extcon;
|
bool use_extcon;
|
||||||
bool otg_present;
|
bool otg_present;
|
||||||
|
bool fcc_stepper_mode;
|
||||||
|
|
||||||
/* workaround flag */
|
/* workaround flag */
|
||||||
u32 wa_flags;
|
u32 wa_flags;
|
||||||
|
|
Loading…
Add table
Reference in a new issue