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, ®) == 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