Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7d1ccb3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: qcom-charger: delay ICL change reporting to parallel psy"

parents 41bb6894 9c5b523f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ Optional Properties:
				via pin in a parallel-charger configuration.
				0 - Active low and 1  - Active high.
				If not specified the default value is active-low.
- qcom,parallel-external-current-sense If present specifies external rsense is
				used for charge current sensing.

Example for standalone charger:

+40 −8
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct pl_data {
	struct votable		*fv_votable;
	struct votable		*pl_disable_votable;
	struct votable		*pl_awake_votable;
	struct votable		*hvdcp_hw_inov_dis_votable;
	struct work_struct	status_change_work;
	struct work_struct	pl_disable_forever_work;
	struct delayed_work	pl_taper_work;
@@ -96,7 +97,8 @@ static void split_settled(struct pl_data *chip)
	 * for desired split
	 */

	if (chip->pl_mode != POWER_SUPPLY_PARALLEL_USBIN_USBIN)
	if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN)
		&& (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT))
		return;

	if (!chip->main_psy)
@@ -262,7 +264,7 @@ static void split_fcc(struct pl_data *chip, int total_ua,
		hw_cc_delta_ua = pval.intval;

	bcl_ua = INT_MAX;
	if (chip->pl_mode == POWER_SUPPLY_PARALLEL_MID_MID) {
	if (chip->pl_mode == POWER_SUPPLY_PL_USBMID_USBMID) {
		rc = power_supply_get_property(chip->main_psy,
			       POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval);
		if (rc < 0) {
@@ -287,6 +289,14 @@ static void split_fcc(struct pl_data *chip, int total_ua,
	slave_limited_ua = min(effective_total_ua, bcl_ua);
	*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
	*slave_ua = (*slave_ua * chip->taper_pct) / 100;
	/*
	 * In USBIN_USBIN configuration with internal rsense parallel
	 * charger's current goes through main charger's BATFET, keep
	 * the main charger's FCC to the votable result.
	 */
	if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
		*master_ua = max(0, total_ua);
	else
		*master_ua = max(0, total_ua - *slave_ua);
}

@@ -316,7 +326,7 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
			total_fcc_ua = pval.intval;
	}

	if (chip->pl_mode == POWER_SUPPLY_PARALLEL_NONE
	if (chip->pl_mode == POWER_SUPPLY_PL_NONE
	    || get_effective_result_locked(chip->pl_disable_votable)) {
		pval.intval = total_fcc_ua;
		rc = power_supply_set_property(chip->main_psy,
@@ -391,7 +401,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
		return rc;
	}

	if (chip->pl_mode != POWER_SUPPLY_PARALLEL_NONE) {
	if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
		pval.intval += PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
		rc = power_supply_set_property(chip->pl_psy,
				POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
@@ -411,6 +421,10 @@ static void pl_disable_forever_work(struct work_struct *work)

	/* Disable Parallel charger forever */
	vote(chip->pl_disable_votable, PL_HW_ABSENT_VOTER, true, 0);

	/* Re-enable autonomous mode */
	if (chip->hvdcp_hw_inov_dis_votable)
		vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER, false, 0);
}

static int pl_disable_vote_callback(struct votable *votable,
@@ -451,7 +465,8 @@ static int pl_disable_vote_callback(struct votable *votable,
			pr_err("Couldn't change slave suspend state rc=%d\n",
				rc);

		if (chip->pl_mode == POWER_SUPPLY_PARALLEL_USBIN_USBIN)
		if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
			|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
			split_settled(chip);
		/*
		 * we could have been enabled while in taper mode,
@@ -469,7 +484,8 @@ static int pl_disable_vote_callback(struct votable *votable,
			}
		}
	} else {
		if (chip->pl_mode == POWER_SUPPLY_PARALLEL_USBIN_USBIN)
		if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
			|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
			split_settled(chip);

		/* pl_psy may be NULL while in the disable branch */
@@ -552,6 +568,21 @@ static bool is_parallel_available(struct pl_data *chip)
	 * pl_psy is present and valid.
	 */
	chip->pl_mode = pval.intval;

	/* Disable autonomous votage increments for USBIN-USBIN */
	if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
		|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) {
		if (!chip->hvdcp_hw_inov_dis_votable)
			chip->hvdcp_hw_inov_dis_votable =
					find_votable("HVDCP_HW_INOV_DIS");
		if (chip->hvdcp_hw_inov_dis_votable)
			/* Read current pulse count */
			vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER,
					true, 0);
		else
			return false;
	}

	vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);

	return true;
@@ -610,7 +641,8 @@ static void handle_settled_aicl_split(struct pl_data *chip)
	int rc;

	if (!get_effective_result(chip->pl_disable_votable)
		&& chip->pl_mode == POWER_SUPPLY_PARALLEL_USBIN_USBIN) {
		&& (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN
			|| chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) {
		/*
		 * call aicl split only when USBIN_USBIN and enabled
		 * and if aicl changed
+16 −0
Original line number Diff line number Diff line
@@ -848,6 +848,8 @@ static enum power_supply_property smb2_batt_props[] = {
	POWER_SUPPLY_PROP_PARALLEL_DISABLE,
	POWER_SUPPLY_PROP_SET_SHIP_MODE,
	POWER_SUPPLY_PROP_DIE_HEALTH,
	POWER_SUPPLY_PROP_RERUN_AICL,
	POWER_SUPPLY_PROP_DP_DM,
};

static int smb2_batt_get_prop(struct power_supply *psy,
@@ -933,6 +935,12 @@ static int smb2_batt_get_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_DIE_HEALTH:
		rc = smblib_get_prop_die_health(chg, val);
		break;
	case POWER_SUPPLY_PROP_DP_DM:
		val->intval = chg->pulse_cnt;
		break;
	case POWER_SUPPLY_PROP_RERUN_AICL:
		val->intval = 0;
		break;
	default:
		pr_err("batt power supply prop %d not supported\n", psp);
		return -EINVAL;
@@ -986,6 +994,12 @@ static int smb2_batt_set_prop(struct power_supply *psy,
			break;
		rc = smblib_set_prop_ship_mode(chg, val);
		break;
	case POWER_SUPPLY_PROP_RERUN_AICL:
		rc = smblib_rerun_aicl(chg);
		break;
	case POWER_SUPPLY_PROP_DP_DM:
		rc = smblib_dp_dm(chg, val->intval);
		break;
	default:
		rc = -EINVAL;
	}
@@ -1001,6 +1015,8 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy,
	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
	case POWER_SUPPLY_PROP_CAPACITY:
	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
	case POWER_SUPPLY_PROP_DP_DM:
	case POWER_SUPPLY_PROP_RERUN_AICL:
		return 1;
	default:
		break;
+227 −17
Original line number Diff line number Diff line
@@ -58,6 +58,12 @@ int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
	return rc;
}

int smblib_multibyte_read(struct smb_charger *chg, u16 addr, u8 *val,
				int count)
{
	return regmap_bulk_read(chg->regmap, addr, val, count);
}

int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
{
	int rc = 0;
@@ -652,6 +658,8 @@ static void smblib_uusb_removal(struct smb_charger *chg)

	chg->voltage_min_uv = MICRO_5V;
	chg->voltage_max_uv = MICRO_5V;
	chg->usb_icl_delta_ua = 0;
	chg->pulse_cnt = 0;

	/* clear USB ICL vote for USB_PSY_VOTER */
	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
@@ -741,6 +749,40 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg)
	return 0;
}

static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
{
	int rc;
	u8 val[2];

	switch (chg->smb_version) {
	case PMI8998_SUBTYPE:
		rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
		if (rc) {
			pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
					rc);
			return rc;
		}
		*count = val[0] & QC_PULSE_COUNT_MASK;
		break;
	case PM660_SUBTYPE:
		rc = smblib_multibyte_read(chg,
				QC_PULSE_COUNT_STATUS_1_REG, val, 2);
		if (rc) {
			pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
					rc);
			return rc;
		}
		*count = (val[1] << 8) | val[0];
		break;
	default:
		smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
				chg->smb_version);
		return -EINVAL;
	}

	return 0;
}

/*********************
 * VOTABLE CALLBACKS *
 *********************/
@@ -975,8 +1017,10 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
{
	struct smb_charger *chg = data;
	int rc;
	u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT
		| HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT | HVDCP_EN_BIT;
	u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;

	/* vote to enable/disable HW autonomous INOV */
	vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);

	/*
	 * Disable the autonomous bit and auth bit for disabling hvdcp.
@@ -987,9 +1031,7 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
		val = HVDCP_EN_BIT;

	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
				 HVDCP_EN_BIT
				 | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT
				 | HVDCP_AUTH_ALG_EN_CFG_BIT,
				 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
				 val);
	if (rc < 0) {
		smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
@@ -1058,6 +1100,37 @@ static int smblib_apsd_disable_vote_callback(struct votable *votable,
	return 0;
}

static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
				void *data, int disable, const char *client)
{
	struct smb_charger *chg = data;
	int rc;

	if (disable) {
		/*
		 * the pulse count register get zeroed when autonomous mode is
		 * disabled. Track that in variables before disabling
		 */
		rc = smblib_get_pulse_cnt(chg, &chg->pulse_cnt);
		if (rc < 0) {
			pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
					rc);
			return rc;
		}
	}

	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
			HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
			disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
	if (rc < 0) {
		smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
				disable ? "disable" : "enable", rc);
		return rc;
	}

	return rc;
}

