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

Commit e30c123e authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: phy: qusb: Set the voltage to regulator according to soc capacity"

parents 464112e0 9b3d98de
Loading
Loading
Loading
Loading
+123 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/regulator/machine.h>
#include <linux/usb/phy.h>
#include <linux/reset.h>
#include <linux/power_supply.h>

#define QUSB2PHY_PLL_PWR_CTL		0x18
#define REF_BUF_EN			BIT(0)
@@ -111,6 +112,7 @@
#define QUSB2PHY_3P3_VOL_MAX		3200000 /* uV */
#define QUSB2PHY_3P3_HPM_LOAD		30000	/* uA */

#define SOC_THRESHOLD_LEVEL		45
#define QUSB2PHY_REFCLK_ENABLE		BIT(0)

#define HSTX_TRIMSIZE			4
@@ -153,6 +155,7 @@ struct qusb_phy {
	struct regulator	*vdda33;
	struct regulator	*vdda18;
	int			vdd_levels[3]; /* none, low, high */
	int			vdda33_levels[3]; /* low, min, max */
	int			init_seq_len;
	int			*qusb_phy_init_seq;
	u32			major_rev;
@@ -169,7 +172,10 @@ struct qusb_phy {
	bool			ulpi_mode;
	bool			dpdm_enable;
	bool			is_se_clk;
	bool			low_soc;

	struct notifier_block	psy_nb;
	struct work_struct	soc_eval_work;
	struct regulator_desc	dpdm_rdesc;
	struct regulator_dev	*dpdm_rdev;

@@ -180,6 +186,7 @@ struct qusb_phy {
	bool			vbus_active;
	bool			id_state;
	struct power_supply	*usb_psy;
	struct power_supply	*batt_psy;
	struct delayed_work	port_det_w;
	enum port_state		port_state;
	unsigned int		dcd_timeout;
@@ -265,6 +272,34 @@ static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high)
	return ret;
}

static int qusb_read_battery_soc(struct qusb_phy *qphy, int *soc_val)
{
	union power_supply_propval val = {0,};
	int ret = 0;

	if (!qphy->batt_psy) {
		qphy->batt_psy = power_supply_get_by_name("battery");
		if (!qphy->batt_psy) {
			dev_err(qphy->phy.dev, "Could not get battery psy\n");
			return -ENODEV;
		}
	}

	if (qphy->batt_psy) {
		ret = power_supply_get_property(qphy->batt_psy,
				POWER_SUPPLY_PROP_CAPACITY, &val);
		if (ret) {
			dev_err(qphy->phy.dev,
					"battery SoC read error\n");
			return ret;
		}
	*soc_val = val.intval;
	}

	dev_dbg(qphy->phy.dev, "soc:%d\n", *soc_val);
	return ret;
}

static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
{
	int ret = 0;
@@ -314,8 +349,9 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
		goto disable_vdda18;
	}

	ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN,
						QUSB2PHY_3P3_VOL_MAX);
	ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[1],
						qphy->vdda33_levels[2]);

	if (ret) {
		dev_err(qphy->phy.dev,
				"Unable to set voltage for vdda33:%d\n", ret);
@@ -628,6 +664,57 @@ static int qusb_phy_init(struct usb_phy *phy)
	return 0;
}

static int qusb_phy_battery_supply_cb(struct notifier_block *nb,
					unsigned long event, void *data)
{
	struct qusb_phy *qphy = container_of(nb, struct qusb_phy, psy_nb);
	int soc_val = 0;

	if (event != PSY_EVENT_PROP_CHANGED)
		return NOTIFY_OK;

	if (qusb_read_battery_soc(qphy, &soc_val) < 0) {
		dev_err(qphy->phy.dev, "%s unable to read battery SoC\n",
				__func__);
		return NOTIFY_OK;
	}

	if (soc_val < SOC_THRESHOLD_LEVEL && !qphy->low_soc) {
		/* Reduce voltage to be set to 2.9V for low SoC */
		qphy->vdda33_levels[1] = qphy->vdda33_levels[0];
		qphy->vdda33_levels[2] = qphy->vdda33_levels[0];
		qphy->low_soc = true;
		queue_work(system_freezable_wq, &qphy->soc_eval_work);
		return NOTIFY_OK;
	}

	if (soc_val > SOC_THRESHOLD_LEVEL && qphy->low_soc) {
		/* Reset voltage to be set to default for normal SoC */
		qphy->vdda33_levels[1] = QUSB2PHY_3P3_VOL_MIN;
		qphy->vdda33_levels[2] = QUSB2PHY_3P3_VOL_MAX;
		qphy->low_soc = false;
		queue_work(system_freezable_wq, &qphy->soc_eval_work);
	}
	return NOTIFY_OK;
}

static void qusb_phy_evaluate_soc(struct work_struct *work)
{
	struct qusb_phy *qphy =
			container_of(work, struct qusb_phy, soc_eval_work);
	int ret = 0;

	dev_dbg(qphy->phy.dev, "%s setting min voltage for vdda33 as %d\n",
				__func__, qphy->vdda33_levels[1]);
	ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[1],
						  qphy->vdda33_levels[2]);
	if (ret) {
		dev_err(qphy->phy.dev,
			"%s unable to set voltage for vdda33, ret = %d\n",
			__func__, ret);
	}
}

static void qusb_phy_shutdown(struct usb_phy *phy)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -1796,9 +1883,30 @@ static int qusb_phy_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	qphy->vdda33_levels[1] = QUSB2PHY_3P3_VOL_MIN;
	qphy->vdda33_levels[2] = QUSB2PHY_3P3_VOL_MAX;
	ret = of_property_read_u32(dev->of_node,
			"qcom,vdda33-voltage-level",
			(u32 *)&qphy->vdda33_levels[0]);
	if (!ret) {
		INIT_WORK(&qphy->soc_eval_work, qusb_phy_evaluate_soc);
		/* Register notifier to change gain based on state of charge */
		qphy->psy_nb.notifier_call = qusb_phy_battery_supply_cb;
		ret = power_supply_reg_notifier(&qphy->psy_nb);
		if (ret) {
			dev_dbg(qphy->phy.dev,
					"%s: could not register pwr supply notifier\n",
					__func__);
			goto remove_phy;
		}
		qphy->low_soc = false;
		qusb_phy_battery_supply_cb(&qphy->psy_nb,
				PSY_EVENT_PROP_CHANGED, NULL);
	}

	ret = qusb_phy_regulator_init(qphy);
	if (ret)
		usb_remove_phy(&qphy->phy);
		goto unreg_notifier_and_put_batt_psy;

	/* de-assert clamp dig n to reduce leakage on 1p8 upon boot up */
	qusb_phy_clear_tcsr_clamp(qphy, true);
@@ -1838,7 +1946,14 @@ static int qusb_phy_probe(struct platform_device *pdev)
	}

	qusb_phy_create_debugfs(qphy);
	return 0;

unreg_notifier_and_put_batt_psy:
	power_supply_unreg_notifier(&qphy->psy_nb);
	if (qphy->batt_psy)
		power_supply_put(qphy->batt_psy);
remove_phy:
	usb_remove_phy(&qphy->phy);
	return ret;
}

@@ -1846,6 +1961,11 @@ static int qusb_phy_remove(struct platform_device *pdev)
{
	struct qusb_phy *qphy = platform_get_drvdata(pdev);

	power_supply_unreg_notifier(&qphy->psy_nb);
	if (qphy->batt_psy)
		power_supply_put(qphy->batt_psy);
	if (qphy->usb_psy)
		power_supply_put(qphy->usb_psy);
	debugfs_remove_recursive(qphy->root);
	usb_remove_phy(&qphy->phy);
	qphy->cable_connected = false;