mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 06:09:23 -04:00
power: qpnp-smbcharger-mmi: Add Dual Battery SM
Add a State Machine for Charging a Dual Parallel battery device. This State Machine requires independent battery measurements with a singular charge controller. Any other type of design might require a different SM. Change-Id: Idd8fabc7b9af3ad853df8f7280d7e393787c1075 Signed-off-by: Kenny Kessler <kenny.kessler@motorola.com> Reviewed-on: https://gerrit.mot.com/1258322 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Ryan Lattrel <ryanl@motorola.com> Reviewed-by: Kenneth Kessler <kennykessler@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
54d94ccc5d
commit
fa24cffe57
1 changed files with 594 additions and 78 deletions
|
|
@ -73,6 +73,10 @@ enum {
|
|||
#define WARM_TEMP 45
|
||||
#define COOL_TEMP 0
|
||||
|
||||
#define HEARTBEAT_DELAY_MS 60000
|
||||
#define HEARTBEAT_DUAL_DELAY_MS 10000
|
||||
#define HEARTBEAT_FACTORY_MS 1000
|
||||
|
||||
enum {
|
||||
TRICKLE_CHARGE = 0,
|
||||
PRE_CHARGE,
|
||||
|
|
@ -113,6 +117,12 @@ enum mmi_temp_zones {
|
|||
ZONE_NONE = 0xFF,
|
||||
};
|
||||
|
||||
enum {
|
||||
BASE_BATT = 0,
|
||||
MAIN_BATT,
|
||||
FLIP_BATT,
|
||||
};
|
||||
|
||||
enum mmi_chrg_step {
|
||||
STEP_MAX,
|
||||
STEP_NORM,
|
||||
|
|
@ -163,6 +173,19 @@ struct smb_mmi_params {
|
|||
struct smb_mmi_chg_param dc_icl;
|
||||
};
|
||||
|
||||
struct mmi_sm_params {
|
||||
int num_temp_zones;
|
||||
struct mmi_temp_zone *temp_zones;
|
||||
enum mmi_temp_zones pres_temp_zone;
|
||||
enum mmi_chrg_step pres_chrg_step;
|
||||
int chrg_taper_cnt;
|
||||
int batt_health;
|
||||
int chrg_iterm;
|
||||
int target_fcc;
|
||||
int target_fv;
|
||||
int ocp[MAX_NUM_STEPS];
|
||||
};
|
||||
|
||||
struct smb_mmi_charger {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
|
|
@ -201,14 +224,8 @@ struct smb_mmi_charger {
|
|||
int gen_log_rate_s;
|
||||
|
||||
/* Charge Profile */
|
||||
int num_temp_zones;
|
||||
struct mmi_temp_zone *temp_zones;
|
||||
enum mmi_temp_zones pres_temp_zone;
|
||||
enum mmi_chrg_step pres_chrg_step;
|
||||
int chrg_taper_cnt;
|
||||
int batt_health;
|
||||
struct mmi_sm_params sm_param[3];
|
||||
int base_fv_mv;
|
||||
int chrg_iterm;
|
||||
int vfloat_comp_mv;
|
||||
struct wakeup_source smb_mmi_hb_wake_source;
|
||||
struct alarm heartbeat_alarm;
|
||||
|
|
@ -1141,7 +1158,9 @@ static int smb_mmi_set_property(struct power_supply *psy,
|
|||
#define MAX_TEMP_C 60
|
||||
#define MIN_MAX_TEMP_C 47
|
||||
#define HYSTERISIS_DEGC 2
|
||||
static bool mmi_find_temp_zone(struct smb_mmi_charger *chip, int temp_c)
|
||||
static bool mmi_find_temp_zone(struct smb_mmi_charger *chg,
|
||||
struct mmi_sm_params *chip,
|
||||
int temp_c)
|
||||
{
|
||||
int prev_zone, num_zones;
|
||||
struct mmi_temp_zone *zones;
|
||||
|
|
@ -1150,8 +1169,8 @@ static bool mmi_find_temp_zone(struct smb_mmi_charger *chip, int temp_c)
|
|||
int i;
|
||||
int max_temp;
|
||||
|
||||
if (!chip) {
|
||||
pr_debug("called before chip valid!\n");
|
||||
if (!chg) {
|
||||
pr_debug("called before chg valid!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1159,8 +1178,8 @@ static bool mmi_find_temp_zone(struct smb_mmi_charger *chip, int temp_c)
|
|||
num_zones = chip->num_temp_zones;
|
||||
prev_zone = chip->pres_temp_zone;
|
||||
|
||||
if (chip->max_chrg_temp >= MIN_MAX_TEMP_C)
|
||||
max_temp = chip->max_chrg_temp;
|
||||
if (chg->max_chrg_temp >= MIN_MAX_TEMP_C)
|
||||
max_temp = chg->max_chrg_temp;
|
||||
else
|
||||
max_temp = zones[num_zones - 1].temp_c;
|
||||
|
||||
|
|
@ -1341,18 +1360,19 @@ static int get_prop_charger_present(struct smb_mmi_charger *chg,
|
|||
|
||||
#define TAPER_COUNT 2
|
||||
#define TAPER_DROP_MA 100
|
||||
static bool mmi_has_current_tapered(struct smb_mmi_charger *chip,
|
||||
static bool mmi_has_current_tapered(struct smb_mmi_charger *chg,
|
||||
struct mmi_sm_params *chip,
|
||||
int batt_ma, int taper_ma)
|
||||
{
|
||||
bool change_state = false;
|
||||
int allowed_fcc, target_ma;
|
||||
|
||||
if (!chip) {
|
||||
if (!chg) {
|
||||
pr_debug("called before chip valid!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
allowed_fcc = get_effective_result(chip->fcc_votable) / 1000;
|
||||
allowed_fcc = get_effective_result(chg->fcc_votable) / 1000;
|
||||
|
||||
if (allowed_fcc >= taper_ma)
|
||||
target_ma = taper_ma;
|
||||
|
|
@ -1435,46 +1455,41 @@ static enum alarmtimer_restart mmi_heartbeat_alarm_cb(struct alarm *alarm,
|
|||
return ALARMTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static void mmi_basic_charge_sm(struct smb_mmi_charger *chip,
|
||||
struct smb_mmi_chg_status *stat)
|
||||
static int mmi_dual_charge_sm(struct smb_mmi_charger *chg,
|
||||
struct smb_mmi_chg_status *stat,
|
||||
int batt)
|
||||
{
|
||||
int target_fcc;
|
||||
int target_fv;
|
||||
int max_fv_mv;
|
||||
int i;
|
||||
struct mmi_temp_zone *zone;
|
||||
|
||||
pr_info("SMBMMI: batt_mv = %d, batt_ma %d, batt_soc %d,"
|
||||
" batt_temp %d, usb_mv %d, cp %d, vp %d\n",
|
||||
stat->batt_mv,
|
||||
stat->batt_ma,
|
||||
stat->batt_soc,
|
||||
stat->batt_temp,
|
||||
stat->usb_mv,
|
||||
stat->charger_present,
|
||||
stat->vbus_present);
|
||||
struct mmi_sm_params *chip = &chg->sm_param[batt];
|
||||
int start_tz = chip->pres_temp_zone;
|
||||
int start_step = chip->pres_chrg_step;
|
||||
|
||||
if (!chip->temp_zones) {
|
||||
pr_debug("SMBMMI: Skipping SM since No Temp Zone Defined!\n");
|
||||
return;
|
||||
pr_debug("SMBMMI: No Temp Zone Defined for batt %d!\n", batt);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (chip->base_fv_mv == 0) {
|
||||
chip->base_fv_mv = get_effective_result(chip->fv_votable);
|
||||
chip->base_fv_mv /= 1000;
|
||||
vote(chip->fv_votable,
|
||||
if (chg->base_fv_mv == 0) {
|
||||
chg->base_fv_mv = get_effective_result(chg->fv_votable);
|
||||
chg->base_fv_mv /= 1000;
|
||||
vote(chg->fv_votable,
|
||||
BATT_PROFILE_VOTER, false, 0);
|
||||
}
|
||||
max_fv_mv = chip->base_fv_mv;
|
||||
max_fv_mv = chg->base_fv_mv;
|
||||
|
||||
mmi_find_temp_zone(chip, stat->batt_temp);
|
||||
mmi_find_temp_zone(chg, chip, stat->batt_temp);
|
||||
zone = &chip->temp_zones[chip->pres_temp_zone];
|
||||
|
||||
if (!stat->charger_present) {
|
||||
chip->pres_chrg_step = STEP_NONE;
|
||||
for (i = 0; i < MAX_NUM_STEPS; i++)
|
||||
chip->ocp[i] = 0;
|
||||
} else if ((chip->pres_temp_zone == ZONE_HOT) ||
|
||||
(chip->pres_temp_zone == ZONE_COLD)) {
|
||||
chip->pres_chrg_step = STEP_STOP;
|
||||
} else if (chip->demo_mode) {
|
||||
} else if (chg->demo_mode) {
|
||||
/* TODO: Ignore Demo Mode for now */
|
||||
} else if ((chip->pres_chrg_step == STEP_NONE) ||
|
||||
(chip->pres_chrg_step == STEP_STOP)) {
|
||||
|
|
@ -1498,17 +1513,11 @@ static void mmi_basic_charge_sm(struct smb_mmi_charger *chip,
|
|||
chip->pres_chrg_step = STEP_MAX;
|
||||
} else if (!zone->fcc_norm_ma)
|
||||
chip->pres_chrg_step = STEP_FLOAT;
|
||||
else if (mmi_has_current_tapered(chip, stat->batt_ma,
|
||||
else if (mmi_has_current_tapered(chg, chip, stat->batt_ma,
|
||||
zone->fcc_norm_ma)) {
|
||||
chip->chrg_taper_cnt = 0;
|
||||
|
||||
if (mmi_charge_halted(chip)) {
|
||||
vote(chip->chg_dis_votable,
|
||||
MMI_HB_VOTER, true, 0);
|
||||
pr_err("SMBMMI: Charge Halt..Toggle\n");
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NUM_STEPS; i++)
|
||||
chip->ocp[i] = 0;
|
||||
chip->pres_chrg_step = STEP_NORM;
|
||||
}
|
||||
} else if (chip->pres_chrg_step == STEP_NORM) {
|
||||
|
|
@ -1518,7 +1527,7 @@ static void mmi_basic_charge_sm(struct smb_mmi_charger *chip,
|
|||
(stat->batt_mv + HYST_STEP_MV) < max_fv_mv) {
|
||||
chip->chrg_taper_cnt = 0;
|
||||
chip->pres_chrg_step = STEP_NORM;
|
||||
} else if (mmi_has_current_tapered(chip, stat->batt_ma,
|
||||
} else if (mmi_has_current_tapered(chg, chip, stat->batt_ma,
|
||||
chip->chrg_iterm)) {
|
||||
chip->pres_chrg_step = STEP_FULL;
|
||||
}
|
||||
|
|
@ -1536,6 +1545,408 @@ static void mmi_basic_charge_sm(struct smb_mmi_charger *chip,
|
|||
/* Take State actions */
|
||||
switch (chip->pres_chrg_step) {
|
||||
case STEP_FLOAT:
|
||||
case STEP_MAX:
|
||||
if (!zone->norm_mv)
|
||||
chip->target_fv = max_fv_mv;
|
||||
else
|
||||
chip->target_fv = zone->norm_mv;
|
||||
chip->target_fcc = zone->fcc_max_ma;
|
||||
break;
|
||||
case STEP_FULL:
|
||||
chip->target_fv = max_fv_mv;
|
||||
chip->target_fcc = -EINVAL;
|
||||
break;
|
||||
case STEP_NORM:
|
||||
chip->target_fv = max_fv_mv + chg->vfloat_comp_mv;
|
||||
chip->target_fcc = zone->fcc_norm_ma;
|
||||
break;
|
||||
case STEP_NONE:
|
||||
chip->target_fv = max_fv_mv;
|
||||
chip->target_fcc = zone->fcc_norm_ma;
|
||||
break;
|
||||
case STEP_STOP:
|
||||
chip->target_fv = max_fv_mv;
|
||||
chip->target_fcc = -EINVAL;
|
||||
break;
|
||||
case STEP_DEMO:
|
||||
chip->target_fv = DEMO_MODE_VOLTAGE;
|
||||
chip->target_fcc = zone->fcc_max_ma;
|
||||
break;
|
||||
default:
|
||||
chip->target_fv = max_fv_mv;
|
||||
chip->target_fcc = zone->fcc_norm_ma;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chip->pres_temp_zone == ZONE_HOT) {
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
} else if (chip->pres_temp_zone == ZONE_COLD) {
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_COLD;
|
||||
} else if (stat->batt_temp >= WARM_TEMP) {
|
||||
if (chip->pres_chrg_step == STEP_STOP)
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
else
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
} else if (stat->batt_temp <= COOL_TEMP) {
|
||||
if (chip->pres_chrg_step == STEP_STOP)
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_COLD;
|
||||
else
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
} else
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
if ((start_tz != chip->pres_temp_zone) ||
|
||||
(start_step != chip->pres_chrg_step)) {
|
||||
pr_info("SMB_MMI:"
|
||||
"Batt %d: batt_mv = %d, batt_ma %d, batt_soc %d,"
|
||||
" batt_temp %d, usb_mv %d, cp %d, vp %d\n",
|
||||
batt,
|
||||
stat->batt_mv,
|
||||
stat->batt_ma,
|
||||
stat->batt_soc,
|
||||
stat->batt_temp,
|
||||
stat->usb_mv,
|
||||
stat->charger_present,
|
||||
stat->vbus_present);
|
||||
pr_info("SMBMMI:"
|
||||
"Batt %d Step State = %s, Temp Zone %d, Health %d\n",
|
||||
batt,
|
||||
stepchg_str[(int)chip->pres_chrg_step],
|
||||
chip->pres_temp_zone,
|
||||
chip->batt_health);
|
||||
return 1;
|
||||
} else {
|
||||
pr_debug("SMB_MMI:"
|
||||
"Batt %d: batt_mv = %d, batt_ma %d, batt_soc %d,"
|
||||
" batt_temp %d, usb_mv %d, cp %d, vp %d\n",
|
||||
batt,
|
||||
stat->batt_mv,
|
||||
stat->batt_ma,
|
||||
stat->batt_soc,
|
||||
stat->batt_temp,
|
||||
stat->usb_mv,
|
||||
stat->charger_present,
|
||||
stat->vbus_present);
|
||||
pr_debug("SMBMMI:"
|
||||
"Batt %d Step State = %s, Temp Zone %d, Health %d\n",
|
||||
batt,
|
||||
stepchg_str[(int)chip->pres_chrg_step],
|
||||
chip->pres_temp_zone,
|
||||
chip->batt_health);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmi_dual_charge_control(struct smb_mmi_charger *chg,
|
||||
struct smb_mmi_chg_status *stat)
|
||||
{
|
||||
int rc;
|
||||
int target_fcc;
|
||||
int target_fv;
|
||||
int effective_fv;
|
||||
int effective_fcc;
|
||||
int ocp;
|
||||
int sm_update;
|
||||
int sched_time = HEARTBEAT_DUAL_DELAY_MS;
|
||||
struct smb_mmi_chg_status chg_stat_main, chg_stat_flip;
|
||||
union power_supply_propval pval;
|
||||
struct mmi_sm_params *main_p = &chg->sm_param[MAIN_BATT];
|
||||
struct mmi_sm_params *flip_p = &chg->sm_param[FLIP_BATT];
|
||||
|
||||
chg_stat_main.charger_present = stat->charger_present;
|
||||
chg_stat_flip.charger_present = stat->charger_present;
|
||||
chg_stat_main.vbus_present = stat->vbus_present;
|
||||
chg_stat_flip.vbus_present = stat->vbus_present;
|
||||
chg_stat_main.usb_mv = stat->usb_mv;
|
||||
chg_stat_flip.usb_mv = stat->usb_mv;
|
||||
|
||||
rc = get_prop_batt_voltage_now(chg, chg->max_main_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Main Batt Voltage rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_main.batt_mv = pval.intval / 1000;
|
||||
|
||||
rc = get_prop_batt_voltage_now(chg, chg->max_flip_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Flip Batt Voltage rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_flip.batt_mv = pval.intval / 1000;
|
||||
|
||||
rc = get_prop_batt_current_now(chg, chg->max_main_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Main Batt Current rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_main.batt_ma = (pval.intval / 1000) * -1;
|
||||
|
||||
rc = get_prop_batt_current_now(chg, chg->max_flip_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Flip Batt Current rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_flip.batt_ma = (pval.intval / 1000) * -1;
|
||||
|
||||
rc = get_prop_batt_capacity(chg, chg->max_main_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Main Batt Capacity rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_main.batt_soc = pval.intval;
|
||||
|
||||
rc = get_prop_batt_capacity(chg, chg->max_flip_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Flip Batt Capacity rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_flip.batt_soc = pval.intval;
|
||||
|
||||
rc = get_prop_batt_temp(chg, chg->max_main_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Main Batt Temperature rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_main.batt_temp = pval.intval / 10;
|
||||
|
||||
rc = get_prop_batt_temp(chg, chg->max_flip_psy, &pval);
|
||||
if (rc < 0) {
|
||||
pr_err("Error getting Flip Batt Temperature rc = %d\n", rc);
|
||||
return sched_time;
|
||||
} else
|
||||
chg_stat_flip.batt_temp = pval.intval / 10;
|
||||
|
||||
sm_update = mmi_dual_charge_sm(chg, &chg_stat_main, MAIN_BATT);
|
||||
if (sm_update < 0)
|
||||
return sched_time;
|
||||
|
||||
sm_update = mmi_dual_charge_sm(chg, &chg_stat_flip, FLIP_BATT);
|
||||
if (sm_update < 0)
|
||||
return sched_time;
|
||||
|
||||
effective_fv = get_effective_result(chg->fv_votable) / 1000;
|
||||
effective_fcc = get_effective_result(chg->fcc_votable);
|
||||
|
||||
/* Check for Charge None */
|
||||
if ((main_p->pres_chrg_step == STEP_NONE) ||
|
||||
(flip_p->pres_chrg_step == STEP_NONE)) {
|
||||
target_fcc = main_p->target_fcc;
|
||||
target_fv = chg->base_fv_mv;
|
||||
sched_time = HEARTBEAT_DELAY_MS;
|
||||
goto vote_now;
|
||||
/* Check for Charge FULL from each */
|
||||
} else if ((main_p->pres_chrg_step == STEP_FULL) &&
|
||||
(flip_p->pres_chrg_step == STEP_FULL)) {
|
||||
target_fcc = -EINVAL;
|
||||
target_fv = chg->base_fv_mv;
|
||||
sched_time = HEARTBEAT_DELAY_MS;
|
||||
goto vote_now;
|
||||
/* Align FULL between batteries */
|
||||
} else if ((main_p->pres_chrg_step == STEP_FULL) &&
|
||||
((flip_p->pres_chrg_step == STEP_MAX) ||
|
||||
(flip_p->pres_chrg_step == STEP_NORM)) &&
|
||||
(chg_stat_flip.batt_soc >= 100) &&
|
||||
((chg_stat_flip.batt_mv + HYST_STEP_MV) >=
|
||||
chg->base_fv_mv)) {
|
||||
target_fcc = -EINVAL;
|
||||
target_fv = chg->base_fv_mv;
|
||||
flip_p->pres_chrg_step = STEP_FULL;
|
||||
pr_info("SMBMMI: Align Flip to Main FULL\n");
|
||||
goto vote_now;
|
||||
} else if ((flip_p->pres_chrg_step == STEP_FULL) &&
|
||||
((main_p->pres_chrg_step == STEP_MAX) ||
|
||||
(main_p->pres_chrg_step == STEP_NORM)) &&
|
||||
(chg_stat_main.batt_soc >= 100) &&
|
||||
((chg_stat_main.batt_mv + HYST_STEP_MV) >=
|
||||
chg->base_fv_mv)) {
|
||||
target_fcc = -EINVAL;
|
||||
target_fv = chg->base_fv_mv;
|
||||
main_p->pres_chrg_step = STEP_FULL;
|
||||
pr_info("SMBMMI: Align Main to Flip FULL\n");
|
||||
goto vote_now;
|
||||
/* Check for Charge Disable from each */
|
||||
} else if ((main_p->target_fcc < 0) ||
|
||||
(flip_p->target_fcc < 0)) {
|
||||
target_fcc = -EINVAL;
|
||||
target_fv = chg->base_fv_mv;
|
||||
goto vote_now;
|
||||
}
|
||||
|
||||
if (main_p->target_fv < flip_p->target_fv)
|
||||
target_fv = main_p->target_fv;
|
||||
else
|
||||
target_fv = flip_p->target_fv;
|
||||
|
||||
if (chg_stat_main.batt_ma < 0) {
|
||||
chg_stat_main.batt_ma *= -1;
|
||||
if (chg_stat_main.batt_ma > main_p->target_fcc) {
|
||||
ocp = chg_stat_main.batt_ma - main_p->target_fcc;
|
||||
main_p->ocp[main_p->pres_temp_zone] += ocp;
|
||||
pr_info("SMBMMI: Main Exceed by %d mA\n",
|
||||
main_p->ocp[main_p->pres_temp_zone]);
|
||||
}
|
||||
}
|
||||
|
||||
if (chg_stat_flip.batt_ma < 0) {
|
||||
chg_stat_flip.batt_ma *= -1;
|
||||
if (chg_stat_flip.batt_ma > flip_p->target_fcc) {
|
||||
ocp = chg_stat_flip.batt_ma - flip_p->target_fcc;
|
||||
flip_p->ocp[flip_p->pres_temp_zone] += ocp;
|
||||
pr_info("SMBMMI: Flip Exceed by %d mA\n",
|
||||
flip_p->ocp[flip_p->pres_temp_zone]);
|
||||
}
|
||||
}
|
||||
|
||||
target_fcc = main_p->target_fcc + flip_p->target_fcc;
|
||||
target_fcc -= main_p->ocp[main_p->pres_temp_zone];
|
||||
target_fcc -= flip_p->ocp[flip_p->pres_temp_zone];
|
||||
if (target_fcc < main_p->target_fcc) {
|
||||
pr_info("SMBMMI: Target FCC adjust too much\n");
|
||||
target_fcc = main_p->target_fcc;
|
||||
}
|
||||
|
||||
if (((main_p->pres_chrg_step == STEP_MAX) ||
|
||||
(flip_p->pres_chrg_step == STEP_MAX) ||
|
||||
(main_p->pres_chrg_step == STEP_NORM) ||
|
||||
(flip_p->pres_chrg_step == STEP_NORM)) &&
|
||||
mmi_charge_halted(chg)) {
|
||||
vote(chg->chg_dis_votable,
|
||||
MMI_HB_VOTER, true, 0);
|
||||
pr_err("SMBMMI: Charge Halt..Toggle\n");
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
vote_now:
|
||||
/* Votes for State */
|
||||
vote(chg->fv_votable, MMI_HB_VOTER, true, target_fv * 1000);
|
||||
|
||||
vote(chg->chg_dis_votable, MMI_HB_VOTER,
|
||||
(target_fcc < 0), 0);
|
||||
|
||||
vote(chg->fcc_votable, MMI_HB_VOTER,
|
||||
true, (target_fcc >= 0) ? (target_fcc * 1000) : 0);
|
||||
|
||||
if (sm_update)
|
||||
pr_info("SMBMMI:"
|
||||
"IMPOSED: FV = %d, CDIS = %d, FCC = %d, USBICL = %d\n",
|
||||
effective_fv,
|
||||
get_effective_result(chg->chg_dis_votable),
|
||||
effective_fcc,
|
||||
get_effective_result(chg->usb_icl_votable));
|
||||
else
|
||||
pr_debug("SMBMMI:"
|
||||
"IMPOSED: FV = %d, CDIS = %d, FCC = %d, USBICL = %d\n",
|
||||
effective_fv,
|
||||
get_effective_result(chg->chg_dis_votable),
|
||||
effective_fcc,
|
||||
get_effective_result(chg->usb_icl_votable));
|
||||
|
||||
return sched_time;
|
||||
}
|
||||
|
||||
static void mmi_basic_charge_sm(struct smb_mmi_charger *chip,
|
||||
struct smb_mmi_chg_status *stat)
|
||||
{
|
||||
int target_fcc;
|
||||
int target_fv;
|
||||
int max_fv_mv;
|
||||
struct mmi_temp_zone *zone;
|
||||
struct mmi_sm_params *prm = &chip->sm_param[BASE_BATT];
|
||||
|
||||
pr_info("SMBMMI: batt_mv = %d, batt_ma %d, batt_soc %d,"
|
||||
" batt_temp %d, usb_mv %d, cp %d, vp %d\n",
|
||||
stat->batt_mv,
|
||||
stat->batt_ma,
|
||||
stat->batt_soc,
|
||||
stat->batt_temp,
|
||||
stat->usb_mv,
|
||||
stat->charger_present,
|
||||
stat->vbus_present);
|
||||
|
||||
if (!prm->temp_zones) {
|
||||
pr_debug("SMBMMI: Skipping SM since No Temp Zone Defined!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (chip->base_fv_mv == 0) {
|
||||
chip->base_fv_mv = get_effective_result(chip->fv_votable);
|
||||
chip->base_fv_mv /= 1000;
|
||||
vote(chip->fv_votable,
|
||||
BATT_PROFILE_VOTER, false, 0);
|
||||
}
|
||||
max_fv_mv = chip->base_fv_mv;
|
||||
|
||||
mmi_find_temp_zone(chip, prm, stat->batt_temp);
|
||||
zone = &prm->temp_zones[prm->pres_temp_zone];
|
||||
|
||||
if (!stat->charger_present) {
|
||||
prm->pres_chrg_step = STEP_NONE;
|
||||
} else if ((prm->pres_temp_zone == ZONE_HOT) ||
|
||||
(prm->pres_temp_zone == ZONE_COLD)) {
|
||||
prm->pres_chrg_step = STEP_STOP;
|
||||
} else if (chip->demo_mode) {
|
||||
/* TODO: Ignore Demo Mode for now */
|
||||
} else if ((prm->pres_chrg_step == STEP_NONE) ||
|
||||
(prm->pres_chrg_step == STEP_STOP)) {
|
||||
if (zone->norm_mv && (stat->batt_mv >= zone->norm_mv)) {
|
||||
if (zone->fcc_norm_ma)
|
||||
prm->pres_chrg_step = STEP_NORM;
|
||||
else
|
||||
prm->pres_chrg_step = STEP_STOP;
|
||||
} else
|
||||
prm->pres_chrg_step = STEP_MAX;
|
||||
} else if (prm->pres_chrg_step == STEP_MAX) {
|
||||
if (!zone->norm_mv) {
|
||||
/* No Step in this Zone */
|
||||
prm->chrg_taper_cnt = 0;
|
||||
if ((stat->batt_mv + HYST_STEP_MV) >= max_fv_mv)
|
||||
prm->pres_chrg_step = STEP_NORM;
|
||||
else
|
||||
prm->pres_chrg_step = STEP_MAX;
|
||||
} else if ((stat->batt_mv + HYST_STEP_MV) < zone->norm_mv) {
|
||||
prm->chrg_taper_cnt = 0;
|
||||
prm->pres_chrg_step = STEP_MAX;
|
||||
} else if (!zone->fcc_norm_ma)
|
||||
prm->pres_chrg_step = STEP_FLOAT;
|
||||
else if (mmi_has_current_tapered(chip, prm, stat->batt_ma,
|
||||
zone->fcc_norm_ma)) {
|
||||
prm->chrg_taper_cnt = 0;
|
||||
|
||||
if (mmi_charge_halted(chip)) {
|
||||
vote(chip->chg_dis_votable,
|
||||
MMI_HB_VOTER, true, 0);
|
||||
pr_err("SMBMMI: Charge Halt..Toggle\n");
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
prm->pres_chrg_step = STEP_NORM;
|
||||
}
|
||||
} else if (prm->pres_chrg_step == STEP_NORM) {
|
||||
if (!zone->fcc_norm_ma)
|
||||
prm->pres_chrg_step = STEP_STOP;
|
||||
else if ((stat->batt_soc < 100) ||
|
||||
(stat->batt_mv + HYST_STEP_MV) < max_fv_mv) {
|
||||
prm->chrg_taper_cnt = 0;
|
||||
prm->pres_chrg_step = STEP_NORM;
|
||||
} else if (mmi_has_current_tapered(chip, prm, stat->batt_ma,
|
||||
prm->chrg_iterm)) {
|
||||
prm->pres_chrg_step = STEP_FULL;
|
||||
}
|
||||
} else if (prm->pres_chrg_step == STEP_FULL) {
|
||||
if (stat->batt_soc <= 99) {
|
||||
prm->chrg_taper_cnt = 0;
|
||||
prm->pres_chrg_step = STEP_NORM;
|
||||
}
|
||||
} else if (prm->pres_chrg_step == STEP_FLOAT) {
|
||||
if ((zone->fcc_norm_ma) ||
|
||||
((stat->batt_mv + HYST_STEP_MV) < zone->norm_mv))
|
||||
prm->pres_chrg_step = STEP_MAX;
|
||||
}
|
||||
|
||||
/* Take State actions */
|
||||
switch (prm->pres_chrg_step) {
|
||||
case STEP_FLOAT:
|
||||
case STEP_MAX:
|
||||
if (!zone->norm_mv)
|
||||
target_fv = max_fv_mv;
|
||||
|
|
@ -1578,27 +1989,27 @@ static void mmi_basic_charge_sm(struct smb_mmi_charger *chip,
|
|||
vote(chip->fcc_votable, MMI_HB_VOTER,
|
||||
true, (target_fcc >= 0) ? (target_fcc * 1000) : 0);
|
||||
|
||||
if (chip->pres_temp_zone == ZONE_HOT) {
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
} else if (chip->pres_temp_zone == ZONE_COLD) {
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_COLD;
|
||||
if (prm->pres_temp_zone == ZONE_HOT) {
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
} else if (prm->pres_temp_zone == ZONE_COLD) {
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_COLD;
|
||||
} else if (stat->batt_temp >= WARM_TEMP) {
|
||||
if (chip->pres_chrg_step == STEP_STOP)
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
if (prm->pres_chrg_step == STEP_STOP)
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
else
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
} else if (stat->batt_temp <= COOL_TEMP) {
|
||||
if (chip->pres_chrg_step == STEP_STOP)
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_COLD;
|
||||
if (prm->pres_chrg_step == STEP_STOP)
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_COLD;
|
||||
else
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
} else
|
||||
chip->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
prm->batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
pr_info("SMBMMI: Step State = %s, Temp Zone %d, Health %d\n",
|
||||
stepchg_str[(int)chip->pres_chrg_step],
|
||||
chip->pres_temp_zone,
|
||||
chip->batt_health);
|
||||
stepchg_str[(int)prm->pres_chrg_step],
|
||||
prm->pres_temp_zone,
|
||||
prm->batt_health);
|
||||
pr_info("SMBMMI: IMPOSED: FV = %d, CDIS = %d, FCC = %d, USBICL = %d\n",
|
||||
get_effective_result(chip->fv_votable),
|
||||
get_effective_result(chip->chg_dis_votable),
|
||||
|
|
@ -1622,8 +2033,6 @@ static int factory_kill_disable;
|
|||
module_param(factory_kill_disable, int, 0644);
|
||||
#define TWO_VOLT 2000000
|
||||
#define SMBCHG_HEARTBEAT_INTERVAL_NS 70000000000
|
||||
#define HEARTBEAT_DELAY_MS 60000
|
||||
#define HEARTBEAT_FACTORY_MS 1000
|
||||
static void mmi_heartbeat_work(struct work_struct *work)
|
||||
{
|
||||
struct smb_mmi_charger *chip = container_of(work,
|
||||
|
|
@ -1766,6 +2175,9 @@ static void mmi_heartbeat_work(struct work_struct *work)
|
|||
if (rc < 0)
|
||||
pr_err("SMBMMI: Couldn't set batt psy cap\n");
|
||||
}
|
||||
|
||||
/* Dual Step and Thermal Charging */
|
||||
hb_resch_time = mmi_dual_charge_control(chip, &chg_stat);
|
||||
} else if (!chip->factory_mode) {
|
||||
/* Fall here for Basic Step and Thermal Charging */
|
||||
mmi_basic_charge_sm(chip, &chg_stat);
|
||||
|
|
@ -1920,54 +2332,55 @@ static int parse_mmi_dt(struct smb_mmi_charger *chg)
|
|||
int rc = 0;
|
||||
int byte_len;
|
||||
int i;
|
||||
struct mmi_sm_params *chip;
|
||||
|
||||
if (!node) {
|
||||
pr_err("mmi dtree info. missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
chip = &chg->sm_param[BASE_BATT];
|
||||
if (of_find_property(node, "qcom,mmi-temp-zones", &byte_len)) {
|
||||
if ((byte_len / sizeof(u32)) % 4) {
|
||||
pr_err("DT error wrong mmi temp zones\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chg->temp_zones = (struct mmi_temp_zone *)
|
||||
chip->temp_zones = (struct mmi_temp_zone *)
|
||||
devm_kzalloc(chg->dev, byte_len, GFP_KERNEL);
|
||||
|
||||
if (chg->temp_zones == NULL)
|
||||
if (chip->temp_zones == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chg->num_temp_zones =
|
||||
chip->num_temp_zones =
|
||||
byte_len / sizeof(struct mmi_temp_zone);
|
||||
|
||||
rc = of_property_read_u32_array(node,
|
||||
"qcom,mmi-temp-zones",
|
||||
(u32 *)chg->temp_zones,
|
||||
(u32 *)chip->temp_zones,
|
||||
byte_len / sizeof(u32));
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read mmi temp zones rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_err("mmi temp zones: Num: %d\n", chg->num_temp_zones);
|
||||
for (i = 0; i < chg->num_temp_zones; i++) {
|
||||
pr_err("mmi temp zones: Num: %d\n", chip->num_temp_zones);
|
||||
for (i = 0; i < chip->num_temp_zones; i++) {
|
||||
pr_err("mmi temp zones: Zone %d, Temp %d C, " \
|
||||
"Step Volt %d mV, Full Rate %d mA, " \
|
||||
"Taper Rate %d mA\n", i,
|
||||
chg->temp_zones[i].temp_c,
|
||||
chg->temp_zones[i].norm_mv,
|
||||
chg->temp_zones[i].fcc_max_ma,
|
||||
chg->temp_zones[i].fcc_norm_ma);
|
||||
chip->temp_zones[i].temp_c,
|
||||
chip->temp_zones[i].norm_mv,
|
||||
chip->temp_zones[i].fcc_max_ma,
|
||||
chip->temp_zones[i].fcc_norm_ma);
|
||||
}
|
||||
chg->pres_temp_zone = ZONE_NONE;
|
||||
chip->pres_temp_zone = ZONE_NONE;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,iterm-ma",
|
||||
&chg->chrg_iterm);
|
||||
&chip->chrg_iterm);
|
||||
if (rc)
|
||||
chg->chrg_iterm = 150;
|
||||
chip->chrg_iterm = 150;
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,vfloat-comp-uv",
|
||||
&chg->vfloat_comp_mv);
|
||||
|
|
@ -1978,6 +2391,108 @@ static int parse_mmi_dt(struct smb_mmi_charger *chg)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int parse_mmi_dual_dt(struct smb_mmi_charger *chg)
|
||||
{
|
||||
struct device_node *node = chg->dev->of_node;
|
||||
int rc = 0;
|
||||
int byte_len;
|
||||
int i;
|
||||
struct mmi_sm_params *chip;
|
||||
|
||||
if (!node) {
|
||||
pr_err("mmi dtree info. missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip = &chg->sm_param[MAIN_BATT];
|
||||
if (of_find_property(node, "qcom,mmi-temp-zones-main", &byte_len)) {
|
||||
if ((byte_len / sizeof(u32)) % 4) {
|
||||
pr_err("DT error wrong mmi temp zones\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip->temp_zones = (struct mmi_temp_zone *)
|
||||
devm_kzalloc(chg->dev, byte_len, GFP_KERNEL);
|
||||
|
||||
if (chip->temp_zones == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->num_temp_zones =
|
||||
byte_len / sizeof(struct mmi_temp_zone);
|
||||
|
||||
rc = of_property_read_u32_array(node,
|
||||
"qcom,mmi-temp-zones-main",
|
||||
(u32 *)chip->temp_zones,
|
||||
byte_len / sizeof(u32));
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read mmi temp zones rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_err("mmi temp zones main: Num: %d\n", chip->num_temp_zones);
|
||||
for (i = 0; i < chip->num_temp_zones; i++) {
|
||||
pr_err("mmi temp zones: Zone %d, Temp %d C, " \
|
||||
"Step Volt %d mV, Full Rate %d mA, " \
|
||||
"Taper Rate %d mA\n", i,
|
||||
chip->temp_zones[i].temp_c,
|
||||
chip->temp_zones[i].norm_mv,
|
||||
chip->temp_zones[i].fcc_max_ma,
|
||||
chip->temp_zones[i].fcc_norm_ma);
|
||||
}
|
||||
chip->pres_temp_zone = ZONE_NONE;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,iterm-ma-main",
|
||||
&chip->chrg_iterm);
|
||||
if (rc)
|
||||
chip->chrg_iterm = 150;
|
||||
|
||||
chip = &chg->sm_param[FLIP_BATT];
|
||||
if (of_find_property(node, "qcom,mmi-temp-zones-flip", &byte_len)) {
|
||||
if ((byte_len / sizeof(u32)) % 4) {
|
||||
pr_err("DT error wrong mmi temp zones\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip->temp_zones = (struct mmi_temp_zone *)
|
||||
devm_kzalloc(chg->dev, byte_len, GFP_KERNEL);
|
||||
|
||||
if (chip->temp_zones == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->num_temp_zones =
|
||||
byte_len / sizeof(struct mmi_temp_zone);
|
||||
|
||||
rc = of_property_read_u32_array(node,
|
||||
"qcom,mmi-temp-zones-flip",
|
||||
(u32 *)chip->temp_zones,
|
||||
byte_len / sizeof(u32));
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read mmi temp zones rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_err("mmi temp zones main: Num: %d\n", chip->num_temp_zones);
|
||||
for (i = 0; i < chip->num_temp_zones; i++) {
|
||||
pr_err("mmi temp zones: Zone %d, Temp %d C, " \
|
||||
"Step Volt %d mV, Full Rate %d mA, " \
|
||||
"Taper Rate %d mA\n", i,
|
||||
chip->temp_zones[i].temp_c,
|
||||
chip->temp_zones[i].norm_mv,
|
||||
chip->temp_zones[i].fcc_max_ma,
|
||||
chip->temp_zones[i].fcc_norm_ma);
|
||||
}
|
||||
chip->pres_temp_zone = ZONE_NONE;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,iterm-ma-flip",
|
||||
&chip->chrg_iterm);
|
||||
if (rc)
|
||||
chip->chrg_iterm = 150;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smb_mmi_chg_config_init(struct smb_mmi_charger *chip)
|
||||
{
|
||||
struct pmic_revid_data *pmic_rev_id;
|
||||
|
|
@ -2082,6 +2597,7 @@ static int smb_mmi_probe(struct platform_device *pdev)
|
|||
if (!rc && max_main_name && max_flip_name) {
|
||||
chip->max_main_psy = power_supply_get_by_name(max_main_name);
|
||||
chip->max_flip_psy = power_supply_get_by_name(max_flip_name);
|
||||
parse_mmi_dual_dt(chip);
|
||||
}
|
||||
|
||||
chip->chg_dis_votable = find_votable("CHG_DISABLE");
|
||||
|
|
|
|||
Loading…
Reference in a new issue