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

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

Merge "power: qpnp-smbcharger: support external boost for OTG"

parents 8d8d53ff 7146f53c
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -88,6 +88,19 @@ Sub node required properties:
			 - power-ok:		Triggers when the charger
						switcher turns on or off.

Regulator Subnodes:
- qcom,smbcharger-boost-otg	A subnode for a regulator device that turns on
				the charger boost for OTG operation.
- qcom,smbcharger-external-otg	A subnode for a regulator device that switches
				off charging and the USB input charge path
				in order to allow an external regulator to
				operate. This can be used in place of the
				qcom,smbcharger-boost-otg if an external boost
				is available.

Regulator Sub node required properties:
- regulator-name		A name string for the regulator in question

Optional Properties:
- qcom,battery-psy-name		The name of the main battery power supply that
				the charger will register. Failing to define
@@ -154,8 +167,8 @@ Optional Properties:
				50, 100, 150, 200, 250, 300, 500, 600.
- qcom,iterm-disabled		Disables the termination current feature. This
				is a boolean property.
- regulator-name		A string used as a descriptive name for OTG
				regulator.
- otg-parent-supply		A phandle to an external boost regulator for
				OTG if it exists.
- qcom,thermal-mitigation:	Array of input current limit values for
				different system thermal mitigation levels.
				This should be a flat array that denotates the
