Despite default reset upon probe, release reset line after powering up the hub and assert reset again before powering down. Signed-off-by: Alexander Stein <alexander.stein@xxxxxxxxxxxxxxx> --- My current DT node on my TQMa8MPxL looks like this ``` &usb_dwc3_1 { dr_mode = "host"; #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usbhub>; status = "okay"; hub_2_0: hub@1 { compatible = "usb451,8142"; reg = <1>; peer-hub = <&hub_3_0>; reset-gpio = <&gpio1 11 GPIO_ACTIVE_LOW>; }; hub_3_0: hub@2 { compatible = "usb451,8140"; reg = <2>; peer-hub = <&hub_2_0>; reset-gpio = <&gpio1 11 GPIO_ACTIVE_LOW>; }; }; ``` which I don't like much for 2 reasons: * the pinctrl has to be put in a common top-node of USB hub node. The pinctrl can not be requested twice. * Apparently there is no conflict on the reset-gpio only because just one device gets probed here: > $ ls /sys/bus/platform/drivers/onboard-usb-hub/ > 38200000.usb:hub@1 bind uevent unbind But this seems better than to use a common fixed-regulator referenced by both hub nodes, which just is controlled by GPIO and does not supply any voltages. Note: It might also be necessary to add bindings to specify ramp up times and/or reset timeouts. drivers/usb/misc/onboard_usb_hub.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index 6b9b949d17d3..348fb5270266 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -7,6 +7,7 @@ #include <linux/device.h> #include <linux/export.h> +#include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/list.h> @@ -38,6 +39,7 @@ struct usbdev_node { struct onboard_hub { struct regulator *vdd; struct device *dev; + struct gpio_desc *reset_gpio; bool always_powered_in_suspend; bool is_powered_on; bool going_away; @@ -56,6 +58,10 @@ static int onboard_hub_power_on(struct onboard_hub *hub) return err; } + /* Deassert reset */ + usleep_range(3000, 3100); + gpiod_set_value_cansleep(hub->reset_gpio, 0); + hub->is_powered_on = true; return 0; @@ -65,6 +71,10 @@ static int onboard_hub_power_off(struct onboard_hub *hub) { int err; + /* Assert reset */ + gpiod_set_value_cansleep(hub->reset_gpio, 1); + usleep_range(4000, 5000); + err = regulator_disable(hub->vdd); if (err) { dev_err(hub->dev, "failed to disable regulator: %d\n", err); @@ -231,6 +241,14 @@ static int onboard_hub_probe(struct platform_device *pdev) if (IS_ERR(hub->vdd)) return PTR_ERR(hub->vdd); + /* Put the hub into reset, pull reset line low, and assure 4ms reset low timing. */ + hub->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(hub->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n"); + + usleep_range(4000, 5000); + hub->dev = dev; mutex_init(&hub->lock); INIT_LIST_HEAD(&hub->udev_list); -- 2.25.1