usb: ehci-generic: handle phy power on/off
[oweals/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 <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_usb_probe(struct udevice *dev)
31 {
32         struct generic_ehci *priv = dev_get_priv(dev);
33         struct ehci_hccr *hccr;
34         struct ehci_hcor *hcor;
35         int i, err, ret, clock_nb, reset_nb;
36
37         err = 0;
38         priv->clock_count = 0;
39         clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
40                                                   "#clock-cells");
41         if (clock_nb > 0) {
42                 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
43                                             GFP_KERNEL);
44                 if (!priv->clocks)
45                         return -ENOMEM;
46
47                 for (i = 0; i < clock_nb; i++) {
48                         err = clk_get_by_index(dev, i, &priv->clocks[i]);
49
50                         if (err < 0)
51                                 break;
52                         err = clk_enable(&priv->clocks[i]);
53                         if (err) {
54                                 pr_err("failed to enable clock %d\n", i);
55                                 clk_free(&priv->clocks[i]);
56                                 goto clk_err;
57                         }
58                         priv->clock_count++;
59                 }
60         } else {
61                 if (clock_nb != -ENOENT) {
62                         pr_err("failed to get clock phandle(%d)\n", 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                                 pr_err("failed to deassert reset %d\n", i);
84                                 reset_free(&priv->resets[i]);
85                                 goto reset_err;
86                         }
87                         priv->reset_count++;
88                 }
89         } else {
90                 if (reset_nb != -ENOENT) {
91                         pr_err("failed to get reset phandle(%d)\n", reset_nb);
92                         goto clk_err;
93                 }
94         }
95
96         err = generic_phy_get_by_index(dev, 0, &priv->phy);
97         if (err) {
98                 if (err != -ENOENT) {
99                         pr_err("failed to get usb phy\n");
100                         goto reset_err;
101                 }
102         } else {
103
104                 err = generic_phy_init(&priv->phy);
105                 if (err) {
106                         pr_err("failed to init usb phy\n");
107                         goto reset_err;
108                 }
109
110                 err = generic_phy_power_on(&priv->phy);
111                 if (err) {
112                         dev_err(dev, "failed to power on usb phy\n");
113                         goto phy_power_err;
114                 }
115         }
116
117         hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
118         hcor = (struct ehci_hcor *)((uintptr_t)hccr +
119                                     HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
120
121         err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
122         if (err)
123                 goto phy_err;
124
125         return 0;
126
127 phy_err:
128         if (generic_phy_valid(&priv->phy)) {
129                 ret = generic_phy_power_off(&priv->phy);
130                 if (ret)
131                         dev_err(dev, "failed to power off usb phy\n");
132         }
133
134 phy_power_err:
135         if (generic_phy_valid(&priv->phy)) {
136                 ret = generic_phy_exit(&priv->phy);
137                 if (ret)
138                         pr_err("failed to release phy\n");
139         }
140
141 reset_err:
142         ret = reset_release_all(priv->resets, priv->reset_count);
143         if (ret)
144                 pr_err("failed to assert all resets\n");
145 clk_err:
146         ret = clk_release_all(priv->clocks, priv->clock_count);
147         if (ret)
148                 pr_err("failed to disable all clocks\n");
149
150         return err;
151 }
152
153 static int ehci_usb_remove(struct udevice *dev)
154 {
155         struct generic_ehci *priv = dev_get_priv(dev);
156         int ret;
157
158         ret = ehci_deregister(dev);
159         if (ret)
160                 return ret;
161
162         if (generic_phy_valid(&priv->phy)) {
163                 ret = generic_phy_power_off(&priv->phy);
164                 if (ret)
165                         return ret;
166
167                 ret = generic_phy_exit(&priv->phy);
168                 if (ret)
169                         return ret;
170         }
171
172         ret =  reset_release_all(priv->resets, priv->reset_count);
173         if (ret)
174                 return ret;
175
176         return clk_release_all(priv->clocks, priv->clock_count);
177 }
178
179 static const struct udevice_id ehci_usb_ids[] = {
180         { .compatible = "generic-ehci" },
181         { }
182 };
183
184 U_BOOT_DRIVER(ehci_generic) = {
185         .name   = "ehci_generic",
186         .id     = UCLASS_USB,
187         .of_match = ehci_usb_ids,
188         .probe = ehci_usb_probe,
189         .remove = ehci_usb_remove,
190         .ops    = &ehci_usb_ops,
191         .priv_auto_alloc_size = sizeof(struct generic_ehci),
192         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
193 };