11b4bd023SJared McNeill /*- 21b4bd023SJared McNeill * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 31b4bd023SJared McNeill * All rights reserved. 41b4bd023SJared McNeill * 51b4bd023SJared McNeill * Redistribution and use in source and binary forms, with or without 61b4bd023SJared McNeill * modification, are permitted provided that the following conditions 71b4bd023SJared McNeill * are met: 81b4bd023SJared McNeill * 1. Redistributions of source code must retain the above copyright 91b4bd023SJared McNeill * notice, this list of conditions and the following disclaimer. 101b4bd023SJared McNeill * 2. Redistributions in binary form must reproduce the above copyright 111b4bd023SJared McNeill * notice, this list of conditions and the following disclaimer in the 121b4bd023SJared McNeill * documentation and/or other materials provided with the distribution. 131b4bd023SJared McNeill * 141b4bd023SJared McNeill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 151b4bd023SJared McNeill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 161b4bd023SJared McNeill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 171b4bd023SJared McNeill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 181b4bd023SJared McNeill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 191b4bd023SJared McNeill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 201b4bd023SJared McNeill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 211b4bd023SJared McNeill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 221b4bd023SJared McNeill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231b4bd023SJared McNeill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241b4bd023SJared McNeill * SUCH DAMAGE. 251b4bd023SJared McNeill * 261b4bd023SJared McNeill * $FreeBSD$ 271b4bd023SJared McNeill */ 281b4bd023SJared McNeill 291b4bd023SJared McNeill /* 301b4bd023SJared McNeill * Allwinner USB PHY 311b4bd023SJared McNeill */ 321b4bd023SJared McNeill 331b4bd023SJared McNeill #include <sys/cdefs.h> 341b4bd023SJared McNeill __FBSDID("$FreeBSD$"); 351b4bd023SJared McNeill 361b4bd023SJared McNeill #include <sys/param.h> 371b4bd023SJared McNeill #include <sys/systm.h> 381b4bd023SJared McNeill #include <sys/bus.h> 391b4bd023SJared McNeill #include <sys/rman.h> 401b4bd023SJared McNeill #include <sys/kernel.h> 411b4bd023SJared McNeill #include <sys/module.h> 421b4bd023SJared McNeill #include <sys/gpio.h> 4363dc81d8SJared McNeill #include <machine/bus.h> 441b4bd023SJared McNeill 451b4bd023SJared McNeill #include <dev/ofw/ofw_bus.h> 461b4bd023SJared McNeill #include <dev/ofw/ofw_bus_subr.h> 47627c360fSJared McNeill #include <dev/gpio/gpiobusvar.h> 481b4bd023SJared McNeill 496a05f063SJared McNeill #include <dev/extres/clk/clk.h> 506a05f063SJared McNeill #include <dev/extres/hwreset/hwreset.h> 516a05f063SJared McNeill #include <dev/extres/regulator/regulator.h> 52627c360fSJared McNeill #include <dev/extres/phy/phy.h> 531b4bd023SJared McNeill 54f8759facSMichal Meloun #include "phynode_if.h" 55627c360fSJared McNeill 5663dc81d8SJared McNeill enum awusbphy_type { 5763dc81d8SJared McNeill AWUSBPHY_TYPE_A10 = 1, 5863dc81d8SJared McNeill AWUSBPHY_TYPE_A13, 5963dc81d8SJared McNeill AWUSBPHY_TYPE_A20, 6063dc81d8SJared McNeill AWUSBPHY_TYPE_A31, 6163dc81d8SJared McNeill AWUSBPHY_TYPE_H3, 625b48129eSKyle Evans AWUSBPHY_TYPE_A64, 635b48129eSKyle Evans AWUSBPHY_TYPE_A83T 6463dc81d8SJared McNeill }; 651b4bd023SJared McNeill 6636dcd6a4SEmmanuel Vadot struct aw_usbphy_conf { 6736dcd6a4SEmmanuel Vadot int num_phys; 6836dcd6a4SEmmanuel Vadot enum awusbphy_type phy_type; 6936dcd6a4SEmmanuel Vadot bool pmu_unk1; 7036dcd6a4SEmmanuel Vadot bool phy0_route; 7136dcd6a4SEmmanuel Vadot }; 7236dcd6a4SEmmanuel Vadot 7336dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a10_usbphy_conf = { 7436dcd6a4SEmmanuel Vadot .num_phys = 3, 7536dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A10, 7636dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 7736dcd6a4SEmmanuel Vadot .phy0_route = false, 7836dcd6a4SEmmanuel Vadot }; 7936dcd6a4SEmmanuel Vadot 8036dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a13_usbphy_conf = { 8136dcd6a4SEmmanuel Vadot .num_phys = 2, 8236dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A13, 8336dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 8436dcd6a4SEmmanuel Vadot .phy0_route = false, 8536dcd6a4SEmmanuel Vadot }; 8636dcd6a4SEmmanuel Vadot 8736dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a20_usbphy_conf = { 8836dcd6a4SEmmanuel Vadot .num_phys = 3, 8936dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A20, 9036dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 9136dcd6a4SEmmanuel Vadot .phy0_route = false, 9236dcd6a4SEmmanuel Vadot }; 9336dcd6a4SEmmanuel Vadot 9436dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a31_usbphy_conf = { 9536dcd6a4SEmmanuel Vadot .num_phys = 3, 9636dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A31, 9736dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 9836dcd6a4SEmmanuel Vadot .phy0_route = false, 9936dcd6a4SEmmanuel Vadot }; 10036dcd6a4SEmmanuel Vadot 10136dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf h3_usbphy_conf = { 10236dcd6a4SEmmanuel Vadot .num_phys = 4, 10336dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_H3, 10436dcd6a4SEmmanuel Vadot .pmu_unk1 = true, 10536dcd6a4SEmmanuel Vadot .phy0_route = false, 10636dcd6a4SEmmanuel Vadot }; 10736dcd6a4SEmmanuel Vadot 10836dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a64_usbphy_conf = { 10936dcd6a4SEmmanuel Vadot .num_phys = 2, 11036dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A64, 11136dcd6a4SEmmanuel Vadot .pmu_unk1 = true, 11236dcd6a4SEmmanuel Vadot .phy0_route = true, 11336dcd6a4SEmmanuel Vadot }; 11436dcd6a4SEmmanuel Vadot 1155b48129eSKyle Evans static const struct aw_usbphy_conf a83t_usbphy_conf = { 1165b48129eSKyle Evans .num_phys = 3, 1175b48129eSKyle Evans .phy_type = AWUSBPHY_TYPE_A83T, 1185b48129eSKyle Evans .pmu_unk1 = false, 1195b48129eSKyle Evans .phy0_route = false, 1205b48129eSKyle Evans }; 1215b48129eSKyle Evans 1221b4bd023SJared McNeill static struct ofw_compat_data compat_data[] = { 12336dcd6a4SEmmanuel Vadot { "allwinner,sun4i-a10-usb-phy", (uintptr_t)&a10_usbphy_conf }, 12436dcd6a4SEmmanuel Vadot { "allwinner,sun5i-a13-usb-phy", (uintptr_t)&a13_usbphy_conf }, 12536dcd6a4SEmmanuel Vadot { "allwinner,sun6i-a31-usb-phy", (uintptr_t)&a31_usbphy_conf }, 12636dcd6a4SEmmanuel Vadot { "allwinner,sun7i-a20-usb-phy", (uintptr_t)&a20_usbphy_conf }, 12736dcd6a4SEmmanuel Vadot { "allwinner,sun8i-h3-usb-phy", (uintptr_t)&h3_usbphy_conf }, 12836dcd6a4SEmmanuel Vadot { "allwinner,sun50i-a64-usb-phy", (uintptr_t)&a64_usbphy_conf }, 1295b48129eSKyle Evans { "allwinner,sun8i-a83t-usb-phy", (uintptr_t)&a83t_usbphy_conf }, 1301b4bd023SJared McNeill { NULL, 0 } 1311b4bd023SJared McNeill }; 1321b4bd023SJared McNeill 133627c360fSJared McNeill struct awusbphy_softc { 13436dcd6a4SEmmanuel Vadot struct resource * phy_ctrl; 13536dcd6a4SEmmanuel Vadot struct resource ** pmu; 13636dcd6a4SEmmanuel Vadot regulator_t * reg; 137627c360fSJared McNeill gpio_pin_t id_det_pin; 138627c360fSJared McNeill int id_det_valid; 139627c360fSJared McNeill gpio_pin_t vbus_det_pin; 140627c360fSJared McNeill int vbus_det_valid; 14136dcd6a4SEmmanuel Vadot struct aw_usbphy_conf *phy_conf; 142627c360fSJared McNeill }; 143627c360fSJared McNeill 144f8759facSMichal Meloun /* Phy class and methods. */ 145f8759facSMichal Meloun static int awusbphy_phy_enable(struct phynode *phy, bool enable); 146f8759facSMichal Meloun static phynode_method_t awusbphy_phynode_methods[] = { 147f8759facSMichal Meloun PHYNODEMETHOD(phynode_enable, awusbphy_phy_enable), 148f8759facSMichal Meloun 149f8759facSMichal Meloun PHYNODEMETHOD_END 150f8759facSMichal Meloun }; 151f8759facSMichal Meloun DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_methods, 152f8759facSMichal Meloun 0, phynode_class); 153f8759facSMichal Meloun 15436dcd6a4SEmmanuel Vadot #define RD4(res, o) bus_read_4(res, (o)) 15536dcd6a4SEmmanuel Vadot #define WR4(res, o, v) bus_write_4(res, (o), (v)) 15636dcd6a4SEmmanuel Vadot #define CLR4(res, o, m) WR4(res, o, RD4(res, o) & ~(m)) 15736dcd6a4SEmmanuel Vadot #define SET4(res, o, m) WR4(res, o, RD4(res, o) | (m)) 15863dc81d8SJared McNeill 15963dc81d8SJared McNeill #define OTG_PHY_CFG 0x20 16063dc81d8SJared McNeill #define OTG_PHY_ROUTE_OTG (1 << 0) 16163dc81d8SJared McNeill #define PMU_IRQ_ENABLE 0x00 16263dc81d8SJared McNeill #define PMU_AHB_INCR8 (1 << 10) 16363dc81d8SJared McNeill #define PMU_AHB_INCR4 (1 << 9) 16463dc81d8SJared McNeill #define PMU_AHB_INCRX_ALIGN (1 << 8) 16563dc81d8SJared McNeill #define PMU_ULPI_BYPASS (1 << 0) 16663dc81d8SJared McNeill #define PMU_UNK_H3 0x10 16763dc81d8SJared McNeill #define PMU_UNK_H3_CLR 0x2 16863dc81d8SJared McNeill 16963dc81d8SJared McNeill static void 17063dc81d8SJared McNeill awusbphy_configure(device_t dev, int phyno) 17163dc81d8SJared McNeill { 17263dc81d8SJared McNeill struct awusbphy_softc *sc; 17363dc81d8SJared McNeill 17463dc81d8SJared McNeill sc = device_get_softc(dev); 17563dc81d8SJared McNeill 17636dcd6a4SEmmanuel Vadot if (sc->pmu[phyno] == NULL) 17763dc81d8SJared McNeill return; 17863dc81d8SJared McNeill 17936dcd6a4SEmmanuel Vadot if (sc->phy_conf->pmu_unk1 == true) 1801eca1d26SEmmanuel Vadot CLR4(sc->pmu[phyno], PMU_UNK_H3, PMU_UNK_H3_CLR); 18163dc81d8SJared McNeill 18236dcd6a4SEmmanuel Vadot SET4(sc->pmu[phyno], PMU_IRQ_ENABLE, PMU_ULPI_BYPASS | 18363dc81d8SJared McNeill PMU_AHB_INCR8 | PMU_AHB_INCR4 | PMU_AHB_INCRX_ALIGN); 18463dc81d8SJared McNeill } 18563dc81d8SJared McNeill 1861b4bd023SJared McNeill static int 1871b4bd023SJared McNeill awusbphy_init(device_t dev) 1881b4bd023SJared McNeill { 189627c360fSJared McNeill struct awusbphy_softc *sc; 190627c360fSJared McNeill phandle_t node; 1911b4bd023SJared McNeill char pname[20]; 19236dcd6a4SEmmanuel Vadot int error, off, rid; 1936a05f063SJared McNeill regulator_t reg; 1946a05f063SJared McNeill hwreset_t rst; 1956a05f063SJared McNeill clk_t clk; 1961b4bd023SJared McNeill 197627c360fSJared McNeill sc = device_get_softc(dev); 198627c360fSJared McNeill node = ofw_bus_get_node(dev); 199627c360fSJared McNeill 20036dcd6a4SEmmanuel Vadot sc->phy_conf = (struct aw_usbphy_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 20136dcd6a4SEmmanuel Vadot 20236dcd6a4SEmmanuel Vadot /* Get phy_ctrl region */ 20336dcd6a4SEmmanuel Vadot if (ofw_bus_find_string_index(node, "reg-names", "phy_ctrl", &rid) != 0) { 20436dcd6a4SEmmanuel Vadot device_printf(dev, "Cannot locate phy control resource\n"); 20536dcd6a4SEmmanuel Vadot return (ENXIO); 20636dcd6a4SEmmanuel Vadot } 20736dcd6a4SEmmanuel Vadot sc->phy_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 20836dcd6a4SEmmanuel Vadot RF_ACTIVE); 20936dcd6a4SEmmanuel Vadot if (sc->phy_ctrl == NULL) { 21036dcd6a4SEmmanuel Vadot device_printf(dev, "Cannot allocate resource\n"); 21136dcd6a4SEmmanuel Vadot return (ENXIO); 21236dcd6a4SEmmanuel Vadot } 21363dc81d8SJared McNeill 2146a05f063SJared McNeill /* Enable clocks */ 215dac93553SMichal Meloun for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) { 2166a05f063SJared McNeill error = clk_enable(clk); 2176a05f063SJared McNeill if (error != 0) { 2186a05f063SJared McNeill device_printf(dev, "couldn't enable clock %s\n", 2196a05f063SJared McNeill clk_get_name(clk)); 2206a05f063SJared McNeill return (error); 2216a05f063SJared McNeill } 2226a05f063SJared McNeill } 2231b4bd023SJared McNeill 2246a05f063SJared McNeill /* De-assert resets */ 225dac93553SMichal Meloun for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) { 2266a05f063SJared McNeill error = hwreset_deassert(rst); 2276a05f063SJared McNeill if (error != 0) { 2286a05f063SJared McNeill device_printf(dev, "couldn't de-assert reset %d\n", 2296a05f063SJared McNeill off); 2306a05f063SJared McNeill return (error); 2316a05f063SJared McNeill } 2326a05f063SJared McNeill } 2336a05f063SJared McNeill 234627c360fSJared McNeill /* Get GPIOs */ 235627c360fSJared McNeill error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios", 236627c360fSJared McNeill &sc->id_det_pin); 237627c360fSJared McNeill if (error == 0) 238627c360fSJared McNeill sc->id_det_valid = 1; 239627c360fSJared McNeill error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios", 240627c360fSJared McNeill &sc->vbus_det_pin); 241627c360fSJared McNeill if (error == 0) 242627c360fSJared McNeill sc->vbus_det_valid = 1; 243627c360fSJared McNeill 24436dcd6a4SEmmanuel Vadot sc->reg = malloc(sizeof(*(sc->reg)) * sc->phy_conf->num_phys, M_DEVBUF, 24536dcd6a4SEmmanuel Vadot M_WAITOK | M_ZERO); 24636dcd6a4SEmmanuel Vadot sc->pmu = malloc(sizeof(*(sc->pmu)) * sc->phy_conf->num_phys, M_DEVBUF, 24736dcd6a4SEmmanuel Vadot M_WAITOK | M_ZERO); 24836dcd6a4SEmmanuel Vadot /* Get regulators */ 24936dcd6a4SEmmanuel Vadot for (off = 0; off < sc->phy_conf->num_phys; off++) { 25036dcd6a4SEmmanuel Vadot snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off); 25136dcd6a4SEmmanuel Vadot if (regulator_get_by_ofw_property(dev, 0, pname, ®) == 0) 25236dcd6a4SEmmanuel Vadot sc->reg[off] = reg; 25336dcd6a4SEmmanuel Vadot 25436dcd6a4SEmmanuel Vadot snprintf(pname, sizeof(pname), "pmu%d", off); 25536dcd6a4SEmmanuel Vadot if (ofw_bus_find_string_index(node, "reg-names", 25636dcd6a4SEmmanuel Vadot pname, &rid) != 0) 25736dcd6a4SEmmanuel Vadot continue; 25836dcd6a4SEmmanuel Vadot 25936dcd6a4SEmmanuel Vadot sc->pmu[off] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 26036dcd6a4SEmmanuel Vadot RF_ACTIVE); 26136dcd6a4SEmmanuel Vadot if (sc->pmu[off] == NULL) { 26236dcd6a4SEmmanuel Vadot device_printf(dev, "Cannot allocate resource\n"); 26336dcd6a4SEmmanuel Vadot return (ENXIO); 26436dcd6a4SEmmanuel Vadot } 26536dcd6a4SEmmanuel Vadot } 26663dc81d8SJared McNeill 267627c360fSJared McNeill return (0); 268627c360fSJared McNeill } 269627c360fSJared McNeill 270627c360fSJared McNeill static int 271627c360fSJared McNeill awusbphy_vbus_detect(device_t dev, int *val) 272627c360fSJared McNeill { 273627c360fSJared McNeill struct awusbphy_softc *sc; 274627c360fSJared McNeill bool active; 275627c360fSJared McNeill int error; 276627c360fSJared McNeill 277627c360fSJared McNeill sc = device_get_softc(dev); 278627c360fSJared McNeill 279627c360fSJared McNeill if (sc->vbus_det_valid) { 280627c360fSJared McNeill error = gpio_pin_is_active(sc->vbus_det_pin, &active); 281de355beaSEmmanuel Vadot if (error != 0) { 282de355beaSEmmanuel Vadot device_printf(dev, "Cannot get status of id pin %d\n", 283de355beaSEmmanuel Vadot error); 284627c360fSJared McNeill return (error); 285de355beaSEmmanuel Vadot } 286627c360fSJared McNeill *val = active; 287627c360fSJared McNeill return (0); 288627c360fSJared McNeill } 289627c360fSJared McNeill 290627c360fSJared McNeill *val = 1; 291627c360fSJared McNeill return (0); 292627c360fSJared McNeill } 293627c360fSJared McNeill 294627c360fSJared McNeill static int 295f8759facSMichal Meloun awusbphy_phy_enable(struct phynode *phynode, bool enable) 296627c360fSJared McNeill { 297f8759facSMichal Meloun device_t dev; 298f8759facSMichal Meloun intptr_t phy; 299627c360fSJared McNeill struct awusbphy_softc *sc; 300627c360fSJared McNeill regulator_t reg; 301627c360fSJared McNeill int error, vbus_det; 302627c360fSJared McNeill 303f8759facSMichal Meloun dev = phynode_get_device(phynode); 304f8759facSMichal Meloun phy = phynode_get_id(phynode); 305627c360fSJared McNeill sc = device_get_softc(dev); 306627c360fSJared McNeill 30736dcd6a4SEmmanuel Vadot if (phy < 0 || phy >= sc->phy_conf->num_phys) 30836dcd6a4SEmmanuel Vadot return (ERANGE); 30936dcd6a4SEmmanuel Vadot 31063dc81d8SJared McNeill /* Configure PHY */ 31163dc81d8SJared McNeill awusbphy_configure(dev, phy); 31263dc81d8SJared McNeill 313627c360fSJared McNeill /* Regulators are optional. If not found, return success. */ 314627c360fSJared McNeill reg = sc->reg[phy]; 315627c360fSJared McNeill if (reg == NULL) 316627c360fSJared McNeill return (0); 317627c360fSJared McNeill 318627c360fSJared McNeill if (enable) { 319627c360fSJared McNeill /* If an external vbus is detected, do not enable phy 0 */ 320627c360fSJared McNeill if (phy == 0) { 321627c360fSJared McNeill error = awusbphy_vbus_detect(dev, &vbus_det); 322de355beaSEmmanuel Vadot if (error) 323de355beaSEmmanuel Vadot goto out; 324de355beaSEmmanuel Vadot 325de355beaSEmmanuel Vadot /* Depending on the PHY we need to route OTG to OHCI/EHCI */ 326de355beaSEmmanuel Vadot if (sc->phy_conf->phy0_route == true) { 327de355beaSEmmanuel Vadot if (vbus_det == 0) 328de355beaSEmmanuel Vadot /* Host mode */ 329de355beaSEmmanuel Vadot CLR4(sc->phy_ctrl, OTG_PHY_CFG, 330de355beaSEmmanuel Vadot OTG_PHY_ROUTE_OTG); 331de355beaSEmmanuel Vadot else 332de355beaSEmmanuel Vadot /* Peripheral mode */ 333de355beaSEmmanuel Vadot SET4(sc->phy_ctrl, OTG_PHY_CFG, 334de355beaSEmmanuel Vadot OTG_PHY_ROUTE_OTG); 335de355beaSEmmanuel Vadot } 336de355beaSEmmanuel Vadot if (vbus_det == 1) 337627c360fSJared McNeill return (0); 338627c360fSJared McNeill } else 339627c360fSJared McNeill error = 0; 340627c360fSJared McNeill if (error == 0) 341627c360fSJared McNeill error = regulator_enable(reg); 342627c360fSJared McNeill } else 343627c360fSJared McNeill error = regulator_disable(reg); 344de355beaSEmmanuel Vadot 345de355beaSEmmanuel Vadot out: 346627c360fSJared McNeill if (error != 0) { 3477dd62272SJared McNeill device_printf(dev, 3487dd62272SJared McNeill "couldn't %s regulator for phy %jd\n", 3497dd62272SJared McNeill enable ? "enable" : "disable", (intmax_t)phy); 350627c360fSJared McNeill return (error); 3516a05f063SJared McNeill } 3521b4bd023SJared McNeill 3531b4bd023SJared McNeill return (0); 3541b4bd023SJared McNeill } 3551b4bd023SJared McNeill 3561b4bd023SJared McNeill static int 3571b4bd023SJared McNeill awusbphy_probe(device_t dev) 3581b4bd023SJared McNeill { 3591b4bd023SJared McNeill if (!ofw_bus_status_okay(dev)) 3601b4bd023SJared McNeill return (ENXIO); 3611b4bd023SJared McNeill 3621b4bd023SJared McNeill if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 3631b4bd023SJared McNeill return (ENXIO); 3641b4bd023SJared McNeill 3651b4bd023SJared McNeill device_set_desc(dev, "Allwinner USB PHY"); 3661b4bd023SJared McNeill return (BUS_PROBE_DEFAULT); 3671b4bd023SJared McNeill } 3681b4bd023SJared McNeill 3691b4bd023SJared McNeill static int 3701b4bd023SJared McNeill awusbphy_attach(device_t dev) 3711b4bd023SJared McNeill { 3721b4bd023SJared McNeill int error; 373f8759facSMichal Meloun struct phynode *phynode; 374f8759facSMichal Meloun struct phynode_init_def phy_init; 375f8759facSMichal Meloun struct awusbphy_softc *sc; 376f8759facSMichal Meloun int i; 3771b4bd023SJared McNeill 378f8759facSMichal Meloun sc = device_get_softc(dev); 3791b4bd023SJared McNeill error = awusbphy_init(dev); 380627c360fSJared McNeill if (error) { 3811b4bd023SJared McNeill device_printf(dev, "failed to initialize USB PHY, error %d\n", 3821b4bd023SJared McNeill error); 383627c360fSJared McNeill return (error); 384627c360fSJared McNeill } 385627c360fSJared McNeill 386f8759facSMichal Meloun /* Create and register phys. */ 387f8759facSMichal Meloun for (i = 0; i < sc->phy_conf->num_phys; i++) { 388f8759facSMichal Meloun bzero(&phy_init, sizeof(phy_init)); 389f8759facSMichal Meloun phy_init.id = i; 390f8759facSMichal Meloun phy_init.ofw_node = ofw_bus_get_node(dev); 391f8759facSMichal Meloun phynode = phynode_create(dev, &awusbphy_phynode_class, 392f8759facSMichal Meloun &phy_init); 393f8759facSMichal Meloun if (phynode == NULL) { 394f8759facSMichal Meloun device_printf(dev, "failed to create USB PHY\n"); 395f8759facSMichal Meloun return (ENXIO); 396f8759facSMichal Meloun } 397f8759facSMichal Meloun if (phynode_register(phynode) == NULL) { 398f8759facSMichal Meloun device_printf(dev, "failed to create USB PHY\n"); 399f8759facSMichal Meloun return (ENXIO); 400f8759facSMichal Meloun } 401f8759facSMichal Meloun } 4021b4bd023SJared McNeill 4031b4bd023SJared McNeill return (error); 4041b4bd023SJared McNeill } 4051b4bd023SJared McNeill 4061b4bd023SJared McNeill static device_method_t awusbphy_methods[] = { 4071b4bd023SJared McNeill /* Device interface */ 4081b4bd023SJared McNeill DEVMETHOD(device_probe, awusbphy_probe), 4091b4bd023SJared McNeill DEVMETHOD(device_attach, awusbphy_attach), 4101b4bd023SJared McNeill 4111b4bd023SJared McNeill DEVMETHOD_END 4121b4bd023SJared McNeill }; 4131b4bd023SJared McNeill 4141b4bd023SJared McNeill static driver_t awusbphy_driver = { 4151b4bd023SJared McNeill "awusbphy", 4161b4bd023SJared McNeill awusbphy_methods, 417627c360fSJared McNeill sizeof(struct awusbphy_softc) 4181b4bd023SJared McNeill }; 4191b4bd023SJared McNeill 4201b4bd023SJared McNeill static devclass_t awusbphy_devclass; 421*9f3b3133SKyle Evans /* aw_usbphy needs to come up after regulators/gpio/etc, but before ehci/ohci */ 422627c360fSJared McNeill EARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass, 423*9f3b3133SKyle Evans 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); 4241b4bd023SJared McNeill MODULE_VERSION(awusbphy, 1); 425