aw_usbphy.c revision 309760
1121992Sjhb/*-
2121992Sjhb * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3121992Sjhb * All rights reserved.
4121992Sjhb *
5121992Sjhb * Redistribution and use in source and binary forms, with or without
6121992Sjhb * modification, are permitted provided that the following conditions
7121992Sjhb * are met:
8121992Sjhb * 1. Redistributions of source code must retain the above copyright
9121992Sjhb *    notice, this list of conditions and the following disclaimer.
10121992Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11121992Sjhb *    notice, this list of conditions and the following disclaimer in the
12121992Sjhb *    documentation and/or other materials provided with the distribution.
13121992Sjhb *
14121992Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15121992Sjhb * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16121992Sjhb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17121992Sjhb * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18121992Sjhb * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19121992Sjhb * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20121992Sjhb * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21121992Sjhb * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22121992Sjhb * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23121992Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24121992Sjhb * SUCH DAMAGE.
25121992Sjhb *
26121992Sjhb * $FreeBSD: stable/11/sys/arm/allwinner/aw_usbphy.c 309760 2016-12-09 20:25:59Z manu $
27121992Sjhb */
28121992Sjhb
29121992Sjhb/*
30121992Sjhb * Allwinner USB PHY
31121992Sjhb */
32121992Sjhb
33121992Sjhb#include <sys/cdefs.h>
34121992Sjhb__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/aw_usbphy.c 309760 2016-12-09 20:25:59Z manu $");
35121992Sjhb
36121992Sjhb#include <sys/param.h>
37121992Sjhb#include <sys/systm.h>
38121992Sjhb#include <sys/bus.h>
39214631Sjhb#include <sys/rman.h>
40121992Sjhb#include <sys/kernel.h>
41261087Sjhb#include <sys/module.h>
42121992Sjhb#include <sys/gpio.h>
43193530Sjkim
44193530Sjkim#include <dev/ofw/ofw_bus.h>
45193530Sjkim#include <dev/ofw/ofw_bus_subr.h>
46121992Sjhb#include <dev/gpio/gpiobusvar.h>
47121992Sjhb
48121992Sjhb#include <dev/extres/clk/clk.h>
49121992Sjhb#include <dev/extres/hwreset/hwreset.h>
50233623Sjhb#include <dev/extres/regulator/regulator.h>
51121992Sjhb#include <dev/extres/phy/phy.h>
52121992Sjhb
53233623Sjhb#include "phy_if.h"
54121992Sjhb
55233623Sjhb#define	USBPHY_NPHYS	4
56121992Sjhb
57129960Sjhbstatic struct ofw_compat_data compat_data[] = {
58233623Sjhb	{ "allwinner,sun4i-a10-usb-phy",	1 },
59121992Sjhb	{ "allwinner,sun5i-a13-usb-phy",	1 },
60269512Sroyger	{ "allwinner,sun6i-a31-usb-phy",	1 },
61167814Sjkim	{ "allwinner,sun7i-a20-usb-phy",	1 },
62121992Sjhb	{ "allwinner,sun8i-a83t-usb-phy",	1 },
63121992Sjhb	{ "allwinner,sun8i-h3-usb-phy",		1 },
64121992Sjhb	{ NULL,					0 }
65227293Sed};
66121992Sjhb
67167814Sjkimstruct awusbphy_softc {
68167814Sjkim	regulator_t		reg[USBPHY_NPHYS];
69121992Sjhb	gpio_pin_t		id_det_pin;
70121992Sjhb	int			id_det_valid;
71167814Sjkim	gpio_pin_t		vbus_det_pin;
72167814Sjkim	int			vbus_det_valid;
73167814Sjkim};
74167814Sjkim
75167814Sjkimstatic int
76167814Sjkimawusbphy_init(device_t dev)
77167814Sjkim{
78121992Sjhb	struct awusbphy_softc *sc;
79121992Sjhb	phandle_t node;
80167814Sjkim	char pname[20];
81167814Sjkim	int error, off;
82121992Sjhb	regulator_t reg;
83121992Sjhb	hwreset_t rst;
84121992Sjhb	clk_t clk;
85197439Sjhb
86121992Sjhb	sc = device_get_softc(dev);
87121992Sjhb	node = ofw_bus_get_node(dev);
88121992Sjhb
89121992Sjhb	/* Enable clocks */
90121992Sjhb	for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
91121992Sjhb		error = clk_enable(clk);
92121992Sjhb		if (error != 0) {
93121992Sjhb			device_printf(dev, "couldn't enable clock %s\n",
94121992Sjhb			    clk_get_name(clk));
95121992Sjhb			return (error);
96121992Sjhb		}
97121992Sjhb	}
98121992Sjhb
99121992Sjhb	/* De-assert resets */
100121992Sjhb	for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) {
101121992Sjhb		error = hwreset_deassert(rst);
102197439Sjhb		if (error != 0) {
103197439Sjhb			device_printf(dev, "couldn't de-assert reset %d\n",
104121992Sjhb			    off);
105269511Sroyger			return (error);
106121992Sjhb		}
107121992Sjhb	}
108121992Sjhb
109121992Sjhb	/* Get regulators */
110121992Sjhb	for (off = 0; off < USBPHY_NPHYS; off++) {
111121992Sjhb		snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off);
112121992Sjhb		if (regulator_get_by_ofw_property(dev, 0, pname, &reg) == 0)
113121992Sjhb			sc->reg[off] = reg;
114121992Sjhb	}
115197439Sjhb
116197439Sjhb	/* Get GPIOs */
117121992Sjhb	error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios",
118121992Sjhb	    &sc->id_det_pin);
119197439Sjhb	if (error == 0)
120121992Sjhb		sc->id_det_valid = 1;
121121992Sjhb	error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios",
122121992Sjhb	    &sc->vbus_det_pin);
123121992Sjhb	if (error == 0)
124121992Sjhb		sc->vbus_det_valid = 1;
125121992Sjhb
126121992Sjhb	return (0);
127121992Sjhb}
128121992Sjhb
129121992Sjhbstatic int
130121992Sjhbawusbphy_vbus_detect(device_t dev, int *val)
131161223Sjhb{
132167814Sjkim	struct awusbphy_softc *sc;
133121992Sjhb	bool active;
134167814Sjkim	int error;
135167814Sjkim
136121992Sjhb	sc = device_get_softc(dev);
137121992Sjhb
138121992Sjhb	if (sc->vbus_det_valid) {
139121992Sjhb		error = gpio_pin_is_active(sc->vbus_det_pin, &active);
140121992Sjhb		if (error != 0)
141121992Sjhb			return (error);
142121992Sjhb		*val = active;
143121992Sjhb		return (0);
144121992Sjhb	}
145125048Sjhb
146121992Sjhb	*val = 1;
147121992Sjhb	return (0);
148121992Sjhb}
149121992Sjhb
150128930Sjhbstatic int
151128930Sjhbawusbphy_phy_enable(device_t dev, intptr_t phy, bool enable)
152121992Sjhb{
153121992Sjhb	struct awusbphy_softc *sc;
154125048Sjhb	regulator_t reg;
155125048Sjhb	int error, vbus_det;
156125048Sjhb
157125048Sjhb	if (phy < 0 || phy >= USBPHY_NPHYS)
158125048Sjhb		return (ERANGE);
159125048Sjhb
160125048Sjhb	sc = device_get_softc(dev);
161125048Sjhb
162233623Sjhb	/* Regulators are optional. If not found, return success. */
163233623Sjhb	reg = sc->reg[phy];
164233623Sjhb	if (reg == NULL)
165233623Sjhb		return (0);
166121992Sjhb
167121992Sjhb	if (enable) {
168121992Sjhb		/* If an external vbus is detected, do not enable phy 0 */
169121992Sjhb		if (phy == 0) {
170121992Sjhb			error = awusbphy_vbus_detect(dev, &vbus_det);
171121992Sjhb			if (error == 0 && vbus_det == 1)
172128930Sjhb				return (0);
173128930Sjhb		} else
174128930Sjhb			error = 0;
175128930Sjhb		if (error == 0)
176128930Sjhb			error = regulator_enable(reg);
177167814Sjkim	} else
178167814Sjkim		error = regulator_disable(reg);
179167814Sjkim	if (error != 0) {
180167814Sjkim		device_printf(dev,
181128930Sjhb		    "couldn't %s regulator for phy %jd\n",
182128930Sjhb		    enable ? "enable" : "disable", (intmax_t)phy);
183128930Sjhb		return (error);
184128930Sjhb	}
185128930Sjhb
186128930Sjhb	return (0);
187128930Sjhb}
188128930Sjhb
189121992Sjhbstatic int
190169395Sjhbawusbphy_probe(device_t dev)
191121992Sjhb{
192121992Sjhb	if (!ofw_bus_status_okay(dev))
193121992Sjhb		return (ENXIO);
194121992Sjhb
195121992Sjhb	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
196121992Sjhb		return (ENXIO);
197233623Sjhb
198233623Sjhb	device_set_desc(dev, "Allwinner USB PHY");
199233623Sjhb	return (BUS_PROBE_DEFAULT);
200121992Sjhb}
201121992Sjhb
202121992Sjhbstatic int
203121992Sjhbawusbphy_attach(device_t dev)
204121992Sjhb{
205121992Sjhb	int error;
206121992Sjhb
207121992Sjhb	error = awusbphy_init(dev);
208121992Sjhb	if (error) {
209215009Sjhb		device_printf(dev, "failed to initialize USB PHY, error %d\n",
210121992Sjhb		    error);
211121992Sjhb		return (error);
212121992Sjhb	}
213121992Sjhb
214121992Sjhb	phy_register_provider(dev);
215197439Sjhb
216121992Sjhb	return (error);
217121992Sjhb}
218197439Sjhb
219197439Sjhbstatic device_method_t awusbphy_methods[] = {
220121992Sjhb	/* Device interface */
221121992Sjhb	DEVMETHOD(device_probe,		awusbphy_probe),
222121992Sjhb	DEVMETHOD(device_attach,	awusbphy_attach),
223167814Sjkim
224121992Sjhb	/* PHY interface */
225167814Sjkim	DEVMETHOD(phy_enable,		awusbphy_phy_enable),
226121992Sjhb
227121992Sjhb	DEVMETHOD_END
228121992Sjhb};
229167814Sjkim
230121992Sjhbstatic driver_t awusbphy_driver = {
231121992Sjhb	"awusbphy",
232121992Sjhb	awusbphy_methods,
233121992Sjhb	sizeof(struct awusbphy_softc)
234121992Sjhb};
235167814Sjkim
236121992Sjhbstatic devclass_t awusbphy_devclass;
237167814Sjkim
238167814SjkimEARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass,
239167814Sjkim    0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
240167814SjkimMODULE_VERSION(awusbphy, 1);
241167814Sjkim