11.5Sthorpej/* $NetBSD: imx8mq_usbphy.c,v 1.5 2021/01/27 03:10:20 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.5Sthorpej__KERNEL_RCSID(0, "$NetBSD: imx8mq_usbphy.c,v 1.5 2021/01/27 03:10:20 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.4Sthorpej DEVICE_COMPAT_EOL 611.1Sskrll}; 621.1Sskrll 631.1Sskrllstruct imx8mq_usbphy_softc { 641.1Sskrll device_t sc_dev; 651.1Sskrll bus_space_tag_t sc_bst; 661.1Sskrll bus_space_handle_t sc_bsh; 671.1Sskrll int sc_phandle; 681.1Sskrll}; 691.1Sskrll 701.1Sskrll#define PHY_READ(sc, reg) \ 711.1Sskrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 721.1Sskrll#define PHY_WRITE(sc, reg, val) \ 731.1Sskrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 741.1Sskrll 751.1SskrllCFATTACH_DECL_NEW(imx8mqusbphy, sizeof(struct imx8mq_usbphy_softc), 761.1Sskrll imx8mq_usbphy_match, imx8mq_usbphy_attach, NULL, NULL); 771.1Sskrll 781.1Sskrllstatic void * 791.1Sskrllimx8mq_usbphy_acquire(device_t dev, const void *data, size_t len) 801.1Sskrll{ 811.1Sskrll if (len != 0) 821.1Sskrll return NULL; 831.1Sskrll 841.1Sskrll return (void *)(uintptr_t)1; 851.1Sskrll} 861.1Sskrll 871.1Sskrllstatic void 881.1Sskrllimx8mq_usbphy_release(device_t dev, void *priv) 891.1Sskrll{ 901.1Sskrll} 911.1Sskrll 921.1Sskrllstatic int 931.1Sskrllimx8mq_usbphy_enable(device_t dev, void *priv, bool enable) 941.1Sskrll{ 951.1Sskrll struct imx8mq_usbphy_softc * const sc = device_private(dev); 961.1Sskrll struct fdtbus_regulator *reg; 971.1Sskrll uint32_t val; 981.1Sskrll int error; 991.1Sskrll 1001.1Sskrll if (enable) { 1011.1Sskrll if (of_hasprop(sc->sc_phandle, "vbus-supply")) { 1021.1Sskrll reg = fdtbus_regulator_acquire(sc->sc_phandle, "vbus-supply"); 1031.1Sskrll if (reg != NULL) { 1041.1Sskrll error = fdtbus_regulator_enable(reg); 1051.1Sskrll if (error != 0) 1061.1Sskrll device_printf(dev, "WARNING: couldn't enable vbus-supply: %d\n", error); 1071.1Sskrll } else { 1081.1Sskrll device_printf(dev, "WARNING: couldn't acquire vbus-supply\n"); 1091.1Sskrll } 1101.1Sskrll } 1111.1Sskrll 1121.1Sskrll val = PHY_READ(sc, PHY_CTL1_ADDR); 1131.1Sskrll val &= ~PHY_VDATDATENB0; 1141.1Sskrll val &= ~PHY_VDATSRCENB0; 1151.1Sskrll val &= ~PHY_COMMONONN; 1161.1Sskrll val |= PHY_RESET; 1171.1Sskrll val |= PHY_ATERESET; 1181.1Sskrll PHY_WRITE(sc, PHY_CTL1_ADDR, val); 1191.1Sskrll 1201.1Sskrll val = PHY_READ(sc, PHY_CTL0_ADDR); 1211.1Sskrll val |= REF_SSP_EN; 1221.1Sskrll PHY_WRITE(sc, PHY_CTL0_ADDR, val); 1231.1Sskrll 1241.1Sskrll val = PHY_READ(sc, PHY_CTL2_ADDR); 1251.1Sskrll val |= PHY_TXENABLEN0; 1261.1Sskrll PHY_WRITE(sc, PHY_CTL2_ADDR, val); 1271.1Sskrll 1281.1Sskrll val = PHY_READ(sc, PHY_CTL1_ADDR); 1291.1Sskrll val &= ~PHY_RESET; 1301.1Sskrll val &= ~PHY_ATERESET; 1311.1Sskrll PHY_WRITE(sc, PHY_CTL1_ADDR, val); 1321.1Sskrll } 1331.1Sskrll 1341.1Sskrll return 0; 1351.1Sskrll} 1361.1Sskrll 1371.1Sskrllconst struct fdtbus_phy_controller_func imx8mq_usbphy_funcs = { 1381.1Sskrll .acquire = imx8mq_usbphy_acquire, 1391.1Sskrll .release = imx8mq_usbphy_release, 1401.1Sskrll .enable = imx8mq_usbphy_enable, 1411.1Sskrll}; 1421.1Sskrll 1431.1Sskrllstatic int 1441.1Sskrllimx8mq_usbphy_match(device_t parent, cfdata_t cf, void *aux) 1451.1Sskrll{ 1461.1Sskrll struct fdt_attach_args * const faa = aux; 1471.1Sskrll 1481.5Sthorpej return of_compatible_match(faa->faa_phandle, compat_data); 1491.1Sskrll} 1501.1Sskrll 1511.1Sskrllstatic void 1521.1Sskrllimx8mq_usbphy_attach(device_t parent, device_t self, void *aux) 1531.1Sskrll{ 1541.1Sskrll struct imx8mq_usbphy_softc * const sc = device_private(self); 1551.1Sskrll struct fdt_attach_args * const faa = aux; 1561.1Sskrll const int phandle = faa->faa_phandle; 1571.1Sskrll bus_addr_t addr; 1581.1Sskrll bus_size_t size; 1591.1Sskrll 1601.1Sskrll sc->sc_dev = self; 1611.1Sskrll sc->sc_bst = faa->faa_bst; 1621.1Sskrll sc->sc_phandle = phandle; 1631.1Sskrll 1641.1Sskrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1651.1Sskrll aprint_error(": couldn't get registers\n"); 1661.1Sskrll return; 1671.1Sskrll } 1681.1Sskrll if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 1691.1Sskrll aprint_error(": couldn't map registers\n"); 1701.1Sskrll return; 1711.1Sskrll } 1721.1Sskrll 1731.1Sskrll /* Enable clocks */ 1741.1Sskrll fdtbus_clock_assign(phandle); 1751.1Sskrll if (fdtbus_clock_enable(phandle, "phy", true) != 0) { 1761.1Sskrll aprint_error(": couldn't enable phy clock\n"); 1771.1Sskrll return; 1781.1Sskrll } 1791.1Sskrll 1801.1Sskrll aprint_naive("\n"); 1811.1Sskrll aprint_normal(": USB PHY\n"); 1821.1Sskrll 1831.1Sskrll fdtbus_register_phy_controller(self, phandle, &imx8mq_usbphy_funcs); 1841.1Sskrll} 185