+1 −2
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@
			qcom,vadc-meas-int-mode;
		};

		pmi8994_charger: pmi8994_otg_supply: qcom,qpnp-smbcharger {
		pmi8994_charger: qcom,qpnp-smbcharger {
			spmi-dev-container;
			compatible = "qcom,qpnp-smbcharger";
			#address-cells = <1>;
@@ -186,7 +186,6 @@
			qcom,parallel-usb-min-current-ma = <1400>;
			qcom,parallel-9v-usb-min-current-ma = <900>;
			qcom,parallel-allowed-lowering-ma = <500>;
			regulator-name = "pmi8994_otg_vreg";

			qcom,chgr@1000 {
				reg = <0x1000 0x100>;
+19 −0
Original line number Diff line number Diff line
@@ -769,4 +769,23 @@
		enable-active-high;
		gpio = <&pm8994_gpios 9 0>;
	};

	usb_otg_switch: usb-otg-switch {
		compatible = "regulator-fixed";
		regulator-name = "usb_otg_vreg";
		vin-supply = <&smbcharger_external_otg>;
		enable-active-high;
		gpio = <&pmi8994_gpios 5 0>;
	};
};

&pmi8994_charger {
	otg-parent-supply = <&pmi8994_boost_5v>;
	smbcharger_charger_otg: qcom,smbcharger-boost-otg {
		regulator-name = "smbcharger_charger_otg";
	};

	smbcharger_external_otg: qcom,smbcharger-external-otg {
		regulator-name = "smbcharger_external_otg";
	};
};
+1 −1
Original line number Diff line number Diff line
@@ -1329,7 +1329,7 @@
		interrupt-names = "hs_phy_irq", "pwr_event_irq", "pmic_id_irq";

		USB3_GDSC-supply = <&gdsc_usb30>;
		vbus_dwc3-supply = <&pmi8994_otg_supply>;
		vbus_dwc3-supply = <&smbcharger_charger_otg>;
		qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <8192>;
		qcom,otg-capability;
+169 −2
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ struct smbchg_chip {
	int				prechg_safety_time;
	int				bmd_pin_src;
	int				resume_soc_threshold;
	bool				use_vfloat_adjustments;
	bool				iterm_disabled;
	bool				bmd_algo_disabled;
	bool				soft_vfloat_comp_disabled;
@@ -91,6 +92,7 @@ struct smbchg_chip {
	bool				low_icl_wa_on;
	bool				battery_unknown;
	bool				charge_unknown_battery;
	u8				original_usbin_allowance;
	struct parallel_usb_cfg		parallel;

	/* flash current prediction */
@@ -153,6 +155,7 @@ struct smbchg_chip {
	bool				psy_registered;

	struct smbchg_regulator		otg_vreg;
	struct smbchg_regulator		ext_otg_vreg;
	struct work_struct		usb_set_online_work;
	spinlock_t			sec_access_lock;
	struct mutex			current_change_lock;
@@ -827,6 +830,11 @@ enum enable_reason {
	 * temperature levels rise
	 */
	REASON_THERMAL = BIT(4),
	/*
	 * an external OTG supply is being used, suspend charge path so the
	 * charger does not accidentally try to charge from the external supply.
	 */
	REASON_OTG = BIT(5),
};

static struct power_supply *get_parallel_psy(struct smbchg_chip *chip)
@@ -857,6 +865,18 @@ static void smbchg_usb_update_online_work(struct work_struct *work)
	mutex_unlock(&chip->usb_set_online_lock);
}

static bool smbchg_primary_usb_is_en(struct smbchg_chip *chip,
		enum enable_reason reason)
{
	bool enabled;

	mutex_lock(&chip->usb_en_lock);
	enabled = (chip->usb_suspended & reason) == 0;
	mutex_unlock(&chip->usb_en_lock);

	return enabled;
}

static int smbchg_primary_usb_en(struct smbchg_chip *chip, bool enable,
		enum enable_reason reason, bool *changed)
{
@@ -1991,13 +2011,114 @@ struct regulator_ops smbchg_otg_reg_ops = {
	.is_enabled	= smbchg_otg_regulator_is_enable,
};

#define USBIN_CHGR_CFG			0xF1
#define USBIN_ADAPTER_9V		0x3
#define HVDCP_EN_BIT			BIT(3)
static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev)
{
	bool changed;
	int rc = 0;
	struct smbchg_chip *chip = rdev_get_drvdata(rdev);

	rc = smbchg_primary_usb_en(chip, false, REASON_OTG, &changed);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't suspend charger rc=%d\n", rc);
		return rc;
	}

	rc = smbchg_read(chip, &chip->original_usbin_allowance,
			chip->usb_chgpth_base + USBIN_CHGR_CFG, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't read usb allowance rc=%d\n", rc);
		return rc;
	}

	/*
	 * To disallow source detect and usbin_uv interrupts, set the adapter
	 * allowance to 9V, so that the audio boost operating in reverse never
	 * gets detected as a valid input
	 */
	rc = smbchg_sec_masked_write(chip,
				chip->usb_chgpth_base + CHGPTH_CFG,
				HVDCP_EN_BIT, 0);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't disable HVDCP rc=%d\n", rc);
		return rc;
	}

	rc = smbchg_sec_masked_write(chip,
				chip->usb_chgpth_base + USBIN_CHGR_CFG,
				0xFF, USBIN_ADAPTER_9V);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't write usb allowance rc=%d\n", rc);
		return rc;
	}

	pr_smb(PR_STATUS, "Enabling OTG Boost\n");
	return rc;
}

static int smbchg_external_otg_regulator_disable(struct regulator_dev *rdev)
{
	bool changed;
	int rc = 0;
	struct smbchg_chip *chip = rdev_get_drvdata(rdev);

	rc = smbchg_primary_usb_en(chip, true, REASON_OTG, &changed);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't unsuspend charger rc=%d\n", rc);
		return rc;
	}

	/*
	 * Reenable HVDCP and set the adapter allowance back to the original
	 * value in order to allow normal USBs to be recognized as a valid
	 * input.
	 */
	rc = smbchg_sec_masked_write(chip,
				chip->usb_chgpth_base + CHGPTH_CFG,
				HVDCP_EN_BIT, HVDCP_EN_BIT);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't enable HVDCP rc=%d\n", rc);
		return rc;
	}

	rc = smbchg_sec_masked_write(chip,
				chip->usb_chgpth_base + USBIN_CHGR_CFG,
				0xFF, chip->original_usbin_allowance);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't write usb allowance rc=%d\n", rc);
		return rc;
	}

	pr_smb(PR_STATUS, "Disabling OTG Boost\n");
	return rc;
}