/*******************
 * VCONN REGULATOR *
 * *****************/
@@ -1645,6 +1718,98 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg,
	return 0;
}

int smblib_rerun_aicl(struct smb_charger *chg)
{
	int rc = 0;
	u8 val;

	/*
	 * Use restart_AICL instead of trigger_AICL as it runs the
	 * complete AICL instead of starting from the last settled value.
	 *
	 * 8998 only supports trigger_AICL return error for 8998
	 */
	switch (chg->smb_version) {
	case PMI8998_SUBTYPE:
		smblib_dbg(chg, PR_PARALLEL, "AICL rerun not supported\n");
		return -EINVAL;
	case PM660_SUBTYPE:
		val = RESTART_AICL_BIT;
		break;
	default:
		smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
				chg->smb_version);
		return -EINVAL;
	}
	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
	if (rc < 0)
		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
				rc);

	return rc;
}

static int smblib_dp_pulse(struct smb_charger *chg)
{
	int rc;

	/* QC 3.0 increment */
	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
			SINGLE_INCREMENT_BIT);
	if (rc < 0)
		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
				rc);

	return rc;
}

static int smblib_dm_pulse(struct smb_charger *chg)
{
	int rc;

	/* QC 3.0 decrement */
	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
			SINGLE_DECREMENT_BIT);
	if (rc < 0)
		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
				rc);

	return rc;
}

