usb: host: ohci-generic: add CLOCK support
[oweals/u-boot.git] / 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 "ohci.h"
12
13 #if !defined(CONFIG_USB_OHCI_NEW)
14 # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW"
15 #endif
16
17 struct generic_ohci {
18         ohci_t ohci;
19         struct clk *clocks;     /* clock list */
20         int clock_count;        /* number of clock in clock list */
21 };
22
23 static int ohci_usb_probe(struct udevice *dev)
24 {
25         struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
26         struct generic_ohci *priv = dev_get_priv(dev);
27         int i, err, ret, clock_nb;
28
29         err = 0;
30         priv->clock_count = 0;
31         clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
32         if (clock_nb > 0) {
33                 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
34                                             GFP_KERNEL);
35                 if (!priv->clocks)
36                         return -ENOMEM;
37
38                 for (i = 0; i < clock_nb; i++) {
39                         err = clk_get_by_index(dev, i, &priv->clocks[i]);
40                         if (err < 0)
41                                 break;
42
43                         err = clk_enable(&priv->clocks[i]);
44                         if (err) {
45                                 error("failed to enable clock %d\n", i);
46                                 clk_free(&priv->clocks[i]);
47                                 goto clk_err;
48                         }
49                         priv->clock_count++;
50                 }
51         } else if (clock_nb != -ENOENT) {
52                 error("failed to get clock phandle(%d)\n", clock_nb);
53                 return clock_nb;
54         }
55
56         err = ohci_register(dev, regs);
57         if (err)
58                 goto clk_err;
59
60         return 0;
61
62 clk_err:
63         ret = clk_release_all(priv->clocks, priv->clock_count);
64         if (ret)
65                 error("failed to disable all clocks\n");
66
67         return err;
68 }
69
70 static int ohci_usb_remove(struct udevice *dev)
71 {
72         struct generic_ohci *priv = dev_get_priv(dev);
73         int ret;
74
75         ret = ohci_deregister(dev);
76         if (ret)
77                 return ret;
78
79         return clk_release_all(priv->clocks, priv->clock_count);
80 }
81
82 static const struct udevice_id ohci_usb_ids[] = {
83         { .compatible = "generic-ohci" },
84         { }
85 };
86
87 U_BOOT_DRIVER(ohci_generic) = {
88         .name   = "ohci_generic",
89         .id     = UCLASS_USB,
90         .of_match = ohci_usb_ids,
91         .probe = ohci_usb_probe,
92         .remove = ohci_usb_remove,
93         .ops    = &ohci_usb_ops,
94         .priv_auto_alloc_size = sizeof(struct generic_ohci),
95         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
96 };