usb: ehci: Make the PHY handling generic
[pandora-u-boot.git] / drivers / usb / host / ehci-generic.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
4  */
5
6 #include <common.h>
7 #include <clk.h>
8 #include <dm/ofnode.h>
9 #include <generic-phy.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         struct phy phy;
25         int clock_count;
26         int reset_count;
27 };
28
29 static int ehci_usb_probe(struct udevice *dev)
30 {
31         struct generic_ehci *priv = dev_get_priv(dev);
32         struct ehci_hccr *hccr;
33         struct ehci_hcor *hcor;
34         int i, err, ret, clock_nb, reset_nb;
35
36         err = 0;
37         priv->clock_count = 0;
38         clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
39                                                   "#clock-cells");
40         if (clock_nb > 0) {
41                 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
42                                             GFP_KERNEL);
43                 if (!priv->clocks)
44                         return -ENOMEM;
45
46                 for (i = 0; i < clock_nb; i++) {
47                         err = clk_get_by_index(dev, i, &priv->clocks[i]);
48
49                         if (err < 0)
50                                 break;
51                         err = clk_enable(&priv->clocks[i]);
52                         if (err) {
53                                 dev_err(dev, "failed to enable clock %d\n", i);
54                                 clk_free(&priv->clocks[i]);
55                                 goto clk_err;
56                         }
57                         priv->clock_count++;
58                 }
59         } else {
60                 if (clock_nb != -ENOENT) {
61                         dev_err(dev, "failed to get clock phandle(%d)\n",
62                                 clock_nb);
63                         return clock_nb;
64                 }
65         }
66
67         priv->reset_count = 0;
68         reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
69                                                   "#reset-cells");
70         if (reset_nb > 0) {
71                 priv->resets = devm_kcalloc(dev, reset_nb,
72                                             sizeof(struct reset_ctl),
73                                             GFP_KERNEL);
74                 if (!priv->resets)
75                         return -ENOMEM;
76
77                 for (i = 0; i < reset_nb; i++) {
78                         err = reset_get_by_index(dev, i, &priv->resets[i]);
79                         if (err < 0)
80                                 break;
81
82                         if (reset_deassert(&priv->resets[i])) {
83                                 dev_err(dev, "failed to deassert reset %d\n",
84                                         i);
85                                 reset_free(&priv->resets[i]);
86                                 goto reset_err;
87                         }
88                         priv->reset_count++;
89                 }
90         } else {
91                 if (reset_nb != -ENOENT) {
92                         dev_err(dev, "failed to get reset phandle(%d)\n",
93                                 reset_nb);
94                         goto clk_err;
95                 }
96         }
97
98         err = ehci_setup_phy(dev, &priv->phy, 0);
99         if (err)
100                 goto reset_err;
101
102         hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
103         hcor = (struct ehci_hcor *)((uintptr_t)hccr +
104                                     HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
105
106         err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
107         if (err)
108                 goto phy_err;
109
110         return 0;
111
112 phy_err:
113         ret = ehci_shutdown_phy(dev, &priv->phy);
114         if (ret)
115                 dev_err(dev, "failed to shutdown usb phy\n");
116
117 reset_err:
118         ret = reset_release_all(priv->resets, priv->reset_count);
119         if (ret)
120                 dev_err(dev, "failed to assert all resets\n");
121 clk_err:
122         ret = clk_release_all(priv->clocks, priv->clock_count);
123         if (ret)
124                 dev_err(dev, "failed to disable all clocks\n");
125
126         return err;
127 }
128
129 static int ehci_usb_remove(struct udevice *dev)
130 {
131         struct generic_ehci *priv = dev_get_priv(dev);
132         int ret;
133
134         ret = ehci_deregister(dev);
135         if (ret)
136                 return ret;
137
138         ret = ehci_shutdown_phy(dev, &priv->phy);
139         if (ret)
140                 return ret;
141
142         ret =  reset_release_all(priv->resets, priv->reset_count);
143         if (ret)
144                 return ret;
145
146         return clk_release_all(priv->clocks, priv->clock_count);
147 }
148
149 static const struct udevice_id ehci_usb_ids[] = {
150         { .compatible = "generic-ehci" },
151         { }
152 };
153
154 U_BOOT_DRIVER(ehci_generic) = {
155         .name   = "ehci_generic",
156         .id     = UCLASS_USB,
157         .of_match = ehci_usb_ids,
158         .probe = ehci_usb_probe,
159         .remove = ehci_usb_remove,
160         .ops    = &ehci_usb_ops,
161         .priv_auto_alloc_size = sizeof(struct generic_ehci),
162         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
163 };