]> git.sur5r.net Git - u-boot/blob - drivers/usb/host/ohci-generic.c
usb: host: ohci-generic: add RESET support
[u-boot] / drivers / usb / host / ohci-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.h>
10 #include <dm/ofnode.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         int clock_count;        /* number of clock in clock list */
23         int reset_count;        /* number of reset in reset list */
24 };
25
26 static int ohci_usb_probe(struct udevice *dev)
27 {
28         struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
29         struct generic_ohci *priv = dev_get_priv(dev);
30         int i, err, ret, clock_nb, reset_nb;
31
32         err = 0;
33         priv->clock_count = 0;
34         clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
35         if (clock_nb > 0) {
36                 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
37                                             GFP_KERNEL);
38                 if (!priv->clocks)
39                         return -ENOMEM;
40
41                 for (i = 0; i < clock_nb; i++) {
42                         err = clk_get_by_index(dev, i, &priv->clocks[i]);
43                         if (err < 0)
44                                 break;
45
46                         err = clk_enable(&priv->clocks[i]);
47                         if (err) {
48                                 error("failed to enable clock %d\n", i);
49                                 clk_free(&priv->clocks[i]);
50                                 goto clk_err;
51                         }
52                         priv->clock_count++;
53                 }
54         } else if (clock_nb != -ENOENT) {
55                 error("failed to get clock phandle(%d)\n", clock_nb);
56                 return clock_nb;
57         }
58
59         priv->reset_count = 0;
60         reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
61         if (reset_nb > 0) {
62                 priv->resets = devm_kcalloc(dev, reset_nb,
63                                             sizeof(struct reset_ctl),
64                                             GFP_KERNEL);
65                 if (!priv->resets)
66                         return -ENOMEM;
67
68                 for (i = 0; i < reset_nb; i++) {
69                         err = reset_get_by_index(dev, i, &priv->resets[i]);
70                         if (err < 0)
71                                 break;
72
73                         err = reset_deassert(&priv->resets[i]);
74                         if (err) {
75                                 error("failed to deassert reset %d\n", i);
76                                 reset_free(&priv->resets[i]);
77                                 goto reset_err;
78                         }
79                         priv->reset_count++;
80                 }
81         } else if (reset_nb != -ENOENT) {
82                 error("failed to get reset phandle(%d)\n", reset_nb);
83                 goto clk_err;
84         }
85
86         err = ohci_register(dev, regs);
87         if (err)
88                 goto reset_err;
89
90         return 0;
91
92 reset_err:
93         ret = reset_release_all(priv->resets, priv->reset_count);
94         if (ret)
95                 error("failed to assert all resets\n");
96 clk_err:
97         ret = clk_release_all(priv->clocks, priv->clock_count);
98         if (ret)
99                 error("failed to disable all clocks\n");
100
101         return err;
102 }
103
104 static int ohci_usb_remove(struct udevice *dev)
105 {
106         struct generic_ohci *priv = dev_get_priv(dev);
107         int ret;
108
109         ret = ohci_deregister(dev);
110         if (ret)
111                 return ret;
112
113         ret = reset_release_all(priv->resets, priv->reset_count);
114         if (ret)
115                 return ret;
116
117         return clk_release_all(priv->clocks, priv->clock_count);
118 }
119
120 static const struct udevice_id ohci_usb_ids[] = {
121         { .compatible = "generic-ohci" },
122         { }
123 };
124
125 U_BOOT_DRIVER(ohci_generic) = {
126         .name   = "ohci_generic",
127         .id     = UCLASS_USB,
128         .of_match = ohci_usb_ids,
129         .probe = ohci_usb_probe,
130         .remove = ohci_usb_remove,
131         .ops    = &ohci_usb_ops,
132         .priv_auto_alloc_size = sizeof(struct generic_ohci),
133         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
134 };