1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/module.h>
4#include <linux/platform_device.h>
5#include <linux/regmap.h>
6
7#include <linux/slab.h>
8#include <linux/of.h>
9#include <linux/io.h>
10#include <linux/usb/phy_companion.h>
11#include <linux/clk.h>
12#include <linux/err.h>
13#include <linux/pm_runtime.h>
14#include <linux/delay.h>
15#include <linux/phy/phy.h>
16
17#include <linux/mfd/syscon.h>
18
19/*
20 * TRM has two sets of USB_CTRL registers.. The correct register bits
21 * are in TRM section 24.9.8.2 USB_CTRL Register. The TRM documents the
22 * phy as being SR70LX Synopsys USB 2.0 OTG nanoPHY. It also seems at
23 * least dm816x rev c ignores writes to USB_CTRL register, but the TI
24 * kernel is writing to those so it's possible that later revisions
25 * have worknig USB_CTRL register.
26 *
27 * Also note that At least USB_CTRL register seems to be dm816x specific
28 * according to the TRM. It's possible that USBPHY_CTRL is more generic,
29 * but that would have to be checked against the SR70LX documentation
30 * which does not seem to be publicly available.
31 *
32 * Finally, the phy on dm814x and am335x is different from dm816x.
33 */
34#define DM816X_USB_CTRL_PHYCLKSRC BIT(8) /* 1 = PLL ref clock */
35#define DM816X_USB_CTRL_PHYSLEEP1 BIT(1) /* Enable the first phy */
36#define DM816X_USB_CTRL_PHYSLEEP0 BIT(0) /* Enable the second phy */
37
38#define DM816X_USBPHY_CTRL_TXRISETUNE 1
39#define DM816X_USBPHY_CTRL_TXVREFTUNE 0xc
40#define DM816X_USBPHY_CTRL_TXPREEMTUNE 0x2
41
42struct dm816x_usb_phy {
43 struct regmap *syscon;
44 struct device *dev;
45 unsigned int instance;
46 struct clk *refclk;
47 struct usb_phy phy;
48 unsigned int usb_ctrl; /* Shared between phy0 and phy1 */
49 unsigned int usbphy_ctrl;
50};
51
52static int dm816x_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host)
53{
54 otg->host = host;
55 if (!host)
56 otg->state = OTG_STATE_UNDEFINED;
57
58 return 0;
59}
60
61static int dm816x_usb_phy_set_peripheral(struct usb_otg *otg,
62 struct usb_gadget *gadget)
63{
64 otg->gadget = gadget;
65 if (!gadget)
66 otg->state = OTG_STATE_UNDEFINED;
67
68 return 0;
69}
70
71static int dm816x_usb_phy_init(struct phy *x)
72{
73 struct dm816x_usb_phy *phy = phy_get_drvdata(phy: x);
74 unsigned int val;
75
76 if (clk_get_rate(clk: phy->refclk) != 24000000)
77 dev_warn(phy->dev, "nonstandard phy refclk\n");
78
79 /* Set PLL ref clock and put phys to sleep */
80 regmap_update_bits(map: phy->syscon, reg: phy->usb_ctrl,
81 DM816X_USB_CTRL_PHYCLKSRC |
82 DM816X_USB_CTRL_PHYSLEEP1 |
83 DM816X_USB_CTRL_PHYSLEEP0,
84 val: 0);
85 regmap_read(map: phy->syscon, reg: phy->usb_ctrl, val: &val);
86 if ((val & 3) != 0)
87 dev_info(phy->dev,
88 "Working dm816x USB_CTRL! (0x%08x)\n",
89 val);
90
91 /*
92 * TI kernel sets these values for "symmetrical eye diagram and
93 * better signal quality" so let's assume somebody checked the
94 * values with a scope and set them here too.
95 */
96 regmap_read(map: phy->syscon, reg: phy->usbphy_ctrl, val: &val);
97 val |= DM816X_USBPHY_CTRL_TXRISETUNE |
98 DM816X_USBPHY_CTRL_TXVREFTUNE |
99 DM816X_USBPHY_CTRL_TXPREEMTUNE;
100 regmap_write(map: phy->syscon, reg: phy->usbphy_ctrl, val);
101
102 return 0;
103}
104
105static const struct phy_ops ops = {
106 .init = dm816x_usb_phy_init,
107 .owner = THIS_MODULE,
108};
109
110static int __maybe_unused dm816x_usb_phy_runtime_suspend(struct device *dev)
111{
112 struct dm816x_usb_phy *phy = dev_get_drvdata(dev);
113 unsigned int mask, val;
114 int error = 0;
115
116 mask = BIT(phy->instance);
117 val = ~BIT(phy->instance);
118 error = regmap_update_bits(map: phy->syscon, reg: phy->usb_ctrl,
119 mask, val);
120 if (error)
121 dev_err(phy->dev, "phy%i failed to power off\n",
122 phy->instance);
123 clk_disable(clk: phy->refclk);
124
125 return 0;
126}
127
128static int __maybe_unused dm816x_usb_phy_runtime_resume(struct device *dev)
129{
130 struct dm816x_usb_phy *phy = dev_get_drvdata(dev);
131 unsigned int mask, val;
132 int error;
133
134 error = clk_enable(clk: phy->refclk);
135 if (error)
136 return error;
137
138 /*
139 * Note that at least dm816x rev c does not seem to do
140 * anything with the USB_CTRL register. But let's follow
141 * what the TI tree is doing in case later revisions use
142 * USB_CTRL.
143 */
144 mask = BIT(phy->instance);
145 val = BIT(phy->instance);
146 error = regmap_update_bits(map: phy->syscon, reg: phy->usb_ctrl,
147 mask, val);
148 if (error) {
149 dev_err(phy->dev, "phy%i failed to power on\n",
150 phy->instance);
151 clk_disable(clk: phy->refclk);
152 return error;
153 }
154
155 return 0;
156}
157
158static UNIVERSAL_DEV_PM_OPS(dm816x_usb_phy_pm_ops,
159 dm816x_usb_phy_runtime_suspend,
160 dm816x_usb_phy_runtime_resume,
161 NULL);
162
163static const struct of_device_id dm816x_usb_phy_id_table[] = {
164 {
165 .compatible = "ti,dm8168-usb-phy",
166 },
167 {},
168};
169MODULE_DEVICE_TABLE(of, dm816x_usb_phy_id_table);
170
171static int dm816x_usb_phy_probe(struct platform_device *pdev)
172{
173 struct dm816x_usb_phy *phy;
174 struct resource *res;
175 struct phy *generic_phy;
176 struct phy_provider *phy_provider;
177 struct usb_otg *otg;
178 int error;
179
180 phy = devm_kzalloc(dev: &pdev->dev, size: sizeof(*phy), GFP_KERNEL);
181 if (!phy)
182 return -ENOMEM;
183
184 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
185 if (!res)
186 return -ENOENT;
187
188 phy->syscon = syscon_regmap_lookup_by_phandle(np: pdev->dev.of_node,
189 property: "syscon");
190 if (IS_ERR(ptr: phy->syscon))
191 return PTR_ERR(ptr: phy->syscon);
192
193 /*
194 * According to sprs614e.pdf, the first usb_ctrl is shared and
195 * the second instance for usb_ctrl is reserved.. Also the
196 * register bits are different from earlier TRMs.
197 */
198 phy->usb_ctrl = 0x20;
199 phy->usbphy_ctrl = (res->start & 0xff) + 4;
200 if (phy->usbphy_ctrl == 0x2c)
201 phy->instance = 1;
202
203 otg = devm_kzalloc(dev: &pdev->dev, size: sizeof(*otg), GFP_KERNEL);
204 if (!otg)
205 return -ENOMEM;
206
207 phy->dev = &pdev->dev;
208 phy->phy.dev = phy->dev;
209 phy->phy.label = "dm8168_usb_phy";
210 phy->phy.otg = otg;
211 phy->phy.type = USB_PHY_TYPE_USB2;
212 otg->set_host = dm816x_usb_phy_set_host;
213 otg->set_peripheral = dm816x_usb_phy_set_peripheral;
214 otg->usb_phy = &phy->phy;
215
216 platform_set_drvdata(pdev, data: phy);
217
218 phy->refclk = devm_clk_get(dev: phy->dev, id: "refclk");
219 if (IS_ERR(ptr: phy->refclk))
220 return PTR_ERR(ptr: phy->refclk);
221 error = clk_prepare(clk: phy->refclk);
222 if (error)
223 return error;
224
225 pm_runtime_enable(dev: phy->dev);
226 generic_phy = devm_phy_create(dev: phy->dev, NULL, ops: &ops);
227 if (IS_ERR(ptr: generic_phy)) {
228 error = PTR_ERR(ptr: generic_phy);
229 goto clk_unprepare;
230 }
231
232 phy_set_drvdata(phy: generic_phy, data: phy);
233
234 phy_provider = devm_of_phy_provider_register(phy->dev,
235 of_phy_simple_xlate);
236 if (IS_ERR(ptr: phy_provider)) {
237 error = PTR_ERR(ptr: phy_provider);
238 goto clk_unprepare;
239 }
240
241 usb_add_phy_dev(&phy->phy);
242
243 return 0;
244
245clk_unprepare:
246 pm_runtime_disable(dev: phy->dev);
247 clk_unprepare(clk: phy->refclk);
248 return error;
249}
250
251static void dm816x_usb_phy_remove(struct platform_device *pdev)
252{
253 struct dm816x_usb_phy *phy = platform_get_drvdata(pdev);
254
255 usb_remove_phy(&phy->phy);
256 pm_runtime_disable(dev: phy->dev);
257 clk_unprepare(clk: phy->refclk);
258}
259
260static struct platform_driver dm816x_usb_phy_driver = {
261 .probe = dm816x_usb_phy_probe,
262 .remove_new = dm816x_usb_phy_remove,
263 .driver = {
264 .name = "dm816x-usb-phy",
265 .pm = &dm816x_usb_phy_pm_ops,
266 .of_match_table = dm816x_usb_phy_id_table,
267 },
268};
269
270module_platform_driver(dm816x_usb_phy_driver);
271
272MODULE_ALIAS("platform:dm816x_usb");
273MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
274MODULE_DESCRIPTION("dm816x usb phy driver");
275MODULE_LICENSE("GPL v2");
276

source code of linux/drivers/phy/ti/phy-dm816x-usb.c