From 925efba5793d5ab0aca4b0e5f1378f50d228d191 Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Thu, 27 Feb 2025 09:45:50 +0000 Subject: [PATCH] power: regulator: add qcom-usb-vbus Add regulator driver that allow some Qualcomm PMIC to feed VBUS output to peripherals that are connected. Signed-off-by: Rui Miguel Silva Acked-by: Caleb Connolly Reviewed-by: Neil Armstrong Reviewed-by: Caleb Connolly Link: https://lore.kernel.org/r/20250227094911.497219-3-rui.silva@linaro.org Signed-off-by: Caleb Connolly --- 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 8f102a92c23..bab68317cfa 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 4382d4b3ab9..054a93e129a 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 00000000000..2d58ef5e111 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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), +}; -- 2.39.5