From 5ea3e3e37ec14a1d90a6764879c38d80f4ffe008 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Thu, 26 Aug 2021 22:11:37 -0500
Subject: [PATCH 45/68] phy: sun4i-usb: Control supplies via the regulator
 uclass

The device tree binding for the PHY provides VBUS supplies as regulator
references. Now that all boards have the appropriate regulator uclass
drivers enabled, the PHY driver can switch to using them. This replaces
direct GPIO usage, which in some cases needed a special DM-incompatible
"virtual" GPIO from the PMIC.

The following boards provided a value for CONFIG_USB0_VBUS_PIN, but are
missing the "usb0_vbus-supply" property in their device tree. None of
them have the MUSB controller enabled in host or OTG mode, so they
should see no impact:
 - Ainol_AW1_defconfig / sun7i-a20-ainol-aw1
 - Ampe_A76_defconfig / sun5i-a13-ampe-a76
 - CHIP_pro_defconfig / sun5i-gr8-chip-pro
 - Cubieboard4_defconfig / sun9i-a80-cubieboard4
 - Merrii_A80_Optimus_defconfig / sun9i-a80-optimus
 - Sunchip_CX-A99_defconfig / sun9i-a80-cx-a99
 - Yones_Toptech_BD1078_defconfig / sun7i-a20-yones-toptech-bd1078
 - Yones_Toptech_BS1078_V2_defconfig /
   sun6i-a31s-yones-toptech-bs1078-v2
 - iNet_3F_defconfig / sun4i-a10-inet-3f
 - iNet_3W_defconfig / sun4i-a10-inet-3w
 - iNet_86VS_defconfig / sun5i-a13-inet-86vs
 - iNet_D978_rev2_defconfig / sun8i-a33-inet-d978-rev2
 - icnova-a20-swac_defconfig / sun7i-a20-icnova-swac
 - sun8i_a23_evb_defconfig / sun8i-a23-evb

Similarly, the following boards set CONFIG_USB1_VBUS_PIN, but do not
have "usb1_vbus-supply" in their device tree. Neither of them have USB
enabled at all, so again there should be no impact:
 - Cubieboard4_defconfig / sun9i-a80-cubieboard4 (also for USB3)
 - sun8i_a23_evb_defconfig / sun8i-a23-evb

The following boards use a different pin for USB1 VBUS between their
defconfig and their device tree. Depending on which is correct, they
may be broken:
 - Linksprite_pcDuino3_Nano_defconfig (PH11) /
   sun7i-a20-pcduino3-nano (PD2)
 - icnova-a20-swac_defconfig (PG10) / sun7i-a20-icnova-swac (PH6)

Finally, this board has conflicting pins given for its USB2 VBUS:
 - Lamobo_R1_defconfig (PH3) / sun7i-a20-lamobo-r1 (PH12)

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 drivers/phy/allwinner/phy-sun4i-usb.c | 41 +++++++++++++--------------
 1 file changed, 19 insertions(+), 22 deletions(-)

--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -87,27 +87,22 @@ struct sun4i_usb_phy_cfg {
 };
 
 struct sun4i_usb_phy_info {
-	const char *gpio_vbus;
 	const char *gpio_vbus_det;
 	const char *gpio_id_det;
 } phy_info[] = {
 	{
-		.gpio_vbus = CONFIG_USB0_VBUS_PIN,
 		.gpio_vbus_det = CONFIG_USB0_VBUS_DET,
 		.gpio_id_det = CONFIG_USB0_ID_DET,
 	},
 	{
-		.gpio_vbus = CONFIG_USB1_VBUS_PIN,
 		.gpio_vbus_det = NULL,
 		.gpio_id_det = NULL,
 	},
 	{
-		.gpio_vbus = CONFIG_USB2_VBUS_PIN,
 		.gpio_vbus_det = NULL,
 		.gpio_id_det = NULL,
 	},
 	{
-		.gpio_vbus = CONFIG_USB3_VBUS_PIN,
 		.gpio_vbus_det = NULL,
 		.gpio_id_det = NULL,
 	},
@@ -115,12 +110,12 @@ struct sun4i_usb_phy_info {
 
 struct sun4i_usb_phy_plat {
 	void __iomem *pmu;
-	struct gpio_desc gpio_vbus;
 	struct gpio_desc gpio_vbus_det;
 	struct gpio_desc gpio_id_det;
 	struct clk clocks;
 	struct clk clk2;
 	struct reset_ctl resets;
+	struct udevice *vbus;
 	int id;
 };
 
@@ -209,6 +204,7 @@ static int sun4i_usb_phy_power_on(struct
 {
 	struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
 	struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+	int ret;
 
 	if (initial_usb_scan_delay) {
 		mdelay(initial_usb_scan_delay);
@@ -221,8 +217,11 @@ static int sun4i_usb_phy_power_on(struct
 		return 0;
 	}
 
-	if (dm_gpio_is_valid(&usb_phy->gpio_vbus))
-		dm_gpio_set_value(&usb_phy->gpio_vbus, 1);
+	if (usb_phy->vbus) {
+		ret = regulator_set_enable(usb_phy->vbus, true);
+		if (ret && ret != -ENOSYS)
+			return ret;
+	}
 
 	return 0;
 }
@@ -231,9 +230,13 @@ static int sun4i_usb_phy_power_off(struc
 {
 	struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
 	struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+	int ret;
 
-	if (dm_gpio_is_valid(&usb_phy->gpio_vbus))
-		dm_gpio_set_value(&usb_phy->gpio_vbus, 0);
+	if (usb_phy->vbus) {
+		ret = regulator_set_enable(usb_phy->vbus, false);
+		if (ret && ret != -ENOSYS)
+			return ret;
+	}
 
 	return 0;
 }
@@ -483,22 +486,16 @@ static int sun4i_usb_phy_probe(struct ud
 	for (i = 0; i < data->cfg->num_phys; i++) {
 		struct sun4i_usb_phy_plat *phy = &plat[i];
 		struct sun4i_usb_phy_info *info = &phy_info[i];
-		char name[16];
+		char name[32];
 
 		if (data->cfg->missing_phys & BIT(i))
 			continue;
 
-		ret = dm_gpio_lookup_name(info->gpio_vbus, &phy->gpio_vbus);
-		if (ret == 0) {
-			ret = dm_gpio_request(&phy->gpio_vbus, "usb_vbus");
-			if (ret)
-				return ret;
-			ret = dm_gpio_set_dir_flags(&phy->gpio_vbus,
-						    GPIOD_IS_OUT);
-			if (ret)
-				return ret;
-			ret = dm_gpio_set_value(&phy->gpio_vbus, 0);
-			if (ret)
+		snprintf(name, sizeof(name), "usb%d_vbus-supply", i);
+		ret = device_get_supply_regulator(dev, name, &phy->vbus);
+		if (phy->vbus) {
+			ret = regulator_set_enable(phy->vbus, false);
+			if (ret && ret != -ENOSYS)
 				return ret;
 		}
 
