xref: /freebsd/sys/dev/usb/controller/usb_nop_xceiv.c (revision 950a6087ec18cd22464b3297573f54a6d9223c99)
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>
45b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
46*950a6087SEmmanuel Vadot #include <dev/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
usb_nop_xceiv_phy_enable(struct phynode * phynode,bool enable)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
usb_nop_xceiv_probe(device_t dev)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
usb_nop_xceiv_attach(device_t dev)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
usb_nop_xceiv_detach(device_t dev)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