Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm/allwinner/aw_usbphy.c
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | native \ No newline at end of property |
svn:keywords | null | FreeBSD=%H \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
/*- | |||||
* Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* | |||||
* $FreeBSD$ | |||||
*/ | |||||
/* | |||||
* Allwinner USB PHY | |||||
*/ | |||||
#include <sys/cdefs.h> | |||||
__FBSDID("$FreeBSD$"); | |||||
#include <sys/param.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/bus.h> | |||||
#include <sys/rman.h> | |||||
#include <sys/kernel.h> | |||||
#include <sys/module.h> | |||||
#include <sys/gpio.h> | |||||
#include <dev/ofw/ofw_bus.h> | |||||
#include <dev/ofw/ofw_bus_subr.h> | |||||
#include "gpio_if.h" | |||||
#define USBPHY_NUMOFF 3 | |||||
#define GPIO_POLARITY(flags) (((flags) & 1) ? GPIO_PIN_LOW : GPIO_PIN_HIGH) | |||||
static struct ofw_compat_data compat_data[] = { | |||||
{ "allwinner,sun4i-a10-usb-phy", 1 }, | |||||
{ "allwinner,sun5i-a13-usb-phy", 1 }, | |||||
{ "allwinner,sun6i-a31-usb-phy", 1 }, | |||||
{ "allwinner,sun7i-a20-usb-phy", 1 }, | |||||
{ NULL, 0 } | |||||
}; | |||||
static int | |||||
awusbphy_gpio_set(device_t dev, phandle_t node, const char *pname) | |||||
{ | |||||
pcell_t gpio_prop[4]; | |||||
phandle_t gpio_node; | |||||
device_t gpio_dev; | |||||
uint32_t pin, flags; | |||||
ssize_t len; | |||||
int val; | |||||
len = OF_getencprop(node, pname, gpio_prop, sizeof(gpio_prop)); | |||||
if (len == -1) | |||||
return (0); | |||||
if (len != sizeof(gpio_prop)) { | |||||
device_printf(dev, "property %s length was %d, expected %d\n", | |||||
pname, len, sizeof(gpio_prop)); | |||||
return (ENXIO); | |||||
} | |||||
gpio_node = OF_node_from_xref(gpio_prop[0]); | |||||
gpio_dev = OF_device_from_xref(gpio_prop[0]); | |||||
if (gpio_dev == NULL) { | |||||
device_printf(dev, "failed to get the GPIO device for %s\n", | |||||
pname); | |||||
return (ENOENT); | |||||
} | |||||
if (GPIO_MAP_GPIOS(gpio_dev, node, gpio_node, | |||||
sizeof(gpio_prop) / sizeof(gpio_prop[0]) - 1, gpio_prop + 1, | |||||
&pin, &flags) != 0) { | |||||
device_printf(dev, "failed to map the GPIO pin for %s\n", | |||||
pname); | |||||
return (ENXIO); | |||||
} | |||||
val = GPIO_POLARITY(flags); | |||||
GPIO_PIN_SETFLAGS(gpio_dev, pin, GPIO_PIN_OUTPUT); | |||||
GPIO_PIN_SET(gpio_dev, pin, val); | |||||
return (0); | |||||
} | |||||
static int | |||||
awusbphy_supply_set(device_t dev, const char *pname) | |||||
{ | |||||
phandle_t node, reg_node; | |||||
pcell_t reg_xref; | |||||
node = ofw_bus_get_node(dev); | |||||
if (OF_getencprop(node, pname, ®_xref, sizeof(reg_xref)) == -1) | |||||
return (0); | |||||
reg_node = OF_node_from_xref(reg_xref); | |||||
return (awusbphy_gpio_set(dev, reg_node, "gpio")); | |||||
} | |||||
static int | |||||
awusbphy_init(device_t dev) | |||||
{ | |||||
char pname[20]; | |||||
phandle_t node; | |||||
int error, off; | |||||
node = ofw_bus_get_node(dev); | |||||
for (off = 0; off < USBPHY_NUMOFF; off++) { | |||||
snprintf(pname, sizeof(pname), "usb%d_id_det-gpio", off); | |||||
error = awusbphy_gpio_set(dev, node, pname); | |||||
if (error) | |||||
return (error); | |||||
snprintf(pname, sizeof(pname), "usb%d_vbus_det-gpio", off); | |||||
error = awusbphy_gpio_set(dev, node, pname); | |||||
if (error) | |||||
return (error); | |||||
snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off); | |||||
error = awusbphy_supply_set(dev, pname); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
awusbphy_probe(device_t dev) | |||||
{ | |||||
if (!ofw_bus_status_okay(dev)) | |||||
return (ENXIO); | |||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) | |||||
return (ENXIO); | |||||
device_set_desc(dev, "Allwinner USB PHY"); | |||||
return (BUS_PROBE_DEFAULT); | |||||
} | |||||
static int | |||||
awusbphy_attach(device_t dev) | |||||
{ | |||||
int error; | |||||
error = awusbphy_init(dev); | |||||
if (error) | |||||
device_printf(dev, "failed to initialize USB PHY, error %d\n", | |||||
error); | |||||
return (error); | |||||
} | |||||
static device_method_t awusbphy_methods[] = { | |||||
/* Device interface */ | |||||
DEVMETHOD(device_probe, awusbphy_probe), | |||||
DEVMETHOD(device_attach, awusbphy_attach), | |||||
DEVMETHOD_END | |||||
}; | |||||
static driver_t awusbphy_driver = { | |||||
"awusbphy", | |||||
awusbphy_methods, | |||||
0, | |||||
}; | |||||
static devclass_t awusbphy_devclass; | |||||
DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass, 0, 0); | |||||
MODULE_VERSION(awusbphy, 1); |