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

Commit 0fc34a9f authored by Harry Yang's avatar Harry Yang Committed by Guru Das Srinagesh
Browse files

power: smb5: Read USBIN voltage via MID_CHG for PM8150B



Currently, the charger driver uses the ADC_USB_IN_V_16 channel to read
USBIN adaptor voltage. The problem with this channel is that overvoltage
is observed to randomly occur while reading it, particularly when the
voltages being read are greater than 9V.

Therefore, switch to using the ADC_MID_CHG_DIV6 channel which is more
stable.

Now, this presents a new challenge - the reading from this channel goes
low (< 1 V) if the voltage on this channel exceeds 10.5V. In this case,
we provide an estimate of the voltage using alternate means:

- For HVDCP2, we read status bits in a register;
- For HVDCP3, we count the number of pulses accumulated so far and
  extrapolate the voltage from 5 V; and
- For USB-PD, we calculate the average of min and max voltages.

Change-Id: Id83e901806cc0d0f135ce3bd699d535407cf3dea
Signed-off-by: default avatarHarry Yang <harryy@codeaurora.org>
Signed-off-by: default avatarGuru Das Srinagesh <gurus@codeaurora.org>
parent 01697ba5
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -615,12 +615,12 @@
&pm8150b_charger {
	qcom,sec-charger-config = <3>;
	qcom,auto-recharge-soc = <98>;
	io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>,
	io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>,
		      <&pm8150b_vadc ADC_USB_IN_I>,
		      <&pm8150b_vadc ADC_SBUx>,
		      <&pm8150b_vadc ADC_VPH_PWR>,
		      <&pm8150b_vadc ADC_CHG_TEMP>;
	io-channel-names = "usb_in_voltage",
	io-channel-names = "mid_voltage",
			   "usb_in_current",
			   "sbux_res",
			   "vph_voltage",
+2 −2
Original line number Diff line number Diff line
@@ -563,12 +563,12 @@
&pm8150b_charger {
	qcom,sec-charger-config = <1>;
	qcom,auto-recharge-soc = <98>;
	io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>,
	io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>,
		      <&pm8150b_vadc ADC_USB_IN_I>,
		      <&pm8150b_vadc ADC_SBUx>,
		      <&pm8150b_vadc ADC_VPH_PWR>,
		      <&pm8150b_vadc ADC_CHG_TEMP>;
	io-channel-names = "usb_in_voltage",
	io-channel-names = "mid_voltage",
			   "usb_in_current",
			   "sbux_res",
			   "vph_voltage",
+13 −2
Original line number Diff line number Diff line
@@ -443,11 +443,22 @@ static int smb5_parse_dt(struct smb5 *chip)
					"qcom,fcc-stepping-enable");

	/* Extract ADC channels */
	rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan);
	if (rc < 0)
		return rc;

	if (!chg->iio.mid_chan) {
		rc = smblib_get_iio_channel(chg, "usb_in_voltage",
				&chg->iio.usbin_v_chan);
		if (rc < 0)
			return rc;

		if (!chg->iio.usbin_v_chan) {
			dev_err(chg->dev, "No voltage channel defined");
			return -EINVAL;
		}
	}

	rc = smblib_get_iio_channel(chg, "chg_temp", &chg->iio.temp_chan);
	if (rc < 0)
		return rc;
+106 −31
Original line number Diff line number Diff line
@@ -2644,44 +2644,120 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
	return 0;
}

int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
static int smblib_estimate_hvdcp_voltage(struct smb_charger *chg,
					 union power_supply_propval *val)
{
	int rc, ret = 0;
	int rc;
	u8 stat;