static int smbchg_external_otg_regulator_is_enable(struct regulator_dev *rdev)
{
	struct smbchg_chip *chip = rdev_get_drvdata(rdev);

	return !smbchg_primary_usb_is_en(chip, REASON_OTG);
}

struct regulator_ops smbchg_external_otg_reg_ops = {
	.enable		= smbchg_external_otg_regulator_enable,
	.disable	= smbchg_external_otg_regulator_disable,
	.is_enabled	= smbchg_external_otg_regulator_is_enable,
};

static int smbchg_regulator_init(struct smbchg_chip *chip)
{
	int rc = 0;
	struct regulator_init_data *init_data;
	struct regulator_config cfg = {};
	struct device_node *regulator_node;

	regulator_node = of_get_child_by_name(chip->dev->of_node,
			"qcom,smbcharger-boost-otg");

	init_data = of_get_regulator_init_data(chip->dev, chip->dev->of_node);
	init_data = of_get_regulator_init_data(chip->dev, regulator_node);
	if (!init_data) {
		dev_err(chip->dev, "Unable to allocate memory\n");
		return -ENOMEM;
@@ -2012,7 +2133,7 @@ static int smbchg_regulator_init(struct smbchg_chip *chip)
		cfg.dev = chip->dev;
		cfg.init_data = init_data;
		cfg.driver_data = chip;
		cfg.of_node = chip->dev->of_node;
		cfg.of_node = regulator_node;

		init_data->constraints.valid_ops_mask
			|= REGULATOR_CHANGE_STATUS;
@@ -2028,6 +2149,45 @@ static int smbchg_regulator_init(struct smbchg_chip *chip)
		}
	}

	if (rc)
		return rc;

	regulator_node = of_get_child_by_name(chip->dev->of_node,
			"qcom,smbcharger-external-otg");
	init_data = of_get_regulator_init_data(chip->dev, regulator_node);
	if (!init_data) {
		dev_err(chip->dev, "Unable to allocate memory\n");
		return -ENOMEM;
	}

	if (init_data->constraints.name) {
		if (of_get_property(chip->dev->of_node,
					"otg-parent-supply", NULL))
			init_data->supply_regulator = "otg-parent";
		chip->ext_otg_vreg.rdesc.owner = THIS_MODULE;
		chip->ext_otg_vreg.rdesc.type = REGULATOR_VOLTAGE;
		chip->ext_otg_vreg.rdesc.ops = &smbchg_external_otg_reg_ops;
		chip->ext_otg_vreg.rdesc.name = init_data->constraints.name;

		cfg.dev = chip->dev;
		cfg.init_data = init_data;
		cfg.driver_data = chip;
		cfg.of_node = regulator_node;

		init_data->constraints.valid_ops_mask
			|= REGULATOR_CHANGE_STATUS;

		chip->ext_otg_vreg.rdev = regulator_register(
					&chip->ext_otg_vreg.rdesc, &cfg);
		if (IS_ERR(chip->ext_otg_vreg.rdev)) {
			rc = PTR_ERR(chip->ext_otg_vreg.rdev);
			chip->ext_otg_vreg.rdev = NULL;
			if (rc != -EPROBE_DEFER)
				dev_err(chip->dev,
					"external OTG reg failed, rc=%d\n", rc);
		}
	}

	return rc;
}

@@ -2035,6 +2195,8 @@ static void smbchg_regulator_deinit(struct smbchg_chip *chip)
{
	if (chip->otg_vreg.rdev)
		regulator_unregister(chip->otg_vreg.rdev);
	if (chip->ext_otg_vreg.rdev)
		regulator_unregister(chip->ext_otg_vreg.rdev);
}

#define REVISION1_REG			0x0
@@ -2874,6 +3036,11 @@ static int smbchg_hw_init(struct smbchg_chip *chip)
		return rc;
	}

	rc = smbchg_read(chip, &chip->original_usbin_allowance,
			chip->usb_chgpth_base + USBIN_CHGR_CFG, 1);
	if (rc < 0)
		dev_err(chip->dev, "Couldn't read usb allowance rc=%d\n", rc);

	return rc;
}