1aa7c3aa6SEmmanuel Vadot /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3aa7c3aa6SEmmanuel Vadot * 4aa7c3aa6SEmmanuel Vadot * Copyright (c) 2019 Rubicon Communications, LLC (Netgate) 5aa7c3aa6SEmmanuel Vadot * 6aa7c3aa6SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 7aa7c3aa6SEmmanuel Vadot * modification, are permitted provided that the following conditions 8aa7c3aa6SEmmanuel Vadot * are met: 9aa7c3aa6SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 10aa7c3aa6SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 11aa7c3aa6SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 12aa7c3aa6SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 13aa7c3aa6SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 14aa7c3aa6SEmmanuel Vadot * 15aa7c3aa6SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16aa7c3aa6SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17aa7c3aa6SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18aa7c3aa6SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19aa7c3aa6SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20aa7c3aa6SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21aa7c3aa6SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22aa7c3aa6SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23aa7c3aa6SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24aa7c3aa6SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25aa7c3aa6SEmmanuel Vadot * SUCH DAMAGE. 26aa7c3aa6SEmmanuel Vadot * 27aa7c3aa6SEmmanuel Vadot */ 28aa7c3aa6SEmmanuel Vadot 29aa7c3aa6SEmmanuel Vadot #include <sys/param.h> 30aa7c3aa6SEmmanuel Vadot #include <sys/systm.h> 31aa7c3aa6SEmmanuel Vadot #include <sys/bus.h> 32aa7c3aa6SEmmanuel Vadot 33aa7c3aa6SEmmanuel Vadot #include <sys/kernel.h> 34aa7c3aa6SEmmanuel Vadot #include <sys/module.h> 35aa7c3aa6SEmmanuel Vadot #include <sys/rman.h> 36aa7c3aa6SEmmanuel Vadot #include <sys/lock.h> 37aa7c3aa6SEmmanuel Vadot #include <sys/mutex.h> 38aa7c3aa6SEmmanuel Vadot 39aa7c3aa6SEmmanuel Vadot #include <machine/bus.h> 40aa7c3aa6SEmmanuel Vadot 41aa7c3aa6SEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 42aa7c3aa6SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 43aa7c3aa6SEmmanuel Vadot 44be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 45*b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h> 46aa7c3aa6SEmmanuel Vadot #include <dev/extres/phy/phy_usb.h> 47aa7c3aa6SEmmanuel Vadot 48aa7c3aa6SEmmanuel Vadot #include "phynode_if.h" 49aa7c3aa6SEmmanuel Vadot 50aa7c3aa6SEmmanuel Vadot struct usb_nop_xceiv_softc { 51aa7c3aa6SEmmanuel Vadot device_t dev; 52aa7c3aa6SEmmanuel Vadot regulator_t vcc_supply; 53aa7c3aa6SEmmanuel Vadot clk_t clk; 54aa7c3aa6SEmmanuel Vadot uint32_t clk_freq; 55aa7c3aa6SEmmanuel Vadot }; 56aa7c3aa6SEmmanuel Vadot 57aa7c3aa6SEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 58aa7c3aa6SEmmanuel Vadot {"usb-nop-xceiv", 1}, 59aa7c3aa6SEmmanuel Vadot {NULL, 0} 60aa7c3aa6SEmmanuel Vadot }; 61aa7c3aa6SEmmanuel Vadot 62aa7c3aa6SEmmanuel Vadot /* Phy class and methods. */ 63aa7c3aa6SEmmanuel Vadot static int usb_nop_xceiv_phy_enable(struct phynode *phy, bool enable); 64aa7c3aa6SEmmanuel Vadot static phynode_usb_method_t usb_nop_xceiv_phynode_methods[] = { 65aa7c3aa6SEmmanuel Vadot PHYNODEMETHOD(phynode_enable, usb_nop_xceiv_phy_enable), 66aa7c3aa6SEmmanuel Vadot 67aa7c3aa6SEmmanuel Vadot PHYNODEMETHOD_END 68aa7c3aa6SEmmanuel Vadot }; 69aa7c3aa6SEmmanuel Vadot DEFINE_CLASS_1(usb_nop_xceiv_phynode, usb_nop_xceiv_phynode_class, 70aa7c3aa6SEmmanuel Vadot usb_nop_xceiv_phynode_methods, 71aa7c3aa6SEmmanuel Vadot sizeof(struct phynode_usb_sc), phynode_usb_class); 72aa7c3aa6SEmmanuel Vadot 73aa7c3aa6SEmmanuel Vadot static int 74aa7c3aa6SEmmanuel Vadot usb_nop_xceiv_phy_enable(struct phynode *phynode, bool enable) 75aa7c3aa6SEmmanuel Vadot { 76aa7c3aa6SEmmanuel Vadot struct usb_nop_xceiv_softc *sc; 77aa7c3aa6SEmmanuel Vadot device_t dev; 78aa7c3aa6SEmmanuel Vadot intptr_t phy; 79aa7c3aa6SEmmanuel Vadot int error; 80aa7c3aa6SEmmanuel Vadot 81aa7c3aa6SEmmanuel Vadot dev = phynode_get_device(phynode); 82aa7c3aa6SEmmanuel Vadot phy = phynode_get_id(phynode); 83aa7c3aa6SEmmanuel Vadot sc = device_get_softc(dev); 84aa7c3aa6SEmmanuel Vadot 85aa7c3aa6SEmmanuel Vadot if (phy != 0) 86aa7c3aa6SEmmanuel Vadot return (ERANGE); 87aa7c3aa6SEmmanuel Vadot 88aa7c3aa6SEmmanuel Vadot /* Enable the phy clock */ 89aa7c3aa6SEmmanuel Vadot if (sc->clk_freq != 0) { 90aa7c3aa6SEmmanuel Vadot if (enable) { 91aa7c3aa6SEmmanuel Vadot error = clk_set_freq(sc->clk, sc->clk_freq, 92aa7c3aa6SEmmanuel Vadot CLK_SET_ROUND_ANY); 93aa7c3aa6SEmmanuel Vadot if (error != 0) { 94aa7c3aa6SEmmanuel Vadot device_printf(dev, "Cannot set clock to %dMhz\n", 95aa7c3aa6SEmmanuel Vadot sc->clk_freq); 96aa7c3aa6SEmmanuel Vadot goto fail; 97aa7c3aa6SEmmanuel Vadot } 98aa7c3aa6SEmmanuel Vadot 99aa7c3aa6SEmmanuel Vadot error = clk_enable(sc->clk); 100aa7c3aa6SEmmanuel Vadot } else 101aa7c3aa6SEmmanuel Vadot error = clk_disable(sc->clk); 102aa7c3aa6SEmmanuel Vadot 103aa7c3aa6SEmmanuel Vadot if (error != 0) { 104aa7c3aa6SEmmanuel Vadot device_printf(dev, "Cannot %sable the clock\n", 105aa7c3aa6SEmmanuel Vadot enable ? "En" : "Dis"); 106aa7c3aa6SEmmanuel Vadot goto fail; 107aa7c3aa6SEmmanuel Vadot } 108aa7c3aa6SEmmanuel Vadot } 109aa7c3aa6SEmmanuel Vadot if (sc->vcc_supply) { 110aa7c3aa6SEmmanuel Vadot if (enable) 111aa7c3aa6SEmmanuel Vadot error = regulator_enable(sc->vcc_supply); 112aa7c3aa6SEmmanuel Vadot else 113aa7c3aa6SEmmanuel Vadot error = regulator_disable(sc->vcc_supply); 114aa7c3aa6SEmmanuel Vadot if (error != 0) { 115aa7c3aa6SEmmanuel Vadot device_printf(dev, "Cannot %sable the regulator\n", 116aa7c3aa6SEmmanuel Vadot enable ? "En" : "Dis"); 117aa7c3aa6SEmmanuel Vadot goto fail; 118aa7c3aa6SEmmanuel Vadot } 119aa7c3aa6SEmmanuel Vadot } 120aa7c3aa6SEmmanuel Vadot 121aa7c3aa6SEmmanuel Vadot return (0); 122aa7c3aa6SEmmanuel Vadot 123aa7c3aa6SEmmanuel Vadot fail: 124aa7c3aa6SEmmanuel Vadot return (ENXIO); 125aa7c3aa6SEmmanuel Vadot } 126aa7c3aa6SEmmanuel Vadot 127aa7c3aa6SEmmanuel Vadot static int 128aa7c3aa6SEmmanuel Vadot usb_nop_xceiv_probe(device_t dev) 129aa7c3aa6SEmmanuel Vadot { 130aa7c3aa6SEmmanuel Vadot 131aa7c3aa6SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 132aa7c3aa6SEmmanuel Vadot return (ENXIO); 133aa7c3aa6SEmmanuel Vadot 134aa7c3aa6SEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 135aa7c3aa6SEmmanuel Vadot return (ENXIO); 136aa7c3aa6SEmmanuel Vadot 137aa7c3aa6SEmmanuel Vadot device_set_desc(dev, "USB NOP PHY"); 138aa7c3aa6SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 139aa7c3aa6SEmmanuel Vadot } 140aa7c3aa6SEmmanuel Vadot 141aa7c3aa6SEmmanuel Vadot static int 142aa7c3aa6SEmmanuel Vadot usb_nop_xceiv_attach(device_t dev) 143aa7c3aa6SEmmanuel Vadot { 144aa7c3aa6SEmmanuel Vadot struct usb_nop_xceiv_softc *sc; 145aa7c3aa6SEmmanuel Vadot struct phynode *phynode; 146aa7c3aa6SEmmanuel Vadot struct phynode_init_def phy_init; 147aa7c3aa6SEmmanuel Vadot phandle_t node; 148aa7c3aa6SEmmanuel Vadot int error; 149aa7c3aa6SEmmanuel Vadot 150aa7c3aa6SEmmanuel Vadot sc = device_get_softc(dev); 151aa7c3aa6SEmmanuel Vadot sc->dev = dev; 152aa7c3aa6SEmmanuel Vadot node = ofw_bus_get_node(dev); 153aa7c3aa6SEmmanuel Vadot 154aa7c3aa6SEmmanuel Vadot /* Parse the optional properties */ 155aa7c3aa6SEmmanuel Vadot OF_getencprop(node, "clock-frequency", &sc->clk_freq, sizeof(uint32_t)); 156aa7c3aa6SEmmanuel Vadot 157aa7c3aa6SEmmanuel Vadot error = clk_get_by_ofw_name(dev, node, "main_clk", &sc->clk); 158aa7c3aa6SEmmanuel Vadot if (error != 0 && sc->clk_freq != 0) { 159aa7c3aa6SEmmanuel Vadot device_printf(dev, "clock property is mandatory if clock-frequency is present\n"); 160aa7c3aa6SEmmanuel Vadot return (ENXIO); 161aa7c3aa6SEmmanuel Vadot } 162aa7c3aa6SEmmanuel Vadot 163aa7c3aa6SEmmanuel Vadot regulator_get_by_ofw_property(dev, node, "vcc-supply", &sc->vcc_supply); 164aa7c3aa6SEmmanuel Vadot 165aa7c3aa6SEmmanuel Vadot phy_init.id = 0; 166aa7c3aa6SEmmanuel Vadot phy_init.ofw_node = node; 167aa7c3aa6SEmmanuel Vadot phynode = phynode_create(dev, &usb_nop_xceiv_phynode_class, 168aa7c3aa6SEmmanuel Vadot &phy_init); 169aa7c3aa6SEmmanuel Vadot if (phynode == NULL) { 170aa7c3aa6SEmmanuel Vadot device_printf(dev, "failed to create USB NOP PHY\n"); 171aa7c3aa6SEmmanuel Vadot return (ENXIO); 172aa7c3aa6SEmmanuel Vadot } 173aa7c3aa6SEmmanuel Vadot if (phynode_register(phynode) == NULL) { 174aa7c3aa6SEmmanuel Vadot device_printf(dev, "failed to create USB NOP PHY\n"); 175aa7c3aa6SEmmanuel Vadot return (ENXIO); 176aa7c3aa6SEmmanuel Vadot } 177aa7c3aa6SEmmanuel Vadot 178aa7c3aa6SEmmanuel Vadot OF_device_register_xref(OF_xref_from_node(node), dev); 179aa7c3aa6SEmmanuel Vadot 180aa7c3aa6SEmmanuel Vadot return (0); 181aa7c3aa6SEmmanuel Vadot } 182aa7c3aa6SEmmanuel Vadot 183aa7c3aa6SEmmanuel Vadot static int 184aa7c3aa6SEmmanuel Vadot usb_nop_xceiv_detach(device_t dev) 185aa7c3aa6SEmmanuel Vadot { 186aa7c3aa6SEmmanuel Vadot 187aa7c3aa6SEmmanuel Vadot return (EBUSY); 188aa7c3aa6SEmmanuel Vadot } 189aa7c3aa6SEmmanuel Vadot 190aa7c3aa6SEmmanuel Vadot static device_method_t usb_nop_xceiv_methods[] = { 191aa7c3aa6SEmmanuel Vadot /* Device interface */ 192aa7c3aa6SEmmanuel Vadot DEVMETHOD(device_probe, usb_nop_xceiv_probe), 193aa7c3aa6SEmmanuel Vadot DEVMETHOD(device_attach, usb_nop_xceiv_attach), 194aa7c3aa6SEmmanuel Vadot DEVMETHOD(device_detach, usb_nop_xceiv_detach), 195aa7c3aa6SEmmanuel Vadot 196aa7c3aa6SEmmanuel Vadot DEVMETHOD_END 197aa7c3aa6SEmmanuel Vadot }; 198aa7c3aa6SEmmanuel Vadot 199aa7c3aa6SEmmanuel Vadot static driver_t usb_nop_xceiv_driver = { 200aa7c3aa6SEmmanuel Vadot "usb_nop_xceiv", 201aa7c3aa6SEmmanuel Vadot usb_nop_xceiv_methods, 202aa7c3aa6SEmmanuel Vadot sizeof(struct usb_nop_xceiv_softc), 203aa7c3aa6SEmmanuel Vadot }; 204aa7c3aa6SEmmanuel Vadot 205aa7c3aa6SEmmanuel Vadot EARLY_DRIVER_MODULE(usb_nop_xceiv, simplebus, usb_nop_xceiv_driver, 206bc9372d7SJohn Baldwin 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); 207