imx8mq_usbphy.c revision 1.2
11.2Sthorpej/* $NetBSD: imx8mq_usbphy.c,v 1.2 2021/01/18 02:35:48 thorpej Exp $ */ 21.1Sskrll 31.1Sskrll/*- 41.1Sskrll * Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca> 51.1Sskrll * All rights reserved. 61.1Sskrll * 71.1Sskrll * Redistribution and use in source and binary forms, with or without 81.1Sskrll * modification, are permitted provided that the following conditions 91.1Sskrll * are met: 101.1Sskrll * 1. Redistributions of source code must retain the above copyright 111.1Sskrll * notice, this list of conditions and the following disclaimer. 121.1Sskrll * 2. Redistributions in binary form must reproduce the above copyright 131.1Sskrll * notice, this list of conditions and the following disclaimer in the 141.1Sskrll * documentation and/or other materials provided with the distribution. 151.1Sskrll * 161.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 171.1Sskrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Sskrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Sskrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 201.1Sskrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 211.1Sskrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 221.1Sskrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 231.1Sskrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 241.1Sskrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251.1Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Sskrll * POSSIBILITY OF SUCH DAMAGE. 271.1Sskrll */ 281.1Sskrll 291.1Sskrll#include <sys/cdefs.h> 301.1Sskrll 311.2Sthorpej__KERNEL_RCSID(0, "$NetBSD: imx8mq_usbphy.c,v 1.2 2021/01/18 02:35:48 thorpej Exp $"); 321.1Sskrll 331.1Sskrll#include <sys/param.h> 341.1Sskrll#include <sys/bus.h> 351.1Sskrll#include <sys/device.h> 361.1Sskrll#include <sys/intr.h> 371.1Sskrll#include <sys/systm.h> 381.1Sskrll#include <sys/time.h> 391.1Sskrll 401.1Sskrll#include <dev/fdt/fdtvar.h> 411.1Sskrll 421.1Sskrll#define PHY_CTL0_ADDR 0x00 431.1Sskrll#define REF_SSP_EN __BIT(2) 441.1Sskrll 451.1Sskrll#define PHY_CTL1_ADDR 0x04 461.1Sskrll#define PHY_VDATDATENB0 __BIT(20) 471.1Sskrll#define PHY_VDATSRCENB0 __BIT(19) 481.1Sskrll#define PHY_ATERESET __BIT(3) 491.1Sskrll#define PHY_COMMONONN __BIT(1) 501.1Sskrll#define PHY_RESET __BIT(0) 511.1Sskrll 521.1Sskrll#define PHY_CTL2_ADDR 0x08 531.1Sskrll#define PHY_TXENABLEN0 __BIT(8) 541.1Sskrll 551.1Sskrllstatic int imx8mq_usbphy_match(device_t, cfdata_t, void *); 561.1Sskrllstatic void imx8mq_usbphy_attach(device_t, device_t, void *); 571.1Sskrll 581.2Sthorpejstatic const struct device_compatible_entry compat_data[] = { 591.2Sthorpej { .compat = "fsl,imx8mq-usb-phy" }, 601.2Sthorpej 611.2Sthorpej { 0 } 621.1Sskrll}; 631.1Sskrll 641.1Sskrllstruct imx8mq_usbphy_softc { 651.1Sskrll device_t sc_dev; 661.1Sskrll bus_space_tag_t sc_bst; 671.1Sskrll bus_space_handle_t sc_bsh; 681.1Sskrll int sc_phandle; 691.1Sskrll}; 701.1Sskrll 711.1Sskrll#define PHY_READ(sc, reg) \ 721.1Sskrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 731.1Sskrll#define PHY_WRITE(sc, reg, val) \ 741.1Sskrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 751.1Sskrll 761.1SskrllCFATTACH_DECL_NEW(imx8mqusbphy, sizeof(struct imx8mq_usbphy_softc), 771.1Sskrll imx8mq_usbphy_match, imx8mq_usbphy_attach, NULL, NULL); 781.1Sskrll 791.1Sskrllstatic void * 801.1Sskrllimx8mq_usbphy_acquire(device_t dev, const void *data, size_t len) 811.1Sskrll{ 821.1Sskrll if (len != 0) 831.1Sskrll return NULL; 841.1Sskrll 851.1Sskrll return (void *)(uintptr_t)1; 861.1Sskrll} 871.1Sskrll 881.1Sskrllstatic void 891.1Sskrllimx8mq_usbphy_release(device_t dev, void *priv) 901.1Sskrll{ 911.1Sskrll} 921.1Sskrll 931.1Sskrllstatic int 941.1Sskrllimx8mq_usbphy_enable(device_t dev, void *priv, bool enable) 951.1Sskrll{ 961.1Sskrll struct imx8mq_usbphy_softc * const sc = device_private(dev); 971.1Sskrll struct fdtbus_regulator *reg; 981.1Sskrll uint32_t val; 991.1Sskrll int error; 1001.1Sskrll 1011.1Sskrll if (enable) { 1021.1Sskrll if (of_hasprop(sc->sc_phandle, "vbus-supply")) { 1031.1Sskrll reg = fdtbus_regulator_acquire(sc->sc_phandle, "vbus-supply"); 1041.1Sskrll if (reg != NULL) { 1051.1Sskrll error = fdtbus_regulator_enable(reg); 1061.1Sskrll if (error != 0) 1071.1Sskrll device_printf(dev, "WARNING: couldn't enable vbus-supply: %d\n", error); 1081.1Sskrll } else { 1091.1Sskrll device_printf(dev, "WARNING: couldn't acquire vbus-supply\n"); 1101.1Sskrll } 1111.1Sskrll } 1121.1Sskrll 1131.1Sskrll val = PHY_READ(sc, PHY_CTL1_ADDR); 1141.1Sskrll val &= ~PHY_VDATDATENB0; 1151.1Sskrll val &= ~PHY_VDATSRCENB0; 1161.1Sskrll val &= ~PHY_COMMONONN; 1171.1Sskrll val |= PHY_RESET; 1181.1Sskrll val |= PHY_ATERESET; 1191.1Sskrll PHY_WRITE(sc, PHY_CTL1_ADDR, val); 1201.1Sskrll 1211.1Sskrll val = PHY_READ(sc, PHY_CTL0_ADDR); 1221.1Sskrll val |= REF_SSP_EN; 1231.1Sskrll PHY_WRITE(sc, PHY_CTL0_ADDR, val); 1241.1Sskrll 1251.1Sskrll val = PHY_READ(sc, PHY_CTL2_ADDR); 1261.1Sskrll val |= PHY_TXENABLEN0; 1271.1Sskrll PHY_WRITE(sc, PHY_CTL2_ADDR, val); 1281.1Sskrll 1291.1Sskrll val = PHY_READ(sc, PHY_CTL1_ADDR); 1301.1Sskrll val &= ~PHY_RESET; 1311.1Sskrll val &= ~PHY_ATERESET; 1321.1Sskrll PHY_WRITE(sc, PHY_CTL1_ADDR, val); 1331.1Sskrll } 1341.1Sskrll 1351.1Sskrll return 0; 1361.1Sskrll} 1371.1Sskrll 1381.1Sskrllconst struct fdtbus_phy_controller_func imx8mq_usbphy_funcs = { 1391.1Sskrll .acquire = imx8mq_usbphy_acquire, 1401.1Sskrll .release = imx8mq_usbphy_release, 1411.1Sskrll .enable = imx8mq_usbphy_enable, 1421.1Sskrll}; 1431.1Sskrll 1441.1Sskrllstatic int 1451.1Sskrllimx8mq_usbphy_match(device_t parent, cfdata_t cf, void *aux) 1461.1Sskrll{ 1471.1Sskrll struct fdt_attach_args * const faa = aux; 1481.1Sskrll 1491.1Sskrll return of_match_compat_data(faa->faa_phandle, compat_data); 1501.1Sskrll} 1511.1Sskrll 1521.1Sskrllstatic void 1531.1Sskrllimx8mq_usbphy_attach(device_t parent, device_t self, void *aux) 1541.1Sskrll{ 1551.1Sskrll struct imx8mq_usbphy_softc * const sc = device_private(self); 1561.1Sskrll struct fdt_attach_args * const faa = aux; 1571.1Sskrll const int phandle = faa->faa_phandle; 1581.1Sskrll bus_addr_t addr; 1591.1Sskrll bus_size_t size; 1601.1Sskrll 1611.1Sskrll sc->sc_dev = self; 1621.1Sskrll sc->sc_bst = faa->faa_bst; 1631.1Sskrll sc->sc_phandle = phandle; 1641.1Sskrll 1651.1Sskrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1661.1Sskrll aprint_error(": couldn't get registers\n"); 1671.1Sskrll return; 1681.1Sskrll } 1691.1Sskrll if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 1701.1Sskrll aprint_error(": couldn't map registers\n"); 1711.1Sskrll return; 1721.1Sskrll } 1731.1Sskrll 1741.1Sskrll /* Enable clocks */ 1751.1Sskrll fdtbus_clock_assign(phandle); 1761.1Sskrll if (fdtbus_clock_enable(phandle, "phy", true) != 0) { 1771.1Sskrll aprint_error(": couldn't enable phy clock\n"); 1781.1Sskrll return; 1791.1Sskrll } 1801.1Sskrll 1811.1Sskrll aprint_naive("\n"); 1821.1Sskrll aprint_normal(": USB PHY\n"); 1831.1Sskrll 1841.1Sskrll fdtbus_register_phy_controller(self, phandle, &imx8mq_usbphy_funcs); 1851.1Sskrll} 186