Message ID | 20250227094911.497219-3-rui.silva@linaro.org |
---|---|
State | New |
Headers | show |
Series | power: regulator: add qcom usb vbus | expand |
On 27/02/2025 10:45, Rui Miguel Silva wrote: > Add regulator driver that allow some Qualcomm PMIC to > feed VBUS output to peripherals that are connected. > > Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org> > --- > drivers/power/regulator/Kconfig | 7 ++ > drivers/power/regulator/Makefile | 1 + > .../power/regulator/qcom_usb_vbus_regulator.c | 111 ++++++++++++++++++ > 3 files changed, 119 insertions(+) > create mode 100644 drivers/power/regulator/qcom_usb_vbus_regulator.c > > diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig > index 958f337c7e73..558133e09bf8 100644 > --- a/drivers/power/regulator/Kconfig > +++ b/drivers/power/regulator/Kconfig > @@ -224,6 +224,13 @@ config DM_REGULATOR_QCOM_RPMH > implements get/set api for a limited set of regulators used > by u-boot. > > +config DM_REGULATOR_QCOM_USB_VBUS > + bool "Enable driver model for Qualcomm USB vbus regulator" > + depends on DM_REGULATOR > + ---help--- > + Enable support for the Qualcomm USB Vbus regulator. The driver > + implements get/set api for the regulator to be used by u-boot. > + > config SPL_DM_REGULATOR_GPIO > bool "Enable Driver Model for GPIO REGULATOR in SPL" > depends on DM_REGULATOR_GPIO && SPL_GPIO > diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile > index ca6c89d13b5c..a4191b9302b1 100644 > --- a/drivers/power/regulator/Makefile > +++ b/drivers/power/regulator/Makefile > @@ -22,6 +22,7 @@ obj-$(CONFIG_$(XPL_)DM_REGULATOR_COMMON) += regulator_common.o > obj-$(CONFIG_$(XPL_)DM_REGULATOR_FIXED) += fixed.o > obj-$(CONFIG_$(XPL_)DM_REGULATOR_GPIO) += gpio-regulator.o > obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o > +obj-$(CONFIG_DM_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus_regulator.o > obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o > obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o > obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o > diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c > new file mode 100644 > index 000000000000..2d58ef5e111e > --- /dev/null > +++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c > @@ -0,0 +1,111 @@ > +// SPDX-License-Identifier: BSD-3-Clause > +/* > + * Copyright (c) 2025, Linaro Limited > + */ > +#define pr_fmt(fmt) "qcom_usb_vbus: " fmt > + > +#include <bitfield.h> > +#include <errno.h> > +#include <dm.h> > +#include <fdtdec.h> > +#include <log.h> > +#include <asm/gpio.h> > +#include <linux/bitops.h> > +#include <linux/printk.h> > +#include <power/pmic.h> > +#include <power/regulator.h> > + > +#define CMD_OTG 0x50 > +#define OTG_EN BIT(0) > +// The 0 bit in this register's bit field is undocumented > +#define OTG_CFG 0x56 > +#define OTG_EN_SRC_CFG BIT(1) > + > +struct qcom_usb_vbus_priv { > + phys_addr_t base; > +}; > + > +static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev) > +{ > + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); > + > + priv->base = dev_read_addr(dev); > + if (priv->base == FDT_ADDR_T_NONE) > + return -EINVAL; > + > + return 0; > +} > + > +static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev) > +{ > + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); > + int otg_en_reg = priv->base + CMD_OTG; > + int ret; > + > + ret = pmic_reg_read(dev->parent, otg_en_reg); > + if (ret < 0) > + log_err("failed to read usb vbus: %d\n", ret); > + else > + ret &= OTG_EN; > + > + return ret; > +} > + > +static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable) > +{ > + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); > + int otg_en_reg = priv->base + CMD_OTG; > + int ret; > + > + if (enable) { > + ret = pmic_clrsetbits(dev->parent, otg_en_reg, 0, OTG_EN); > + if (ret < 0) { > + log_err("error enabling: %d\n", ret); > + return ret; > + } > + } else { > + ret = pmic_clrsetbits(dev->parent, otg_en_reg, OTG_EN, 0); > + if (ret < 0) { > + log_err("error disabling: %d\n", ret); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int qcom_usb_vbus_regulator_probe(struct udevice *dev) > +{ > + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); > + int otg_cfg_reg = priv->base + OTG_CFG; > + int ret; > + > + /* Disable HW logic for VBUS enable */ > + ret = pmic_clrsetbits(dev->parent, otg_cfg_reg, OTG_EN_SRC_CFG, 0); > + if (ret < 0) { > + log_err("error setting EN_SRC_CFG: %d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static const struct dm_regulator_ops qcom_usb_vbus_regulator_ops = { > + .get_enable = qcom_usb_vbus_regulator_get_enable, > + .set_enable = qcom_usb_vbus_regulator_set_enable, > +}; > + > +static const struct udevice_id qcom_usb_vbus_regulator_ids[] = { > + { .compatible = "qcom,pm8150b-vbus-reg"}, > + { }, > +}; > + > +U_BOOT_DRIVER(qcom_usb_vbus_regulator) = { > + .name = "qcom-usb-vbus-regulator", > + .id = UCLASS_REGULATOR, > + .of_match = qcom_usb_vbus_regulator_ids, > + .of_to_plat = qcom_usb_vbus_regulator_of_to_plat, > + .ops = &qcom_usb_vbus_regulator_ops, > + .probe = qcom_usb_vbus_regulator_probe, > + .priv_auto = sizeof(struct qcom_usb_vbus_priv), > +}; Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 958f337c7e73..558133e09bf8 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -224,6 +224,13 @@ config DM_REGULATOR_QCOM_RPMH implements get/set api for a limited set of regulators used by u-boot. +config DM_REGULATOR_QCOM_USB_VBUS + bool "Enable driver model for Qualcomm USB vbus regulator" + depends on DM_REGULATOR + ---help--- + Enable support for the Qualcomm USB Vbus regulator. The driver + implements get/set api for the regulator to be used by u-boot. + config SPL_DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR in SPL" depends on DM_REGULATOR_GPIO && SPL_GPIO diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index ca6c89d13b5c..a4191b9302b1 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_$(XPL_)DM_REGULATOR_COMMON) += regulator_common.o obj-$(CONFIG_$(XPL_)DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_$(XPL_)DM_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o +obj-$(CONFIG_DM_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus_regulator.o obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c new file mode 100644 index 000000000000..2d58ef5e111e --- /dev/null +++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2025, Linaro Limited + */ +#define pr_fmt(fmt) "qcom_usb_vbus: " fmt + +#include <bitfield.h> +#include <errno.h> +#include <dm.h> +#include <fdtdec.h> +#include <log.h> +#include <asm/gpio.h> +#include <linux/bitops.h> +#include <linux/printk.h> +#include <power/pmic.h> +#include <power/regulator.h> + +#define CMD_OTG 0x50 +#define OTG_EN BIT(0) +// The 0 bit in this register's bit field is undocumented +#define OTG_CFG 0x56 +#define OTG_EN_SRC_CFG BIT(1) + +struct qcom_usb_vbus_priv { + phys_addr_t base; +}; + +static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev) +{ + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev) +{ + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); + int otg_en_reg = priv->base + CMD_OTG; + int ret; + + ret = pmic_reg_read(dev->parent, otg_en_reg); + if (ret < 0) + log_err("failed to read usb vbus: %d\n", ret); + else + ret &= OTG_EN; + + return ret; +} + +static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable) +{ + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); + int otg_en_reg = priv->base + CMD_OTG; + int ret; + + if (enable) { + ret = pmic_clrsetbits(dev->parent, otg_en_reg, 0, OTG_EN); + if (ret < 0) { + log_err("error enabling: %d\n", ret); + return ret; + } + } else { + ret = pmic_clrsetbits(dev->parent, otg_en_reg, OTG_EN, 0); + if (ret < 0) { + log_err("error disabling: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int qcom_usb_vbus_regulator_probe(struct udevice *dev) +{ + struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); + int otg_cfg_reg = priv->base + OTG_CFG; + int ret; + + /* Disable HW logic for VBUS enable */ + ret = pmic_clrsetbits(dev->parent, otg_cfg_reg, OTG_EN_SRC_CFG, 0); + if (ret < 0) { + log_err("error setting EN_SRC_CFG: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct dm_regulator_ops qcom_usb_vbus_regulator_ops = { + .get_enable = qcom_usb_vbus_regulator_get_enable, + .set_enable = qcom_usb_vbus_regulator_set_enable, +}; + +static const struct udevice_id qcom_usb_vbus_regulator_ids[] = { + { .compatible = "qcom,pm8150b-vbus-reg"}, + { }, +}; + +U_BOOT_DRIVER(qcom_usb_vbus_regulator) = { + .name = "qcom-usb-vbus-regulator", + .id = UCLASS_REGULATOR, + .of_match = qcom_usb_vbus_regulator_ids, + .of_to_plat = qcom_usb_vbus_regulator_of_to_plat, + .ops = &qcom_usb_vbus_regulator_ops, + .probe = qcom_usb_vbus_regulator_probe, + .priv_auto = sizeof(struct qcom_usb_vbus_priv), +};
Add regulator driver that allow some Qualcomm PMIC to feed VBUS output to peripherals that are connected. Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org> --- drivers/power/regulator/Kconfig | 7 ++ drivers/power/regulator/Makefile | 1 + .../power/regulator/qcom_usb_vbus_regulator.c | 111 ++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 drivers/power/regulator/qcom_usb_vbus_regulator.c