Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface
0004  *
0005  * Copyright (C) 2015 Intel Corporation
0006  *
0007  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/time64.h>
0012 #include <linux/ulpi/regs.h>
0013 
0014 #include "core.h"
0015 #include "io.h"
0016 
0017 #define DWC3_ULPI_ADDR(a) \
0018         ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
0019         DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
0020         DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
0021 
0022 #define DWC3_ULPI_BASE_DELAY    DIV_ROUND_UP(NSEC_PER_SEC, 60000000L)
0023 
0024 static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read)
0025 {
0026     unsigned long ns = 5L * DWC3_ULPI_BASE_DELAY;
0027     unsigned int count = 10000;
0028     u32 reg;
0029 
0030     if (addr >= ULPI_EXT_VENDOR_SPECIFIC)
0031         ns += DWC3_ULPI_BASE_DELAY;
0032 
0033     if (read)
0034         ns += DWC3_ULPI_BASE_DELAY;
0035 
0036     reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
0037     if (reg & DWC3_GUSB2PHYCFG_SUSPHY)
0038         usleep_range(1000, 1200);
0039 
0040     while (count--) {
0041         ndelay(ns);
0042         reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
0043         if (reg & DWC3_GUSB2PHYACC_DONE)
0044             return 0;
0045         cpu_relax();
0046     }
0047 
0048     return -ETIMEDOUT;
0049 }
0050 
0051 static int dwc3_ulpi_read(struct device *dev, u8 addr)
0052 {
0053     struct dwc3 *dwc = dev_get_drvdata(dev);
0054     u32 reg;
0055     int ret;
0056 
0057     reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
0058     dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
0059 
0060     ret = dwc3_ulpi_busyloop(dwc, addr, true);
0061     if (ret)
0062         return ret;
0063 
0064     reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
0065 
0066     return DWC3_GUSB2PHYACC_DATA(reg);
0067 }
0068 
0069 static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
0070 {
0071     struct dwc3 *dwc = dev_get_drvdata(dev);
0072     u32 reg;
0073 
0074     reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
0075     reg |= DWC3_GUSB2PHYACC_WRITE | val;
0076     dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
0077 
0078     return dwc3_ulpi_busyloop(dwc, addr, false);
0079 }
0080 
0081 static const struct ulpi_ops dwc3_ulpi_ops = {
0082     .read = dwc3_ulpi_read,
0083     .write = dwc3_ulpi_write,
0084 };
0085 
0086 int dwc3_ulpi_init(struct dwc3 *dwc)
0087 {
0088     /* Register the interface */
0089     dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
0090     if (IS_ERR(dwc->ulpi)) {
0091         dev_err(dwc->dev, "failed to register ULPI interface");
0092         return PTR_ERR(dwc->ulpi);
0093     }
0094 
0095     return 0;
0096 }
0097 
0098 void dwc3_ulpi_exit(struct dwc3 *dwc)
0099 {
0100     if (dwc->ulpi) {
0101         ulpi_unregister_interface(dwc->ulpi);
0102         dwc->ulpi = NULL;
0103     }
0104 }