1 // SPDX-License-Identifier: GPL-2.0 2 /** 3 * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface 4 * 5 * Copyright (C) 2015 Intel Corporation 6 * 7 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 #include <linux/ulpi/regs.h> 15 16 #include "core.h" 17 #include "io.h" 18 19 #define DWC3_ULPI_ADDR(a) \ 20 ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \ 21 DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \ 22 DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a)) 23 24 static int dwc3_ulpi_busyloop(struct dwc3 *dwc) 25 { 26 unsigned count = 1000; 27 u32 reg; 28 29 while (count--) { 30 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); 31 if (!(reg & DWC3_GUSB2PHYACC_BUSY)) 32 return 0; 33 cpu_relax(); 34 } 35 36 return -ETIMEDOUT; 37 } 38 39 static int dwc3_ulpi_read(struct device *dev, u8 addr) 40 { 41 struct dwc3 *dwc = dev_get_drvdata(dev); 42 u32 reg; 43 int ret; 44 45 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 46 if (reg & DWC3_GUSB2PHYCFG_SUSPHY) { 47 reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 48 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 49 } 50 51 reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); 52 dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); 53 54 ret = dwc3_ulpi_busyloop(dwc); 55 if (ret) 56 return ret; 57 58 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); 59 60 return DWC3_GUSB2PHYACC_DATA(reg); 61 } 62 63 static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val) 64 { 65 struct dwc3 *dwc = dev_get_drvdata(dev); 66 u32 reg; 67 68 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 69 if (reg & DWC3_GUSB2PHYCFG_SUSPHY) { 70 reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 71 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 72 } 73 74 reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); 75 reg |= DWC3_GUSB2PHYACC_WRITE | val; 76 dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); 77 78 return dwc3_ulpi_busyloop(dwc); 79 } 80 81 static const struct ulpi_ops dwc3_ulpi_ops = { 82 .read = dwc3_ulpi_read, 83 .write = dwc3_ulpi_write, 84 }; 85 86 int dwc3_ulpi_init(struct dwc3 *dwc) 87 { 88 /* Register the interface */ 89 dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops); 90 if (IS_ERR(dwc->ulpi)) { 91 dev_err(dwc->dev, "failed to register ULPI interface"); 92 return PTR_ERR(dwc->ulpi); 93 } 94 95 return 0; 96 } 97 98 void dwc3_ulpi_exit(struct dwc3 *dwc) 99 { 100 if (dwc->ulpi) { 101 ulpi_unregister_interface(dwc->ulpi); 102 dwc->ulpi = NULL; 103 } 104 } 105