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