xref: /openbmc/u-boot/drivers/usb/host/ohci-generic.c (revision cbd2fba1)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
4  */
5 
6 #include <common.h>
7 #include <clk.h>
8 #include <dm.h>
9 #include <dm/ofnode.h>
10 #include <generic-phy.h>
11 #include <reset.h>
12 #include "ohci.h"
13 
14 #if !defined(CONFIG_USB_OHCI_NEW)
15 # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW"
16 #endif
17 
18 struct generic_ohci {
19 	ohci_t ohci;
20 	struct clk *clocks;	/* clock list */
21 	struct reset_ctl *resets; /* reset list */
22 	struct phy phy;
23 	int clock_count;	/* number of clock in clock list */
24 	int reset_count;	/* number of reset in reset list */
25 };
26 
27 static int ohci_setup_phy(struct udevice *dev, int index)
28 {
29 	struct generic_ohci *priv = dev_get_priv(dev);
30 	int ret;
31 
32 	ret = generic_phy_get_by_index(dev, index, &priv->phy);
33 	if (ret) {
34 		if (ret != -ENOENT) {
35 			dev_err(dev, "failed to get usb phy\n");
36 			return ret;
37 		}
38 	} else {
39 		ret = generic_phy_init(&priv->phy);
40 		if (ret) {
41 			dev_err(dev, "failed to init usb phy\n");
42 			return ret;
43 		}
44 
45 		ret = generic_phy_power_on(&priv->phy);
46 		if (ret) {
47 			dev_err(dev, "failed to power on usb phy\n");
48 			return generic_phy_exit(&priv->phy);
49 		}
50 	}
51 
52 	return 0;
53 }
54 
55 static int ohci_shutdown_phy(struct udevice *dev)
56 {
57 	struct generic_ohci *priv = dev_get_priv(dev);
58 	int ret = 0;
59 
60 	if (generic_phy_valid(&priv->phy)) {
61 		ret = generic_phy_power_off(&priv->phy);
62 		if (ret) {
63 			dev_err(dev, "failed to power off usb phy\n");
64 			return ret;
65 		}
66 
67 		ret = generic_phy_exit(&priv->phy);
68 		if (ret) {
69 			dev_err(dev, "failed to power off usb phy\n");
70 			return ret;
71 		}
72 	}
73 
74 	return 0;
75 }
76 
77 static int ohci_usb_probe(struct udevice *dev)
78 {
79 	struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
80 	struct generic_ohci *priv = dev_get_priv(dev);
81 	int i, err, ret, clock_nb, reset_nb;
82 
83 	err = 0;
84 	priv->clock_count = 0;
85 	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
86 	if (clock_nb > 0) {
87 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
88 					    GFP_KERNEL);
89 		if (!priv->clocks)
90 			return -ENOMEM;
91 
92 		for (i = 0; i < clock_nb; i++) {
93 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
94 			if (err < 0)
95 				break;
96 
97 			err = clk_enable(&priv->clocks[i]);
98 			if (err) {
99 				dev_err(dev, "failed to enable clock %d\n", i);
100 				clk_free(&priv->clocks[i]);
101 				goto clk_err;
102 			}
103 			priv->clock_count++;
104 		}
105 	} else if (clock_nb != -ENOENT) {
106 		dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb);
107 		return clock_nb;
108 	}
109 
110 	priv->reset_count = 0;
111 	reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
112 	if (reset_nb > 0) {
113 		priv->resets = devm_kcalloc(dev, reset_nb,
114 					    sizeof(struct reset_ctl),
115 					    GFP_KERNEL);
116 		if (!priv->resets)
117 			return -ENOMEM;
118 
119 		for (i = 0; i < reset_nb; i++) {
120 			err = reset_get_by_index(dev, i, &priv->resets[i]);
121 			if (err < 0)
122 				break;
123 
124 			err = reset_deassert(&priv->resets[i]);
125 			if (err) {
126 				dev_err(dev, "failed to deassert reset %d\n", i);
127 				reset_free(&priv->resets[i]);
128 				goto reset_err;
129 			}
130 			priv->reset_count++;
131 		}
132 	} else if (reset_nb != -ENOENT) {
133 		dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb);
134 		goto clk_err;
135 	}
136 
137 	err = ohci_setup_phy(dev, 0);
138 	if (err)
139 		goto reset_err;
140 
141 	err = ohci_register(dev, regs);
142 	if (err)
143 		goto phy_err;
144 
145 	return 0;
146 
147 phy_err:
148 	ret = ohci_shutdown_phy(dev);
149 	if (ret)
150 		dev_err(dev, "failed to shutdown usb phy\n");
151 
152 reset_err:
153 	ret = reset_release_all(priv->resets, priv->reset_count);
154 	if (ret)
155 		dev_err(dev, "failed to assert all resets\n");
156 clk_err:
157 	ret = clk_release_all(priv->clocks, priv->clock_count);
158 	if (ret)
159 		dev_err(dev, "failed to disable all clocks\n");
160 
161 	return err;
162 }
163 
164 static int ohci_usb_remove(struct udevice *dev)
165 {
166 	struct generic_ohci *priv = dev_get_priv(dev);
167 	int ret;
168 
169 	ret = ohci_deregister(dev);
170 	if (ret)
171 		return ret;
172 
173 	ret = ohci_shutdown_phy(dev);
174 	if (ret)
175 		return ret;
176 
177 	ret = reset_release_all(priv->resets, priv->reset_count);
178 	if (ret)
179 		return ret;
180 
181 	return clk_release_all(priv->clocks, priv->clock_count);
182 }
183 
184 static const struct udevice_id ohci_usb_ids[] = {
185 	{ .compatible = "generic-ohci" },
186 	{ }
187 };
188 
189 U_BOOT_DRIVER(ohci_generic) = {
190 	.name	= "ohci_generic",
191 	.id	= UCLASS_USB,
192 	.of_match = ohci_usb_ids,
193 	.probe = ohci_usb_probe,
194 	.remove = ohci_usb_remove,
195 	.ops	= &ohci_usb_ops,
196 	.priv_auto_alloc_size = sizeof(struct generic_ohci),
197 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
198 };
199