int smblib_dp_dm(struct smb_charger *chg, int val)
{
	int target_icl_ua, rc = 0;

	switch (val) {
	case POWER_SUPPLY_DP_DM_DP_PULSE:
		rc = smblib_dp_pulse(chg);
		if (!rc)
			chg->pulse_cnt++;
		smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
				rc, chg->pulse_cnt);
		break;
	case POWER_SUPPLY_DP_DM_DM_PULSE:
		rc = smblib_dm_pulse(chg);
		if (!rc && chg->pulse_cnt)
			chg->pulse_cnt--;
		smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
				rc, chg->pulse_cnt);
		break;
	case POWER_SUPPLY_DP_DM_ICL_DOWN:
		chg->usb_icl_delta_ua -= 100000;
		target_icl_ua = get_effective_result(chg->usb_icl_votable);
		vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
				target_icl_ua + chg->usb_icl_delta_ua);
		break;
	case POWER_SUPPLY_DP_DM_ICL_UP:
	default:
		break;
	}

	return rc;
}

/*******************
 * DC PSY GETTERS *
 *******************/
@@ -2915,26 +3080,38 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
}

#define USB_WEAK_INPUT_UA	1400000
#define ICL_CHANGE_DELAY_MS	1000
irqreturn_t smblib_handle_icl_change(int irq, void *data)
{
	u8 stat;
	int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	int rc, settled_ua;

	rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
	if (chg->mode == PARALLEL_MASTER) {
		rc = smblib_read(chg, AICL_STATUS_REG, &stat);
		if (rc < 0) {
			smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
					rc);
			return IRQ_HANDLED;
		}

		rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
				&settled_ua);
		if (rc < 0) {
			smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
			return IRQ_HANDLED;
		}

	if (chg->mode == PARALLEL_MASTER) {
		power_supply_changed(chg->usb_main_psy);
		vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
					settled_ua >= USB_WEAK_INPUT_UA, 0);
		/* If AICL settled then schedule work now */
		if ((settled_ua == get_effective_result(chg->usb_icl_votable))
				|| (stat & AICL_DONE_BIT))
			delay = 0;

		schedule_delayed_work(&chg->icl_change_work,
						msecs_to_jiffies(delay));
	}

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s icl_settled=%d\n",
						irq_data->name, settled_ua);
	return IRQ_HANDLED;
}

