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