diff --git a/sys/arm/allwinner/a10_ehci.c b/sys/arm/allwinner/a10_ehci.c index 6c91ba6f3feb..95e59907cb16 100644 --- a/sys/arm/allwinner/a10_ehci.c +++ b/sys/arm/allwinner/a10_ehci.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #define EHCI_HC_DEVSTR "Allwinner Integrated USB 2.0 controller" @@ -94,6 +95,7 @@ struct aw_ehci_softc { ehci_softc_t sc; clk_t clk; hwreset_t rst; + phy_t phy; }; struct aw_ehci_conf { @@ -225,6 +227,18 @@ a10_ehci_attach(device_t self) goto error; } + /* Enable USB PHY */ + err = phy_get_by_ofw_name(self, "usb", &aw_sc->phy); + if (err != 0) { + device_printf(self, "Could not get phy\n"); + goto error; + } + err = phy_enable(self, aw_sc->phy); + if (err != 0) { + device_printf(self, "Could not enable phy\n"); + goto error; + } + /* Enable passby */ reg_value = A10_READ_4(sc, SW_USB_PMU_IRQ_ENABLE); reg_value |= SW_AHB_INCR8; /* AHB INCR8 enable */ diff --git a/sys/arm/allwinner/aw_usbphy.c b/sys/arm/allwinner/aw_usbphy.c index 362da6590471..3eb3c656b23e 100644 --- a/sys/arm/allwinner/aw_usbphy.c +++ b/sys/arm/allwinner/aw_usbphy.c @@ -43,12 +43,16 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include +#include -#define USBPHY_NUMOFF 3 +#include "phy_if.h" + +#define USBPHY_NPHYS 4 static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-usb-phy", 1 }, @@ -60,15 +64,28 @@ static struct ofw_compat_data compat_data[] = { { NULL, 0 } }; +struct awusbphy_softc { + regulator_t reg[USBPHY_NPHYS]; + gpio_pin_t id_det_pin; + int id_det_valid; + gpio_pin_t vbus_det_pin; + int vbus_det_valid; +}; + static int awusbphy_init(device_t dev) { + struct awusbphy_softc *sc; + phandle_t node; char pname[20]; int error, off; regulator_t reg; hwreset_t rst; clk_t clk; + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + /* Enable clocks */ for (off = 0; clk_get_by_ofw_index(dev, off, &clk) == 0; off++) { error = clk_enable(clk); @@ -89,17 +106,80 @@ awusbphy_init(device_t dev) } } - /* Enable regulator(s) */ - for (off = 0; off < USBPHY_NUMOFF; off++) { + /* Get regulators */ + for (off = 0; off < USBPHY_NPHYS; off++) { snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off); - if (regulator_get_by_ofw_property(dev, pname, ®) != 0) - continue; - error = regulator_enable(reg); - if (error != 0) { - device_printf(dev, "couldn't enable regulator %s\n", - pname); + if (regulator_get_by_ofw_property(dev, pname, ®) == 0) + sc->reg[off] = reg; + } + + /* Get GPIOs */ + error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios", + &sc->id_det_pin); + if (error == 0) + sc->id_det_valid = 1; + error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios", + &sc->vbus_det_pin); + if (error == 0) + sc->vbus_det_valid = 1; + + return (0); +} + +static int +awusbphy_vbus_detect(device_t dev, int *val) +{ + struct awusbphy_softc *sc; + bool active; + int error; + + sc = device_get_softc(dev); + + if (sc->vbus_det_valid) { + error = gpio_pin_is_active(sc->vbus_det_pin, &active); + if (error != 0) return (error); - } + *val = active; + return (0); + } + + *val = 1; + return (0); +} + +static int +awusbphy_phy_enable(device_t dev, int phy, bool enable) +{ + struct awusbphy_softc *sc; + regulator_t reg; + int error, vbus_det; + + if (phy < 0 || phy >= USBPHY_NPHYS) + return (ERANGE); + + sc = device_get_softc(dev); + + /* Regulators are optional. If not found, return success. */ + reg = sc->reg[phy]; + if (reg == NULL) + return (0); + + if (enable) { + /* If an external vbus is detected, do not enable phy 0 */ + if (phy == 0) { + error = awusbphy_vbus_detect(dev, &vbus_det); + if (error == 0 && vbus_det == 1) + return (0); + } else + error = 0; + if (error == 0) + error = regulator_enable(reg); + } else + error = regulator_disable(reg); + if (error != 0) { + device_printf(dev, "couldn't %s regulator for phy %d\n", + enable ? "enable" : "disable", phy); + return (error); } return (0); @@ -124,9 +204,13 @@ awusbphy_attach(device_t dev) int error; error = awusbphy_init(dev); - if (error) + if (error) { device_printf(dev, "failed to initialize USB PHY, error %d\n", error); + return (error); + } + + phy_register_provider(dev); return (error); } @@ -136,16 +220,20 @@ static device_method_t awusbphy_methods[] = { DEVMETHOD(device_probe, awusbphy_probe), DEVMETHOD(device_attach, awusbphy_attach), + /* PHY interface */ + DEVMETHOD(phy_enable, awusbphy_phy_enable), + DEVMETHOD_END }; static driver_t awusbphy_driver = { "awusbphy", awusbphy_methods, - 0, + sizeof(struct awusbphy_softc) }; static devclass_t awusbphy_devclass; -DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass, 0, 0); +EARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass, + 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(awusbphy, 1); diff --git a/sys/dev/usb/controller/generic_ohci.c b/sys/dev/usb/controller/generic_ohci.c index 5d00c525a12e..9656c8faa1c8 100644 --- a/sys/dev/usb/controller/generic_ohci.c +++ b/sys/dev/usb/controller/generic_ohci.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #ifdef EXT_RESOURCES #include #include +#include #endif #include "generic_usb_if.h" @@ -76,6 +77,7 @@ struct generic_ohci_softc { #ifdef EXT_RESOURCES hwreset_t rst; + phy_t phy; TAILQ_HEAD(, clk_list) clk_list; #endif }; @@ -180,6 +182,15 @@ generic_ohci_attach(device_t dev) goto error; } } + + /* Enable phy */ + if (phy_get_by_ofw_name(dev, "usb", &sc->phy) == 0) { + err = phy_enable(dev, sc->phy); + if (err != 0) { + device_printf(dev, "Could not enable phy\n"); + goto error; + } + } #endif if (GENERIC_USB_INIT(dev) != 0) { @@ -253,6 +264,14 @@ generic_ohci_detach(device_t dev) usb_bus_mem_free_all(&sc->ohci_sc.sc_bus, &ohci_iterate_hw_softc); #ifdef EXT_RESOURCES + /* Disable phy */ + if (sc->phy) { + err = phy_disable(dev, sc->phy); + if (err != 0) + device_printf(dev, "Could not disable phy\n"); + phy_release(sc->phy); + } + /* Disable clock */ TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) { err = clk_disable(clk->clk);