]> git.sur5r.net Git - u-boot/blob - drivers/usb/host/ehci-generic.c
b012d8651f1239c2a4048d3d5369c3eb08e23d4d
[u-boot] / drivers / usb / host / ehci-generic.c
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/ofnode.h>
10 #include <generic-phy.h>
11 #include <reset.h>
12 #include <asm/io.h>
13 #include <dm.h>
14 #include "ehci.h"
15
16 /*
17  * Even though here we don't explicitly use "struct ehci_ctrl"
18  * ehci_register() expects it to be the first thing that resides in
19  * device's private data.
20  */
21 struct generic_ehci {
22         struct ehci_ctrl ctrl;
23         struct clk *clocks;
24         struct reset_ctl *resets;
25         struct phy phy;
26         int clock_count;
27         int reset_count;
28 };
29
30 static int ehci_setup_phy(struct udevice *dev, int index)
31 {
32         struct generic_ehci *priv = dev_get_priv(dev);
33         int ret;
34
35         ret = generic_phy_get_by_index(dev, index, &priv->phy);
36         if (ret) {
37                 if (ret != -ENOENT) {
38                         dev_err(dev, "failed to get usb phy\n");
39                         return ret;
40                 }
41         } else {
42                 ret = generic_phy_init(&priv->phy);
43                 if (ret) {
44                         dev_err(dev, "failed to init usb phy\n");
45                         return ret;
46                 }
47
48                 ret = generic_phy_power_on(&priv->phy);
49                 if (ret) {
50                         dev_err(dev, "failed to power on usb phy\n");
51                         return generic_phy_exit(&priv->phy);
52                 }
53         }
54
55         return 0;
56 }
57
58 static int ehci_shutdown_phy(struct udevice *dev)
59 {
60         struct generic_ehci *priv = dev_get_priv(dev);
61         int ret = 0;
62
63         if (generic_phy_valid(&priv->phy)) {
64                 ret = generic_phy_power_off(&priv->phy);
65                 if (ret) {
66                         dev_err(dev, "failed to power off usb phy\n");
67                         return ret;
68                 }
69
70                 ret = generic_phy_exit(&priv->phy);
71                 if (ret) {
72                         dev_err(dev, "failed to power off usb phy\n");
73                         return ret;
74                 }
75         }
76
77         return 0;
78 }
79
80 static int ehci_usb_probe(struct udevice *dev)
81 {
82         struct generic_ehci *priv = dev_get_priv(dev);
83         struct ehci_hccr *hccr;
84         struct ehci_hcor *hcor;
85         int i, err, ret, clock_nb, reset_nb;
86
87         err = 0;
88         priv->clock_count = 0;
89         clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
90                                                   "#clock-cells");
91         if (clock_nb > 0) {
92                 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
93                                             GFP_KERNEL);
94                 if (!priv->clocks)
95                         return -ENOMEM;
96
97                 for (i = 0; i < clock_nb; i++) {
98                         err = clk_get_by_index(dev, i, &priv->clocks[i]);
99
100                         if (err < 0)
101                                 break;
102                         err = clk_enable(&priv->clocks[i]);
103                         if (err) {
104                                 dev_err(dev, "failed to enable clock %d\n", i);
105                                 clk_free(&priv->clocks[i]);
106                                 goto clk_err;
107                         }
108                         priv->clock_count++;
109                 }
110         } else {
111                 if (clock_nb != -ENOENT) {
112                         dev_err(dev, "failed to get clock phandle(%d)\n",
113                                 clock_nb);
114                         return clock_nb;
115                 }
116         }
117
118         priv->reset_count = 0;
119         reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
120                                                   "#reset-cells");
121         if (reset_nb > 0) {
122                 priv->resets = devm_kcalloc(dev, reset_nb,
123                                             sizeof(struct reset_ctl),
124                                             GFP_KERNEL);
125                 if (!priv->resets)
126                         return -ENOMEM;
127
128                 for (i = 0; i < reset_nb; i++) {
129                         err = reset_get_by_index(dev, i, &priv->resets[i]);
130                         if (err < 0)
131                                 break;
132
133                         if (reset_deassert(&priv->resets[i])) {
134                                 dev_err(dev, "failed to deassert reset %d\n",
135                                         i);
136                                 reset_free(&priv->resets[i]);
137                                 goto reset_err;
138                         }
139                         priv->reset_count++;
140                 }
141         } else {
142                 if (reset_nb != -ENOENT) {
143                         dev_err(dev, "failed to get reset phandle(%d)\n",
144                                 reset_nb);
145                         goto clk_err;
146                 }
147         }
148
149         err = ehci_setup_phy(dev, 0);
150         if (err)
151                 goto reset_err;
152
153         hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
154         hcor = (struct ehci_hcor *)((uintptr_t)hccr +
155                                     HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
156
157         err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
158         if (err)
159                 goto phy_err;
160
161         return 0;
162
163 phy_err:
164         ret = ehci_shutdown_phy(dev);
165         if (ret)
166                 dev_err(dev, "failed to shutdown usb phy\n");
167
168 reset_err:
169         ret = reset_release_all(priv->resets, priv->reset_count);
170         if (ret)
171                 dev_err(dev, "failed to assert all resets\n");
172 clk_err:
173         ret = clk_release_all(priv->clocks, priv->clock_count);
174         if (ret)
175                 dev_err(dev, "failed to disable all clocks\n");
176
177         return err;
178 }
179
180 static int ehci_usb_remove(struct udevice *dev)
181 {
182         struct generic_ehci *priv = dev_get_priv(dev);
183         int ret;
184
185         ret = ehci_deregister(dev);
186         if (ret)
187                 return ret;
188
189         ret = ehci_shutdown_phy(dev);
190         if (ret)
191                 return ret;
192
193         ret =  reset_release_all(priv->resets, priv->reset_count);
194         if (ret)
195                 return ret;
196
197         return clk_release_all(priv->clocks, priv->clock_count);
198 }
199
200 static const struct udevice_id ehci_usb_ids[] = {
201         { .compatible = "generic-ehci" },
202         { }
203 };
204
205 U_BOOT_DRIVER(ehci_generic) = {
206         .name   = "ehci_generic",
207         .id     = UCLASS_USB,
208         .of_match = ehci_usb_ids,
209         .probe = ehci_usb_probe,
210         .remove = ehci_usb_remove,
211         .ops    = &ehci_usb_ops,
212         .priv_auto_alloc_size = sizeof(struct generic_ehci),
213         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
214 };