	/* set 12V OV to 14.6V */
	if (chg->smb_version == PM8150B_SUBTYPE) {
		rc = smblib_masked_write(chg, USB_ENG_SSUPPLY_USB2_REG,
				ENG_SSUPPLY_12V_OV_OPT_BIT,
				ENG_SSUPPLY_12V_OV_OPT_BIT);
	rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
	if (rc < 0) {
			smblib_err(chg, "Couldn't set USB_ENG_SSUPPLY_USB2_REG rc=%d\n",
		smblib_err(chg, "Couldn't read QC_CHANGE_STATUS_REG rc=%d\n",
				rc);
		return rc;
	}

	if (stat & QC_5V_BIT)
		val->intval = MICRO_5V;
	else if (stat & QC_9V_BIT)
		val->intval = MICRO_9V;
	else if (stat & QC_12V_BIT)
		val->intval = MICRO_12V;

	return 0;
}

#define HVDCP3_STEP_UV	200000
static int smblib_estimate_adaptor_voltage(struct smb_charger *chg,
					  union power_supply_propval *val)
{
	switch (chg->real_charger_type) {
	case POWER_SUPPLY_TYPE_USB_HVDCP:
		return smblib_estimate_hvdcp_voltage(chg, val);
	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
		val->intval = MICRO_5V + (HVDCP3_STEP_UV * chg->pulse_cnt);
		break;
	case POWER_SUPPLY_TYPE_USB_PD:
		/* Take the average of min and max values */
		val->intval = chg->voltage_min_uv +
			((chg->voltage_max_uv - chg->voltage_min_uv) / 2);
		break;
	default:
		val->intval = MICRO_5V;
		break;
	}

	return 0;
}

static int smblib_read_mid_voltage_chan(struct smb_charger *chg,
					union power_supply_propval *val)
{
	int rc;

	if (!chg->iio.mid_chan)
		return -ENODATA;

	rc = iio_read_channel_processed(chg->iio.mid_chan, &val->intval);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read MID channel rc=%d\n", rc);
		return rc;
	}

	/*
	 * If MID voltage < 1V, it is unreliable.
	 * Figure out voltage from registers and calculations.
	 */
	if (val->intval < 1000000)
		return smblib_estimate_adaptor_voltage(chg, val);

	return 0;
}

	if (chg->iio.usbin_v_chan) {
		rc = iio_read_channel_processed(chg->iio.usbin_v_chan,
				&val->intval);
		if (rc < 0)
			ret = -ENODATA;
	} else {
		ret = -ENODATA;
static int smblib_read_usbin_voltage_chan(struct smb_charger *chg,
				     union power_supply_propval *val)
{
	int rc;

	if (!chg->iio.usbin_v_chan)
		return -ENODATA;

	rc = iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read USBIN channel rc=%d\n", rc);
		return rc;
	}

	return 0;
}

	/*  restore 12V OV to 13.2V */
	if (chg->smb_version == PM8150B_SUBTYPE) {
		rc = smblib_masked_write(chg, USB_ENG_SSUPPLY_USB2_REG,
				ENG_SSUPPLY_12V_OV_OPT_BIT, 0);
int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
				    union power_supply_propval *val)
{
	union power_supply_propval pval = {0, };
	int rc;

	rc = smblib_get_prop_usb_present(chg, &pval);
	if (rc < 0) {
			smblib_err(chg, "Couldn't restore USB_ENG_SSUPPLY_USB2_REG rc=%d\n",
					rc);
			ret = -ENODATA;
		smblib_err(chg, "Couldn't get usb presence status rc=%d\n", rc);
		return -ENODATA;
	}

	/* usb not present */
	if (!pval.intval) {
		val->intval = 0;
		return 0;
	}

	return ret;
	/*
	 * For PM8150B, use MID_CHG ADC channel because overvoltage is observed
	 * to occur randomly in the USBIN channel, particularly at high
	 * voltages.
	 */
	if (chg->smb_version == PM8150B_SUBTYPE)
		return smblib_read_mid_voltage_chan(chg, val);
	else
		return smblib_read_usbin_voltage_chan(chg, val);
}

bool smblib_rsbux_low(struct smb_charger *chg, int r_thr)
@@ -3039,7 +3115,6 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg,
	return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
}

#define HVDCP3_STEP_UV	200000
int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
						union power_supply_propval *val)
{
+1 −0
Original line number Diff line number Diff line
@@ -290,6 +290,7 @@ struct smb_iio {
	struct iio_channel	*temp_chan;
	struct iio_channel	*usbin_i_chan;
	struct iio_channel	*usbin_v_chan;
	struct iio_channel	*mid_chan;
	struct iio_channel	*batt_i_chan;
	struct iio_channel	*connector_temp_chan;
	struct iio_channel	*sbux_chan;