Merge "usb: phy: qusb: Set the voltage to regulator according to soc capacity"
This commit is contained in:
commit
e30c123efa
1 changed files with 123 additions and 3 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue