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