1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
4  */
5 
6 #include <clk.h>
7 #include <log.h>
8 #include <dm/device_compat.h>
9 #include <dm/devres.h>
10 #include <dm/ofnode.h>
11 #include <generic-phy.h>
12 #include <reset.h>
13 #include <asm/io.h>
14 #include <dm.h>
15 #include "ehci.h"
16 #include <power/regulator.h>
17 
18 /*
19  * Even though here we don't explicitly use "struct ehci_ctrl"
20  * ehci_register() expects it to be the first thing that resides in
21  * device's private data.
22  */
23 struct generic_ehci {
24 	struct ehci_ctrl ctrl;
25 	struct clk_bulk clocks;
26 	struct reset_ctl_bulk resets;
27 	struct phy phy;
28 	struct udevice *vbus_supply;
29 };
30 
ehci_enable_vbus_supply(struct udevice * dev)31 static int ehci_enable_vbus_supply(struct udevice *dev)
32 {
33 	struct generic_ehci *priv = dev_get_priv(dev);
34 	int ret;
35 
36 	ret = device_get_supply_regulator(dev, "vbus-supply",
37 					  &priv->vbus_supply);
38 	if (ret && ret != -ENOENT)
39 		return ret;
40 
41 	ret = regulator_set_enable_if_allowed(priv->vbus_supply, true);
42 	if (ret && ret != -ENOSYS) {
43 		dev_err(dev, "Error enabling VBUS supply (ret=%d)\n", ret);
44 		return ret;
45 	}
46 
47 	return 0;
48 }
49 
ehci_disable_vbus_supply(struct generic_ehci * priv)50 static int ehci_disable_vbus_supply(struct generic_ehci *priv)
51 {
52 	int ret;
53 
54 	ret = regulator_set_enable_if_allowed(priv->vbus_supply, false);
55 	if (ret && ret != -ENOSYS)
56 		return ret;
57 
58 	return 0;
59 }
60 
ehci_usb_probe(struct udevice * dev)61 static int ehci_usb_probe(struct udevice *dev)
62 {
63 	struct generic_ehci *priv = dev_get_priv(dev);
64 	struct ehci_hccr *hccr;
65 	struct ehci_hcor *hcor;
66 	int err, ret;
67 
68 	err = 0;
69 	ret = clk_get_bulk(dev, &priv->clocks);
70 	if (ret && ret != -ENOENT) {
71 		dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
72 		return ret;
73 	}
74 
75 	err = clk_enable_bulk(&priv->clocks);
76 	if (err) {
77 		dev_err(dev, "Failed to enable clocks (err=%d)\n", err);
78 		goto clk_err;
79 	}
80 
81 	err = reset_get_bulk(dev, &priv->resets);
82 	if (err && err != -ENOENT) {
83 		dev_err(dev, "Failed to get resets (err=%d)\n", err);
84 		goto clk_err;
85 	}
86 
87 	err = reset_deassert_bulk(&priv->resets);
88 	if (err) {
89 		dev_err(dev, "Failed to get deassert resets (err=%d)\n", err);
90 		goto reset_err;
91 	}
92 
93 	err = ehci_enable_vbus_supply(dev);
94 	if (err)
95 		goto reset_err;
96 
97 	err = generic_setup_phy(dev, &priv->phy, 0, PHY_MODE_USB_HOST, 0);
98 	if (err)
99 		goto regulator_err;
100 
101 	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
102 	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
103 				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
104 
105 	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
106 	if (err)
107 		goto phy_err;
108 
109 	return 0;
110 
111 phy_err:
112 	ret = generic_shutdown_phy(&priv->phy);
113 	if (ret)
114 		dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret);
115 
116 regulator_err:
117 	ret = ehci_disable_vbus_supply(priv);
118 	if (ret)
119 		dev_err(dev, "failed to disable VBUS supply (ret=%d)\n", ret);
120 
121 reset_err:
122 	ret = reset_release_bulk(&priv->resets);
123 	if (ret)
124 		dev_err(dev, "failed to release resets (ret=%d)\n", ret);
125 clk_err:
126 	ret = clk_release_bulk(&priv->clocks);
127 	if (ret)
128 		dev_err(dev, "failed to release clocks (ret=%d)\n", ret);
129 
130 	return err;
131 }
132 
ehci_usb_remove(struct udevice * dev)133 static int ehci_usb_remove(struct udevice *dev)
134 {
135 	struct generic_ehci *priv = dev_get_priv(dev);
136 	int ret;
137 
138 	ret = ehci_deregister(dev);
139 	if (ret)
140 		return ret;
141 
142 	ret = generic_shutdown_phy(&priv->phy);
143 	if (ret)
144 		return ret;
145 
146 	ret = ehci_disable_vbus_supply(priv);
147 	if (ret)
148 		return ret;
149 
150 	ret = reset_release_bulk(&priv->resets);
151 	if (ret)
152 		return ret;
153 
154 	return clk_release_bulk(&priv->clocks);
155 }
156 
157 static const struct udevice_id ehci_usb_ids[] = {
158 	{ .compatible = "generic-ehci" },
159 	{ }
160 };
161 
162 U_BOOT_DRIVER(ehci_generic) = {
163 	.name	= "ehci_generic",
164 	.id	= UCLASS_USB,
165 	.of_match = ehci_usb_ids,
166 	.probe = ehci_usb_probe,
167 	.remove = ehci_usb_remove,
168 	.ops	= &ehci_usb_ops,
169 	.priv_auto	= sizeof(struct generic_ehci),
170 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
171 };
172