xref: /linux/drivers/usb/dwc3/ulpi.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
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 
10 #include <linux/delay.h>
11 #include <linux/time64.h>
12 #include <linux/ulpi/regs.h>
13 #include <linux/ulpi/driver.h>
14 
15 #include "core.h"
16 #include "io.h"
17 
18 #define USB_VENDOR_MICROCHIP 0x0424
19 
20 #define DWC3_ULPI_ADDR(a) \
21 		((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
22 		DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
23 		DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
24 
25 #define DWC3_ULPI_BASE_DELAY	DIV_ROUND_UP(NSEC_PER_SEC, 60000000L)
26 
27 static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read)
28 {
29 	unsigned long ns = 5L * DWC3_ULPI_BASE_DELAY;
30 	unsigned int count = 10000;
31 	u32 reg;
32 
33 	if (addr >= ULPI_EXT_VENDOR_SPECIFIC)
34 		ns += DWC3_ULPI_BASE_DELAY;
35 
36 	if (read)
37 		ns += DWC3_ULPI_BASE_DELAY;
38 
39 	reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
40 	if (reg & DWC3_GUSB2PHYCFG_SUSPHY)
41 		usleep_range(1000, 1200);
42 
43 	while (count--) {
44 		ndelay(ns);
45 		reg = dwc3_readl(dwc, DWC3_GUSB2PHYACC(0));
46 		if (reg & DWC3_GUSB2PHYACC_DONE)
47 			return 0;
48 		cpu_relax();
49 	}
50 
51 	return -ETIMEDOUT;
52 }
53 
54 static int dwc3_ulpi_read(struct device *dev, u8 addr)
55 {
56 	struct dwc3 *dwc = dev_get_drvdata(dev);
57 	u32 reg;
58 	int ret;
59 
60 	reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
61 	dwc3_writel(dwc, DWC3_GUSB2PHYACC(0), reg);
62 
63 	ret = dwc3_ulpi_busyloop(dwc, addr, true);
64 	if (ret)
65 		return ret;
66 
67 	reg = dwc3_readl(dwc, DWC3_GUSB2PHYACC(0));
68 
69 	return DWC3_GUSB2PHYACC_DATA(reg);
70 }
71 
72 static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
73 {
74 	struct dwc3 *dwc = dev_get_drvdata(dev);
75 	u32 reg;
76 
77 	reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
78 	reg |= DWC3_GUSB2PHYACC_WRITE | val;
79 	dwc3_writel(dwc, DWC3_GUSB2PHYACC(0), reg);
80 
81 	return dwc3_ulpi_busyloop(dwc, addr, false);
82 }
83 
84 static const struct ulpi_ops dwc3_ulpi_ops = {
85 	.read = dwc3_ulpi_read,
86 	.write = dwc3_ulpi_write,
87 };
88 
89 static void dwc3_ulpi_detect_config(struct dwc3 *dwc)
90 {
91 	struct ulpi *ulpi = dwc->ulpi;
92 
93 	switch (ulpi->id.vendor) {
94 	case USB_VENDOR_MICROCHIP:
95 		switch (ulpi->id.product) {
96 		case 0x0009:
97 			/* Microchip USB3340 ULPI PHY */
98 			dwc->enable_usb2_transceiver_delay = true;
99 			break;
100 		default:
101 			break;
102 		}
103 		break;
104 	default:
105 		break;
106 	}
107 }
108 
109 int dwc3_ulpi_init(struct dwc3 *dwc)
110 {
111 	/* Register the interface */
112 	dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
113 	if (IS_ERR(dwc->ulpi)) {
114 		dev_err(dwc->dev, "failed to register ULPI interface");
115 		return PTR_ERR(dwc->ulpi);
116 	}
117 
118 	dwc3_ulpi_detect_config(dwc);
119 
120 	return 0;
121 }
122 
123 void dwc3_ulpi_exit(struct dwc3 *dwc)
124 {
125 	if (dwc->ulpi) {
126 		ulpi_unregister_interface(dwc->ulpi);
127 		dwc->ulpi = NULL;
128 	}
129 }
130