Hi Quentin, pt., 16 maj 2025 o 17:05 Quentin Schulz <quentin.sch...@cherry.de> napisał(a): > > Hi Lukasz, > > On 4/25/25 12:56 PM, Lukasz Czechowski wrote: > > Some of the onboard hubs require multiple power supplies, so extend > > the driver to support them. > > The implementation is inspired by the kernel driver, as introduced > > by commit [1] in the v6.10 kernel. > > > > [1] > > https://github.com/torvalds/linux/commit/ec1848cd5df426f57a7f6a8a6b95b69259c52cfc > > Signed-off-by: Lukasz Czechowski <lukasz.czechow...@thaumatec.com> > > --- > > common/usb_onboard_hub.c | 45 > > +++++++++++++++++++++++++++++++++------------ > > 1 file changed, 33 insertions(+), 12 deletions(-) > > > > diff --git a/common/usb_onboard_hub.c b/common/usb_onboard_hub.c > > index 325c274ed952..b8fa38a4111d 100644 > > --- a/common/usb_onboard_hub.c > > +++ b/common/usb_onboard_hub.c > > @@ -20,14 +20,18 @@ > > #define USB5744_CONFIG_REG_ACCESS 0x0037 > > #define USB5744_CONFIG_REG_ACCESS_LSB 0x99 > > > > +#define MAX_SUPPLIES 2 > > + > > struct onboard_hub { > > - struct udevice *vdd; > > + struct udevice *vdd[MAX_SUPPLIES]; > > struct gpio_desc *reset_gpio; > > }; > > > > struct onboard_hub_data { > > unsigned long reset_us; > > unsigned long power_on_delay_us; > > + unsigned int num_supplies; > > + const char * const supply_names[MAX_SUPPLIES]; > > int (*init)(struct udevice *dev); > > }; > > > > @@ -144,20 +148,28 @@ static int usb_onboard_hub_probe(struct udevice *dev) > > struct onboard_hub_data *data = > > (struct onboard_hub_data *)dev_get_driver_data(dev); > > struct onboard_hub *hub = dev_get_priv(dev); > > + unsigned int i; > > int ret; > > > > - ret = device_get_supply_regulator(dev, "vdd-supply", &hub->vdd); > > - if (ret && ret != -ENOENT) { > > - dev_err(dev, "can't get vdd-supply: %d\n", ret); > > - return ret; > > + if (data->num_supplies > MAX_SUPPLIES) { > > + dev_err(dev, "invalid supplies number, max supported: %d\n", > > MAX_SUPPLIES); > > + return -EINVAL; > > } > > > > - if (hub->vdd) { > > - ret = regulator_set_enable_if_allowed(hub->vdd, true); > > - if (ret && ret != -ENOSYS) { > > - dev_err(dev, "can't enable vdd-supply: %d\n", ret); > > + for (i = 0; i < data->num_supplies; i++) { > > + ret = device_get_supply_regulator(dev, data->supply_names[i], > > &hub->vdd[i]); > > + if (ret && ret != -ENOENT) { > > + dev_err(dev, "can't get %s: %d\n", > > data->supply_names[i], ret); > > return ret; > > } > > + > > + if (hub->vdd[i]) { > > + ret = regulator_set_enable_if_allowed(hub->vdd[i], > > true); > > + if (ret && ret != -ENOSYS) { > > + dev_err(dev, "can't enable %s: %d\n", > > data->supply_names[i], ret); > > + return ret; > > + } > > + } > > I'm wondering if we shouldn't have all return ret; actually be goto err; > instead? I would assume that the error path in the probe function should > be really close to what we have in remove function? > > To that extent, before this patch even, I think we should probably > dm_gpio_set_value() the reset line when there's an error so that the hub > is held in reset? > > Additionally, I believe the dm_gpio_free() in the remove function is > unnecessary because we request the gpio with a devm_ function which > should call dm_gpio_free() whenever appropriate? >
I think it's worth improving, and this can be done in separate patch, > Finally, specifically for this patch here, I believe we should disable > all regulators in the opposite order when in the error path? > > Something like: > > err: > for (i = data->num_supplies - 1; i >= 0; i--) { > ret = regulator_set_enable_if_allowed(hub->vdd[i], false); > if (ret) > dev_err(dev, "can't disable %s: %d\n", > data->supply_names[i], ret); > } > > ? what do you think? > Thanks for the comments. That's a good point. I'll update it in v2. > > } > > > > ret = usb_onboard_hub_reset(dev); > > @@ -208,7 +220,10 @@ static int usb_onboard_hub_bind(struct udevice *dev) > > > > static int usb_onboard_hub_remove(struct udevice *dev) > > { > > + struct onboard_hub_data *data = > > + (struct onboard_hub_data *)dev_get_driver_data(dev); > > struct onboard_hub *hub = dev_get_priv(dev); > > + unsigned int i; > > int ret; > > > > if (hub->reset_gpio) { > > @@ -216,9 +231,11 @@ static int usb_onboard_hub_remove(struct udevice *dev) > > dm_gpio_free(hub->reset_gpio->dev, hub->reset_gpio); > > } > > > > - ret = regulator_set_enable_if_allowed(hub->vdd, false); > > - if (ret) > > - dev_err(dev, "can't disable vdd-supply: %d\n", ret); > > + for (i = 0; i < data->num_supplies; i++) { > > + ret = regulator_set_enable_if_allowed(hub->vdd[i], false); > > + if (ret) > > + dev_err(dev, "can't disable %s: %d\n", > > data->supply_names[i], ret); > > + } > > > > The error/remove path is usually unwinding in opposite order than the > normal path, so that would be looping from last supply to first. C.f. > regulator_bulk_disable in the Linux kernel. > > > return ret; > > This one's an issue now, it'll return 0 if the last > regulator_set_enable_if_allowed is 0, overriding the return code from > dm_gpio_set_value and earlier regulator_set_enable_if_allowed calls. We > should probably |= them or return some appropriate hardcoded value if at > least one failed. > > Cheers, > Quentin Best regards, Lukasz