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