usb: host: ehci-generic: add error path and .remove callback
[platform/kernel/u-boot.git] / 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 <reset.h>
11 #include <asm/io.h>
12 #include <dm.h>
13 #include "ehci.h"
14
15 /*
16  * Even though here we don't explicitly use "struct ehci_ctrl"
17  * ehci_register() expects it to be the first thing that resides in
18  * device's private data.
19  */
20 struct generic_ehci {
21         struct ehci_ctrl ctrl;
22         struct clk *clocks;
23         struct reset_ctl *resets;
24         int clock_count;
25         int reset_count;
26 };
27
28 static int ehci_usb_probe(struct udevice *dev)
29 {
30         struct generic_ehci *priv = dev_get_priv(dev);
31         struct ehci_hccr *hccr;
32         struct ehci_hcor *hcor;
33         int i, err, ret, clock_nb, reset_nb;
34
35         err = 0;
36         priv->clock_count = 0;
37         clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
38                                                   "#clock-cells");
39         if (clock_nb > 0) {
40                 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
41                                             GFP_KERNEL);
42                 if (!priv->clocks)
43                         return -ENOMEM;
44
45                 for (i = 0; i < clock_nb; i++) {
46                         err = clk_get_by_index(dev, i, &priv->clocks[i]);
47
48                         if (err < 0)
49                                 break;
50                         err = clk_enable(&priv->clocks[i]);
51                         if (err) {
52                                 error("failed to enable clock %d\n", i);
53                                 clk_free(&priv->clocks[i]);
54                                 goto clk_err;
55                         }
56                         priv->clock_count++;
57                 }
58         } else {
59                 if (clock_nb != -ENOENT) {
60                         error("failed to get clock phandle(%d)\n", clock_nb);
61                         return clock_nb;
62                 }
63         }
64
65         priv->reset_count = 0;
66         reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
67                                                   "#reset-cells");
68         if (reset_nb > 0) {
69                 priv->resets = devm_kcalloc(dev, reset_nb,
70                                             sizeof(struct reset_ctl),
71                                             GFP_KERNEL);
72                 if (!priv->resets)
73                         return -ENOMEM;
74
75                 for (i = 0; i < reset_nb; i++) {
76                         err = reset_get_by_index(dev, i, &priv->resets[i]);
77                         if (err < 0)
78                                 break;
79
80                         if (reset_deassert(&priv->resets[i])) {
81                                 error("failed to deassert reset %d\n", i);
82                                 reset_free(&priv->resets[i]);
83                                 goto reset_err;
84                         }
85                         priv->reset_count++;
86                 }
87         } else {
88                 if (reset_nb != -ENOENT) {
89                         error("failed to get reset phandle(%d)\n", reset_nb);
90                         goto clk_err;
91                 }
92         }
93
94         hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE);
95         hcor = (struct ehci_hcor *)((uintptr_t)hccr +
96                                     HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
97
98         err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
99         if (err)
100                 goto reset_err;
101
102         return 0;
103
104 reset_err:
105         ret = reset_release_all(priv->resets, priv->reset_count);
106         if (ret)
107                 error("failed to assert all resets\n");
108 clk_err:
109         ret = clk_release_all(priv->clocks, priv->clock_count);
110         if (ret)
111                 error("failed to disable all clocks\n");
112
113         return err;
114 }
115
116 static int ehci_usb_remove(struct udevice *dev)
117 {
118         struct generic_ehci *priv = dev_get_priv(dev);
119         int ret;
120
121         ret = ehci_deregister(dev);
122         if (ret)
123                 return ret;
124
125         ret =  reset_release_all(priv->resets, priv->reset_count);
126         if (ret)
127                 return ret;
128
129         return clk_release_all(priv->clocks, priv->clock_count);
130 }
131
132 static const struct udevice_id ehci_usb_ids[] = {
133         { .compatible = "generic-ehci" },
134         { }
135 };
136
137 U_BOOT_DRIVER(ehci_generic) = {
138         .name   = "ehci_generic",
139         .id     = UCLASS_USB,
140         .of_match = ehci_usb_ids,
141         .probe = ehci_usb_probe,
142         .remove = ehci_usb_remove,
143         .ops    = &ehci_usb_ops,
144         .priv_auto_alloc_size = sizeof(struct generic_ehci),
145         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
146 };