xref: /openbmc/linux/drivers/usb/chipidea/ulpi.c (revision 5d0e4d78)
1 /*
2  * Copyright (c) 2016 Linaro Ltd.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 
14 #include <linux/device.h>
15 #include <linux/usb/chipidea.h>
16 #include <linux/ulpi/interface.h>
17 
18 #include "ci.h"
19 
20 #define ULPI_WAKEUP		BIT(31)
21 #define ULPI_RUN		BIT(30)
22 #define ULPI_WRITE		BIT(29)
23 #define ULPI_SYNC_STATE		BIT(27)
24 #define ULPI_ADDR(n)		((n) << 16)
25 #define ULPI_DATA(n)		(n)
26 
27 static int ci_ulpi_wait(struct ci_hdrc *ci, u32 mask)
28 {
29 	unsigned long usec = 10000;
30 
31 	while (usec--) {
32 		if (!hw_read(ci, OP_ULPI_VIEWPORT, mask))
33 			return 0;
34 
35 		udelay(1);
36 	}
37 
38 	return -ETIMEDOUT;
39 }
40 
41 static int ci_ulpi_read(struct device *dev, u8 addr)
42 {
43 	struct ci_hdrc *ci = dev_get_drvdata(dev);
44 	int ret;
45 
46 	hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
47 	ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
48 	if (ret)
49 		return ret;
50 
51 	hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_RUN | ULPI_ADDR(addr));
52 	ret = ci_ulpi_wait(ci, ULPI_RUN);
53 	if (ret)
54 		return ret;
55 
56 	return hw_read(ci, OP_ULPI_VIEWPORT, GENMASK(15, 8)) >> 8;
57 }
58 
59 static int ci_ulpi_write(struct device *dev, u8 addr, u8 val)
60 {
61 	struct ci_hdrc *ci = dev_get_drvdata(dev);
62 	int ret;
63 
64 	hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
65 	ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
66 	if (ret)
67 		return ret;
68 
69 	hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff,
70 		 ULPI_RUN | ULPI_WRITE | ULPI_ADDR(addr) | val);
71 	return ci_ulpi_wait(ci, ULPI_RUN);
72 }
73 
74 int ci_ulpi_init(struct ci_hdrc *ci)
75 {
76 	if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI)
77 		return 0;
78 
79 	/*
80 	 * Set PORTSC correctly so we can read/write ULPI registers for
81 	 * identification purposes
82 	 */
83 	hw_phymode_configure(ci);
84 
85 	ci->ulpi_ops.read = ci_ulpi_read;
86 	ci->ulpi_ops.write = ci_ulpi_write;
87 	ci->ulpi = ulpi_register_interface(ci->dev, &ci->ulpi_ops);
88 	if (IS_ERR(ci->ulpi))
89 		dev_err(ci->dev, "failed to register ULPI interface");
90 
91 	return PTR_ERR_OR_ZERO(ci->ulpi);
92 }
93 
94 void ci_ulpi_exit(struct ci_hdrc *ci)
95 {
96 	if (ci->ulpi) {
97 		ulpi_unregister_interface(ci->ulpi);
98 		ci->ulpi = NULL;
99 	}
100 }
101 
102 int ci_ulpi_resume(struct ci_hdrc *ci)
103 {
104 	int cnt = 100000;
105 
106 	while (cnt-- > 0) {
107 		if (hw_read(ci, OP_ULPI_VIEWPORT, ULPI_SYNC_STATE))
108 			return 0;
109 		udelay(1);
110 	}
111 
112 	return -ETIMEDOUT;
113 }
114