Loading drivers/usb/phy/phy-msm-qusb.c +112 −14 Original line number Diff line number Diff line /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -57,6 +57,14 @@ #define PORT_OFFSET(i) ((i == 0) ? 0x0 : ((i == 1) ? 0x6c : 0x88)) #define HS_PHY_CTRL_REG(i) (0x10 + PORT_OFFSET(i)) #define QUSB2PHY_1P8_VOL_MIN 1800000 /* uV */ #define QUSB2PHY_1P8_VOL_MAX 1800000 /* uV */ #define QUSB2PHY_1P8_HPM_LOAD 30000 /* uA */ #define QUSB2PHY_3P3_VOL_MIN 3075000 /* uV */ #define QUSB2PHY_3P3_VOL_MAX 3200000 /* uV */ #define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */ struct qusb_phy { struct usb_phy phy; void __iomem *base; Loading Loading @@ -93,49 +101,139 @@ static int qusb_phy_reset(struct usb_phy *phy) return 0; } static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high) { int min, ret; min = high ? 1 : 0; /* low or none? */ ret = regulator_set_voltage(qphy->vdd, qphy->vdd_levels[min], qphy->vdd_levels[2]); if (ret) { dev_err(qphy->phy.dev, "unable to set voltage for qusb vdd\n"); return ret; } dev_dbg(qphy->phy.dev, "min_vol:%d max_vol:%d\n", qphy->vdd_levels[min], qphy->vdd_levels[2]); return ret; } static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on) { int ret = 0; dev_dbg(qphy->phy.dev, "%s turn %s regulators\n", __func__, on ? "on" : "off"); dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n", __func__, on ? "on" : "off", qphy->power_enabled); if (qphy->power_enabled == on) if (qphy->power_enabled == on) { dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n"); return 0; } if (!on) goto disable_vdda33; ret = qusb_phy_config_vdd(qphy, true); if (ret) { dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", ret); goto err_vdd; } ret = regulator_enable(qphy->vdd); if (ret) { dev_err(qphy->phy.dev, "unable to enable vdd\n"); return ret; dev_err(qphy->phy.dev, "Unable to enable VDD\n"); goto unconfig_vdd; } ret = regulator_set_optimum_mode(qphy->vdda18, QUSB2PHY_1P8_HPM_LOAD); if (ret < 0) { dev_err(qphy->phy.dev, "Unable to set HPM of vdda18:%d\n", ret); goto disable_vdd; } ret = regulator_set_voltage(qphy->vdda18, QUSB2PHY_1P8_VOL_MIN, QUSB2PHY_1P8_VOL_MAX); if (ret) { dev_err(qphy->phy.dev, "Unable to set voltage for vdda18:%d\n", ret); goto put_vdda18_lpm; } ret = regulator_enable(qphy->vdda18); if (ret) { dev_err(qphy->phy.dev, "unable to enable vdda18\n"); goto disable_vdd; dev_err(qphy->phy.dev, "Unable to enable vdda18:%d\n", ret); goto unset_vdda18; } ret = regulator_set_optimum_mode(qphy->vdda33, QUSB2PHY_3P3_HPM_LOAD); if (ret < 0) { dev_err(qphy->phy.dev, "Unable to set HPM of vdda33:%d\n", ret); goto disable_vdda18; } ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN, QUSB2PHY_3P3_VOL_MAX); if (ret) { dev_err(qphy->phy.dev, "Unable to set voltage for vdda33:%d\n", ret); goto put_vdda33_lpm; } ret = regulator_enable(qphy->vdda33); if (ret) { dev_err(qphy->phy.dev, "unable to enable vdda33\n"); goto disable_vdda18; dev_err(qphy->phy.dev, "Unable to enable vdda33:%d\n", ret); goto unset_vdd33; } qphy->power_enabled = true; pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__); return 0; disable_vdda33: regulator_disable(qphy->vdda33); ret = regulator_disable(qphy->vdda33); if (ret) dev_err(qphy->phy.dev, "Unable to disable vdda33:%d\n", ret); unset_vdd33: ret = regulator_set_voltage(qphy->vdda33, 0, QUSB2PHY_3P3_VOL_MAX); if (ret) dev_err(qphy->phy.dev, "Unable to set (0) voltage for vdda33:%d\n", ret); put_vdda33_lpm: ret = regulator_set_optimum_mode(qphy->vdda33, 0); if (ret < 0) dev_err(qphy->phy.dev, "Unable to set (0) HPM of vdda33\n"); disable_vdda18: regulator_disable(qphy->vdda18); ret = regulator_disable(qphy->vdda18); if (ret) dev_err(qphy->phy.dev, "Unable to disable vdda18:%d\n", ret); unset_vdda18: ret = regulator_set_voltage(qphy->vdda18, 0, QUSB2PHY_1P8_VOL_MAX); if (ret) dev_err(qphy->phy.dev, "Unable to set (0) voltage for vdda18:%d\n", ret); put_vdda18_lpm: ret = regulator_set_optimum_mode(qphy->vdda18, 0); if (ret < 0) dev_err(qphy->phy.dev, "Unable to set LPM of vdda18\n"); disable_vdd: regulator_disable(qphy->vdd); ret = regulator_disable(qphy->vdd); if (ret) dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", ret); unconfig_vdd: ret = qusb_phy_config_vdd(qphy, false); if (ret) dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", ret); err_vdd: qphy->power_enabled = false; dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n"); return ret; } Loading Loading
drivers/usb/phy/phy-msm-qusb.c +112 −14 Original line number Diff line number Diff line /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -57,6 +57,14 @@ #define PORT_OFFSET(i) ((i == 0) ? 0x0 : ((i == 1) ? 0x6c : 0x88)) #define HS_PHY_CTRL_REG(i) (0x10 + PORT_OFFSET(i)) #define QUSB2PHY_1P8_VOL_MIN 1800000 /* uV */ #define QUSB2PHY_1P8_VOL_MAX 1800000 /* uV */ #define QUSB2PHY_1P8_HPM_LOAD 30000 /* uA */ #define QUSB2PHY_3P3_VOL_MIN 3075000 /* uV */ #define QUSB2PHY_3P3_VOL_MAX 3200000 /* uV */ #define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */ struct qusb_phy { struct usb_phy phy; void __iomem *base; Loading Loading @@ -93,49 +101,139 @@ static int qusb_phy_reset(struct usb_phy *phy) return 0; } static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high) { int min, ret; min = high ? 1 : 0; /* low or none? */ ret = regulator_set_voltage(qphy->vdd, qphy->vdd_levels[min], qphy->vdd_levels[2]); if (ret) { dev_err(qphy->phy.dev, "unable to set voltage for qusb vdd\n"); return ret; } dev_dbg(qphy->phy.dev, "min_vol:%d max_vol:%d\n", qphy->vdd_levels[min], qphy->vdd_levels[2]); return ret; } static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on) { int ret = 0; dev_dbg(qphy->phy.dev, "%s turn %s regulators\n", __func__, on ? "on" : "off"); dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n", __func__, on ? "on" : "off", qphy->power_enabled); if (qphy->power_enabled == on) if (qphy->power_enabled == on) { dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n"); return 0; } if (!on) goto disable_vdda33; ret = qusb_phy_config_vdd(qphy, true); if (ret) { dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", ret); goto err_vdd; } ret = regulator_enable(qphy->vdd); if (ret) { dev_err(qphy->phy.dev, "unable to enable vdd\n"); return ret; dev_err(qphy->phy.dev, "Unable to enable VDD\n"); goto unconfig_vdd; } ret = regulator_set_optimum_mode(qphy->vdda18, QUSB2PHY_1P8_HPM_LOAD); if (ret < 0) { dev_err(qphy->phy.dev, "Unable to set HPM of vdda18:%d\n", ret); goto disable_vdd; } ret = regulator_set_voltage(qphy->vdda18, QUSB2PHY_1P8_VOL_MIN, QUSB2PHY_1P8_VOL_MAX); if (ret) { dev_err(qphy->phy.dev, "Unable to set voltage for vdda18:%d\n", ret); goto put_vdda18_lpm; } ret = regulator_enable(qphy->vdda18); if (ret) { dev_err(qphy->phy.dev, "unable to enable vdda18\n"); goto disable_vdd; dev_err(qphy->phy.dev, "Unable to enable vdda18:%d\n", ret); goto unset_vdda18; } ret = regulator_set_optimum_mode(qphy->vdda33, QUSB2PHY_3P3_HPM_LOAD); if (ret < 0) { dev_err(qphy->phy.dev, "Unable to set HPM of vdda33:%d\n", ret); goto disable_vdda18; } ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN, QUSB2PHY_3P3_VOL_MAX); if (ret) { dev_err(qphy->phy.dev, "Unable to set voltage for vdda33:%d\n", ret); goto put_vdda33_lpm; } ret = regulator_enable(qphy->vdda33); if (ret) { dev_err(qphy->phy.dev, "unable to enable vdda33\n"); goto disable_vdda18; dev_err(qphy->phy.dev, "Unable to enable vdda33:%d\n", ret); goto unset_vdd33; } qphy->power_enabled = true; pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__); return 0; disable_vdda33: regulator_disable(qphy->vdda33); ret = regulator_disable(qphy->vdda33); if (ret) dev_err(qphy->phy.dev, "Unable to disable vdda33:%d\n", ret); unset_vdd33: ret = regulator_set_voltage(qphy->vdda33, 0, QUSB2PHY_3P3_VOL_MAX); if (ret) dev_err(qphy->phy.dev, "Unable to set (0) voltage for vdda33:%d\n", ret); put_vdda33_lpm: ret = regulator_set_optimum_mode(qphy->vdda33, 0); if (ret < 0) dev_err(qphy->phy.dev, "Unable to set (0) HPM of vdda33\n"); disable_vdda18: regulator_disable(qphy->vdda18); ret = regulator_disable(qphy->vdda18); if (ret) dev_err(qphy->phy.dev, "Unable to disable vdda18:%d\n", ret); unset_vdda18: ret = regulator_set_voltage(qphy->vdda18, 0, QUSB2PHY_1P8_VOL_MAX); if (ret) dev_err(qphy->phy.dev, "Unable to set (0) voltage for vdda18:%d\n", ret); put_vdda18_lpm: ret = regulator_set_optimum_mode(qphy->vdda18, 0); if (ret < 0) dev_err(qphy->phy.dev, "Unable to set LPM of vdda18\n"); disable_vdd: regulator_disable(qphy->vdd); ret = regulator_disable(qphy->vdd); if (ret) dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", ret); unconfig_vdd: ret = qusb_phy_config_vdd(qphy, false); if (ret) dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", ret); err_vdd: qphy->power_enabled = false; dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n"); return ret; } Loading