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

This commit is contained in:
qctecmdr 2020-09-22 01:33:13 -07:00 committed by Gerrit - the friendly Code Review server
commit e30c123efa

View file

@ -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;