@@ -3279,6 +3456,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)

	chg->vconn_attempts = 0;
	chg->otg_attempts = 0;
	chg->pulse_cnt = 0;
	chg->usb_icl_delta_ua = 0;

	chg->usb_ever_removed = true;

@@ -3801,6 +3980,25 @@ static void smblib_otg_ss_done_work(struct work_struct *work)
	mutex_unlock(&chg->otg_oc_lock);
}

static void smblib_icl_change_work(struct work_struct *work)
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
							icl_change_work.work);
	int rc, settled_ua;

	rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
	if (rc < 0) {
		smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
		return;
	}

	power_supply_changed(chg->usb_main_psy);
	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
				settled_ua >= USB_WEAK_INPUT_UA, 0);

	smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
}

static int smblib_create_votables(struct smb_charger *chg)
{
	int rc = 0;
@@ -3917,6 +4115,15 @@ static int smblib_create_votables(struct smb_charger *chg)
		return rc;
	}

	chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
					VOTE_SET_ANY,
					smblib_hvdcp_hw_inov_dis_vote_callback,
					chg);
	if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
		rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
		return rc;
	}

	return rc;
}

@@ -3940,6 +4147,8 @@ static void smblib_destroy_votables(struct smb_charger *chg)
		destroy_votable(chg->pl_enable_votable_indirect);
	if (chg->apsd_disable_votable)
		destroy_votable(chg->apsd_disable_votable);
	if (chg->hvdcp_hw_inov_dis_votable)
		destroy_votable(chg->hvdcp_hw_inov_dis_votable);
}

static void smblib_iio_deinit(struct smb_charger *chg)
@@ -3970,6 +4179,7 @@ int smblib_init(struct smb_charger *chg)
	INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
	INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
	INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
	INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
	chg->fake_capacity = -EINVAL;

	switch (chg->mode) {
+7 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ enum print_reason {
#define PD_SUSPEND_SUPPORTED_VOTER	"PD_SUSPEND_SUPPORTED_VOTER"
#define PL_DELAY_HVDCP_VOTER		"PL_DELAY_HVDCP_VOTER"
#define CTM_VOTER			"CTM_VOTER"
#define SW_QC3_VOTER			"SW_QC3_VOTER"

#define VCONN_MAX_ATTEMPTS	3
#define OTG_MAX_ATTEMPTS	3
@@ -267,6 +268,7 @@ struct smb_charger {
	struct votable		*hvdcp_disable_votable_indirect;
	struct votable		*hvdcp_enable_votable;
	struct votable		*apsd_disable_votable;
	struct votable		*hvdcp_hw_inov_dis_votable;

	/* work */
	struct work_struct	bms_update_work;
@@ -278,6 +280,7 @@ struct smb_charger {
	struct work_struct	otg_oc_work;
	struct work_struct	vconn_oc_work;
	struct delayed_work	otg_ss_done_work;
	struct delayed_work	icl_change_work;

	/* cached status */
	int			voltage_min_uv;
@@ -315,6 +318,8 @@ struct smb_charger {
	/* qnovo */
	int			qnovo_fcc_ua;
	int			qnovo_fv_uv;
	int			usb_icl_delta_ua;
	int			pulse_cnt;
};

int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -472,6 +477,8 @@ 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_dp_dm(struct smb_charger *chg, int val);
int smblib_rerun_aicl(struct smb_charger *chg);

int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
Loading